mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-15 22:19:54 +00:00
286 lines
8.3 KiB
C++
286 lines
8.3 KiB
C++
//
|
|
// Created by koncord on 02.01.16.
|
|
//
|
|
|
|
#include <boost/algorithm/clamp.hpp>
|
|
#include <components/openmw-mp/Log.hpp>
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
|
|
#include "../mwgui/windowmanagerimp.hpp"
|
|
|
|
#include "../mwclass/npc.hpp"
|
|
|
|
#include "../mwinput/inputmanagerimp.hpp"
|
|
|
|
#include "../mwmechanics/actor.hpp"
|
|
#include "../mwmechanics/aitravel.hpp"
|
|
#include "../mwmechanics/creaturestats.hpp"
|
|
#include "../mwmechanics/npcstats.hpp"
|
|
#include "../mwmechanics/mechanicsmanagerimp.hpp"
|
|
#include "../mwmechanics/spellcasting.hpp"
|
|
|
|
#include "../mwstate/statemanagerimp.hpp"
|
|
|
|
#include "../mwworld/action.hpp"
|
|
#include "../mwworld/cellstore.hpp"
|
|
#include "../mwworld/customdata.hpp"
|
|
#include "../mwworld/inventorystore.hpp"
|
|
#include "../mwworld/player.hpp"
|
|
#include "../mwworld/worldimp.hpp"
|
|
|
|
#include "DedicatedPlayer.hpp"
|
|
#include "Main.hpp"
|
|
#include "GUIController.hpp"
|
|
#include "CellController.hpp"
|
|
#include "MechanicsHelper.hpp"
|
|
|
|
|
|
using namespace mwmp;
|
|
using namespace std;
|
|
|
|
DedicatedPlayer::DedicatedPlayer(RakNet::RakNetGUID guid) : BasePlayer(guid)
|
|
{
|
|
reference = 0;
|
|
attack.pressed = 0;
|
|
creatureStats.mDead = false;
|
|
movementFlags = 0;
|
|
}
|
|
DedicatedPlayer::~DedicatedPlayer()
|
|
{
|
|
|
|
}
|
|
|
|
void DedicatedPlayer::update(float dt)
|
|
{
|
|
MWMechanics::CreatureStats *ptrCreatureStats = &ptr.getClass().getCreatureStats(ptr);
|
|
|
|
MWMechanics::DynamicStat<float> value;
|
|
|
|
if (creatureStats.mDead)
|
|
{
|
|
value.readState(creatureStats.mDynamic[0]);
|
|
ptrCreatureStats->setHealth(value);
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
value.readState(creatureStats.mDynamic[i]);
|
|
ptrCreatureStats->setDynamic(i, value);
|
|
}
|
|
|
|
if (ptrCreatureStats->isDead())
|
|
ptrCreatureStats->resurrect();
|
|
|
|
ptrCreatureStats->setAttacked(false);
|
|
|
|
ptrCreatureStats->getAiSequence().stopCombat();
|
|
|
|
ptrCreatureStats->setAlarmed(false);
|
|
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Alarm, 0);
|
|
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Fight, 0);
|
|
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Flee, 0);
|
|
ptrCreatureStats->setAiSetting(MWMechanics::CreatureStats::AI_Hello, 0);
|
|
|
|
move(dt);
|
|
updateAnimFlags();
|
|
}
|
|
|
|
void DedicatedPlayer::move(float dt)
|
|
{
|
|
if (state != 2) return;
|
|
|
|
ESM::Position refPos = ptr.getRefData().getPosition();
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
{
|
|
static const int timeMultiplier = 15;
|
|
osg::Vec3f lerp = Main::get().getMechanicsHelper()->getLinearInterpolation(refPos.asVec3(), position.asVec3(), dt * timeMultiplier);
|
|
refPos.pos[0] = lerp.x();
|
|
refPos.pos[1] = lerp.y();
|
|
refPos.pos[2] = lerp.z();
|
|
|
|
world->moveObject(ptr, refPos.pos[0], refPos.pos[1], refPos.pos[2]);
|
|
}
|
|
|
|
MWMechanics::Movement *move = &ptr.getClass().getMovementSettings(ptr);
|
|
move->mPosition[0] = direction.pos[0];
|
|
move->mPosition[1] = direction.pos[1];
|
|
move->mPosition[2] = direction.pos[2];
|
|
|
|
world->rotateObject(ptr, position.rot[0], position.rot[1], position.rot[2]);
|
|
}
|
|
|
|
void DedicatedPlayer::updateAnimFlags()
|
|
{
|
|
using namespace MWMechanics;
|
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
// Until we figure out a better workaround for disabling player gravity,
|
|
// simply cast Levitate over and over on a player that's supposed to be flying
|
|
if (!isFlying)
|
|
{
|
|
ptr.getClass().getCreatureStats(ptr).getActiveSpells().purgeEffect(ESM::MagicEffect::Levitate);
|
|
}
|
|
else if (isFlying && !world->isFlying(ptr))
|
|
{
|
|
MWMechanics::CastSpell cast(ptr, ptr);
|
|
cast.mHitPosition = ptr.getRefData().getPosition().asVec3();
|
|
cast.mAlwaysSucceed = true;
|
|
cast.cast("Levitate");
|
|
}
|
|
|
|
if (drawState == 0)
|
|
ptr.getClass().getCreatureStats(ptr).setDrawState(DrawState_Nothing);
|
|
else if (drawState == 1)
|
|
ptr.getClass().getCreatureStats(ptr).setDrawState(DrawState_Weapon);
|
|
else if (drawState == 2)
|
|
ptr.getClass().getCreatureStats(ptr).setDrawState(DrawState_Spell);
|
|
|
|
MWMechanics::CreatureStats *ptrCreatureStats = &ptr.getClass().getCreatureStats(ptr);
|
|
ptrCreatureStats->setMovementFlag(CreatureStats::Flag_Run, (movementFlags & CreatureStats::Flag_Run) != 0);
|
|
ptrCreatureStats->setMovementFlag(CreatureStats::Flag_Sneak, (movementFlags & CreatureStats::Flag_Sneak) != 0);
|
|
ptrCreatureStats->setMovementFlag(CreatureStats::Flag_ForceJump, (movementFlags & CreatureStats::Flag_ForceJump) != 0);
|
|
ptrCreatureStats->setMovementFlag(CreatureStats::Flag_ForceMoveJump, (movementFlags & CreatureStats::Flag_ForceMoveJump) != 0);
|
|
}
|
|
|
|
void DedicatedPlayer::updateEquipment()
|
|
{
|
|
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr);
|
|
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
|
{
|
|
MWWorld::ContainerStoreIterator it = invStore.getSlot(slot);
|
|
|
|
const string &dedicItem = equipedItems[slot].refId;
|
|
std::string item = "";
|
|
bool equal = false;
|
|
if (it != invStore.end())
|
|
{
|
|
item = it->getCellRef().getRefId();
|
|
if (!Misc::StringUtils::ciEqual(item, dedicItem)) // if other item equiped
|
|
{
|
|
MWWorld::ContainerStore &store = ptr.getClass().getContainerStore(ptr);
|
|
store.remove(item, store.count(item), ptr);
|
|
}
|
|
else
|
|
equal = true;
|
|
}
|
|
|
|
if (dedicItem.empty() || equal)
|
|
continue;
|
|
|
|
const int count = equipedItems[slot].count;
|
|
ptr.getClass().getContainerStore(ptr).add(dedicItem, count, ptr);
|
|
|
|
for (MWWorld::ContainerStoreIterator it2 = invStore.begin(); it2 != invStore.end(); ++it2)
|
|
{
|
|
if (::Misc::StringUtils::ciEqual(it2->getCellRef().getRefId(), dedicItem)) // equip item
|
|
{
|
|
boost::shared_ptr<MWWorld::Action> action = it2->getClass().use(*it2);
|
|
action->execute(ptr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DedicatedPlayer::updateCell()
|
|
{
|
|
// Prevent cell update when player hasn't been instantiated yet
|
|
if (state == 0)
|
|
return;
|
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
MWWorld::CellStore *cellStore;
|
|
|
|
|
|
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Server says DedicatedPlayer %s moved to %s",
|
|
this->npc.mName.c_str(), cell.getDescription().c_str());
|
|
|
|
try
|
|
{
|
|
if (cell.isExterior())
|
|
cellStore = world->getExterior(cell.mData.mX, cell.mData.mY);
|
|
else
|
|
cellStore = world->getInterior(cell.mName);
|
|
}
|
|
// If the intended cell doesn't exist on this client, use ToddTest as a replacement
|
|
catch (std::exception&)
|
|
{
|
|
cellStore = world->getInterior("ToddTest");
|
|
LOG_APPEND(Log::LOG_INFO, "%s", "- Cell doesn't exist on this client");
|
|
}
|
|
|
|
if (!cellStore) return;
|
|
|
|
// Allow this player's reference to move across a cell now that a manual cell
|
|
// update has been called
|
|
setPtr(world->moveObject(ptr, cellStore, position.pos[0], position.pos[1], position.pos[2]));
|
|
|
|
// If this player is now in a cell that is active for us, we should send them all
|
|
// NPC data in that cell
|
|
if (Main::get().getCellController()->isActiveWorldCell(cell))
|
|
{
|
|
if (Main::get().getCellController()->isInitializedCell(cell))
|
|
Main::get().getCellController()->getCell(cell)->updateLocal(true);
|
|
}
|
|
}
|
|
|
|
void DedicatedPlayer::updateMarker()
|
|
{
|
|
if (!markerEnabled)
|
|
return;
|
|
|
|
GUIController *gui = Main::get().getGUIController();
|
|
|
|
if (gui->mPlayerMarkers.contains(marker))
|
|
{
|
|
gui->mPlayerMarkers.deleteMarker(marker);
|
|
marker = gui->CreateMarker(guid);
|
|
gui->mPlayerMarkers.addMarker(marker);
|
|
}
|
|
else
|
|
gui->mPlayerMarkers.addMarker(marker, true);
|
|
}
|
|
|
|
void DedicatedPlayer::removeMarker()
|
|
{
|
|
if (!markerEnabled)
|
|
return;
|
|
|
|
markerEnabled = false;
|
|
Main::get().getGUIController()->mPlayerMarkers.deleteMarker(marker);
|
|
}
|
|
|
|
void DedicatedPlayer::setMarkerState(bool state)
|
|
{
|
|
if (state)
|
|
{
|
|
markerEnabled = true;
|
|
updateMarker();
|
|
}
|
|
else
|
|
removeMarker();
|
|
}
|
|
|
|
MWWorld::Ptr DedicatedPlayer::getPtr()
|
|
{
|
|
return ptr;
|
|
}
|
|
|
|
MWWorld::Ptr DedicatedPlayer::getLiveCellPtr()
|
|
{
|
|
return reference->getPtr();
|
|
}
|
|
|
|
MWWorld::ManualRef *DedicatedPlayer::getRef()
|
|
{
|
|
return reference;
|
|
}
|
|
|
|
void DedicatedPlayer::setPtr(const MWWorld::Ptr& newPtr)
|
|
{
|
|
ptr = newPtr;
|
|
}
|