2017-04-10 15:24:30 +00:00
|
|
|
#include <boost/algorithm/clamp.hpp>
|
|
|
|
#include <components/openmw-mp/Log.hpp>
|
2017-06-02 10:05:33 +00:00
|
|
|
#include <apps/openmw/mwmechanics/steering.hpp>
|
2017-02-26 23:02:59 +00:00
|
|
|
|
2016-01-12 03:41:44 +00:00
|
|
|
#include "../mwbase/environment.hpp"
|
2017-10-31 13:19:14 +00:00
|
|
|
#include "../mwbase/soundmanager.hpp"
|
2017-02-26 23:02:59 +00:00
|
|
|
|
2016-01-12 03:41:44 +00:00
|
|
|
#include "../mwclass/npc.hpp"
|
2017-02-26 23:02:59 +00:00
|
|
|
|
2017-10-31 13:19:14 +00:00
|
|
|
#include "../mwdialogue/dialoguemanagerimp.hpp"
|
|
|
|
|
|
|
|
#include "../mwgui/windowmanagerimp.hpp"
|
|
|
|
|
2017-04-08 09:54:38 +00:00
|
|
|
#include "../mwinput/inputmanagerimp.hpp"
|
|
|
|
|
2016-11-12 11:39:04 +00:00
|
|
|
#include "../mwmechanics/actor.hpp"
|
2017-02-26 23:02:59 +00:00
|
|
|
#include "../mwmechanics/aitravel.hpp"
|
2016-01-12 03:41:44 +00:00
|
|
|
#include "../mwmechanics/creaturestats.hpp"
|
|
|
|
#include "../mwmechanics/npcstats.hpp"
|
|
|
|
#include "../mwmechanics/mechanicsmanagerimp.hpp"
|
2017-02-27 21:01:33 +00:00
|
|
|
#include "../mwmechanics/spellcasting.hpp"
|
2017-02-26 23:02:59 +00:00
|
|
|
|
2017-04-08 09:54:38 +00:00
|
|
|
#include "../mwstate/statemanagerimp.hpp"
|
|
|
|
|
2016-01-12 03:41:44 +00:00
|
|
|
#include "../mwworld/action.hpp"
|
2017-02-26 23:02:59 +00:00
|
|
|
#include "../mwworld/cellstore.hpp"
|
|
|
|
#include "../mwworld/customdata.hpp"
|
2017-04-10 15:24:30 +00:00
|
|
|
#include "../mwworld/inventorystore.hpp"
|
2017-02-26 23:02:59 +00:00
|
|
|
#include "../mwworld/player.hpp"
|
|
|
|
#include "../mwworld/worldimp.hpp"
|
|
|
|
|
2017-04-10 15:24:30 +00:00
|
|
|
#include "DedicatedPlayer.hpp"
|
2016-10-22 09:06:26 +00:00
|
|
|
#include "Main.hpp"
|
2016-12-16 08:59:15 +00:00
|
|
|
#include "GUIController.hpp"
|
2017-04-05 09:00:21 +00:00
|
|
|
#include "CellController.hpp"
|
2017-04-17 11:37:19 +00:00
|
|
|
#include "MechanicsHelper.hpp"
|
2017-02-26 23:02:59 +00:00
|
|
|
|
2017-04-10 15:24:30 +00:00
|
|
|
|
2016-01-12 03:41:44 +00:00
|
|
|
using namespace mwmp;
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
DedicatedPlayer::DedicatedPlayer(RakNet::RakNetGUID guid) : BasePlayer(guid)
|
|
|
|
{
|
2017-05-01 14:54:43 +00:00
|
|
|
reference = 0;
|
2017-01-25 15:06:15 +00:00
|
|
|
attack.pressed = 0;
|
|
|
|
creatureStats.mDead = false;
|
2016-01-12 03:41:44 +00:00
|
|
|
movementFlags = 0;
|
2017-07-28 17:49:26 +00:00
|
|
|
attack.instant = false;
|
2016-01-12 03:41:44 +00:00
|
|
|
}
|
|
|
|
DedicatedPlayer::~DedicatedPlayer()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-04-24 15:38:57 +00:00
|
|
|
void DedicatedPlayer::update(float dt)
|
|
|
|
{
|
2017-04-29 14:40:22 +00:00
|
|
|
MWMechanics::CreatureStats *ptrCreatureStats = &ptr.getClass().getCreatureStats(ptr);
|
2017-04-24 15:38:57 +00:00
|
|
|
|
|
|
|
MWMechanics::DynamicStat<float> value;
|
|
|
|
|
|
|
|
if (creatureStats.mDead)
|
|
|
|
{
|
|
|
|
value.readState(creatureStats.mDynamic[0]);
|
2017-04-29 14:40:22 +00:00
|
|
|
ptrCreatureStats->setHealth(value);
|
2017-04-24 15:38:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-05 17:38:28 +00:00
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
{
|
|
|
|
value.readState(creatureStats.mDynamic[i]);
|
|
|
|
ptrCreatureStats->setDynamic(i, value);
|
|
|
|
}
|
2017-04-24 15:38:57 +00:00
|
|
|
|
2017-04-29 14:40:22 +00:00
|
|
|
if (ptrCreatureStats->isDead())
|
|
|
|
ptrCreatureStats->resurrect();
|
2017-04-24 15:38:57 +00:00
|
|
|
|
2017-04-29 14:40:22 +00:00
|
|
|
ptrCreatureStats->setAttacked(false);
|
2017-04-24 15:38:57 +00:00
|
|
|
|
2017-04-29 14:40:22 +00:00
|
|
|
ptrCreatureStats->getAiSequence().stopCombat();
|
2017-04-24 15:38:57 +00:00
|
|
|
|
2017-04-29 14:40:22 +00:00
|
|
|
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);
|
2017-04-24 15:38:57 +00:00
|
|
|
|
2017-05-14 07:52:44 +00:00
|
|
|
// Only move and set anim flags if the framerate isn't too low
|
|
|
|
if (dt < 0.1)
|
|
|
|
{
|
|
|
|
move(dt);
|
|
|
|
setAnimFlags();
|
|
|
|
}
|
2017-04-24 15:38:57 +00:00
|
|
|
}
|
|
|
|
|
2016-11-15 19:54:06 +00:00
|
|
|
void DedicatedPlayer::move(float dt)
|
2016-01-12 03:41:44 +00:00
|
|
|
{
|
|
|
|
if (state != 2) return;
|
|
|
|
|
2016-09-29 09:05:44 +00:00
|
|
|
ESM::Position refPos = ptr.getRefData().getPosition();
|
2016-01-12 03:41:44 +00:00
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
2017-05-28 00:30:23 +00:00
|
|
|
const int maxInterpolationDistance = 40;
|
2016-01-12 03:41:44 +00:00
|
|
|
|
2017-05-09 01:39:27 +00:00
|
|
|
// Apply interpolation only if the position hasn't changed too much from last time
|
2017-06-27 14:25:29 +00:00
|
|
|
bool shouldInterpolate =
|
|
|
|
abs(position.pos[0] - refPos.pos[0]) < maxInterpolationDistance &&
|
|
|
|
abs(position.pos[1] - refPos.pos[1]) < maxInterpolationDistance &&
|
|
|
|
abs(position.pos[2] - refPos.pos[2]) < maxInterpolationDistance;
|
2017-05-09 01:39:27 +00:00
|
|
|
|
|
|
|
if (shouldInterpolate)
|
2016-01-12 03:41:44 +00:00
|
|
|
{
|
2017-03-04 06:21:37 +00:00
|
|
|
static const int timeMultiplier = 15;
|
2017-06-27 08:34:32 +00:00
|
|
|
osg::Vec3f lerp = MechanicsHelper::getLinearInterpolation(refPos.asVec3(), position.asVec3(), dt * timeMultiplier);
|
2017-02-27 21:01:33 +00:00
|
|
|
|
2017-06-27 14:25:29 +00:00
|
|
|
world->moveObject(ptr, lerp.x(), lerp.y(), lerp.z());
|
2016-01-12 03:41:44 +00:00
|
|
|
}
|
2017-05-09 01:39:27 +00:00
|
|
|
else
|
|
|
|
world->moveObject(ptr, position.pos[0], position.pos[1], position.pos[2]);
|
2016-01-12 03:41:44 +00:00
|
|
|
|
2017-06-02 10:05:33 +00:00
|
|
|
float oldZ = ptr.getRefData().getPosition().rot[2];
|
|
|
|
world->rotateObject(ptr, position.rot[0], 0, oldZ);
|
2017-05-30 09:08:58 +00:00
|
|
|
|
2016-01-12 03:41:44 +00:00
|
|
|
MWMechanics::Movement *move = &ptr.getClass().getMovementSettings(ptr);
|
2017-01-25 15:06:15 +00:00
|
|
|
move->mPosition[0] = direction.pos[0];
|
|
|
|
move->mPosition[1] = direction.pos[1];
|
2017-06-02 10:05:33 +00:00
|
|
|
|
|
|
|
MWMechanics::zTurn(ptr, position.rot[2], osg::DegreesToRadians(1.0));
|
2016-01-12 03:41:44 +00:00
|
|
|
}
|
|
|
|
|
2018-04-08 07:56:33 +00:00
|
|
|
void DedicatedPlayer::setBaseInfo()
|
|
|
|
{
|
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
|
|
|
|
ESM::Creature tempCreature;
|
|
|
|
ESM::NPC tempNpc;
|
|
|
|
|
|
|
|
if (!creatureRefId.empty())
|
|
|
|
{
|
|
|
|
const ESM::Creature *tmpCreature = world->getStore().get<ESM::Creature>().search(creatureRefId);
|
|
|
|
if (tmpCreature == 0)
|
|
|
|
{
|
|
|
|
creatureRefId = "";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tempCreature = getCreatureRecord();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (creatureRefId.empty())
|
|
|
|
{
|
|
|
|
tempNpc = getNpcRecord();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool reset = false;
|
|
|
|
if (reference)
|
|
|
|
{
|
|
|
|
deleteReference();
|
|
|
|
reset = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state == 0)
|
|
|
|
{
|
|
|
|
createReference(tempNpc, tempCreature, reset);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
updateReference(tempNpc, tempCreature);
|
|
|
|
}
|
|
|
|
|
|
|
|
state = 2;
|
|
|
|
|
|
|
|
// Give this new character a fatigue of at least 1 so it doesn't spawn
|
|
|
|
// on the ground
|
|
|
|
creatureStats.mDynamic[2].mBase = 1;
|
|
|
|
|
|
|
|
world->enable(ptr);
|
|
|
|
}
|
|
|
|
|
2017-05-14 07:52:44 +00:00
|
|
|
void DedicatedPlayer::setAnimFlags()
|
2016-01-12 03:41:44 +00:00
|
|
|
{
|
2017-04-17 16:34:32 +00:00
|
|
|
using namespace MWMechanics;
|
2016-01-12 03:41:44 +00:00
|
|
|
|
2017-04-17 16:34:32 +00:00
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
2016-01-12 03:41:44 +00:00
|
|
|
|
2017-04-17 16:34:32 +00:00
|
|
|
// 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");
|
2016-01-12 03:41:44 +00:00
|
|
|
}
|
|
|
|
|
2017-04-17 16:34:32 +00:00
|
|
|
if (drawState == 0)
|
2017-04-29 14:40:22 +00:00
|
|
|
ptr.getClass().getCreatureStats(ptr).setDrawState(DrawState_Nothing);
|
2017-04-17 16:34:32 +00:00
|
|
|
else if (drawState == 1)
|
2017-04-29 14:40:22 +00:00
|
|
|
ptr.getClass().getCreatureStats(ptr).setDrawState(DrawState_Weapon);
|
2017-04-17 16:34:32 +00:00
|
|
|
else if (drawState == 2)
|
2017-04-29 14:40:22 +00:00
|
|
|
ptr.getClass().getCreatureStats(ptr).setDrawState(DrawState_Spell);
|
2016-08-18 19:29:54 +00:00
|
|
|
|
2017-04-29 14:40:22 +00:00
|
|
|
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);
|
2016-01-12 03:41:44 +00:00
|
|
|
}
|
|
|
|
|
2017-05-14 07:52:44 +00:00
|
|
|
void DedicatedPlayer::setEquipment()
|
2016-01-12 03:41:44 +00:00
|
|
|
{
|
|
|
|
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr);
|
|
|
|
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
|
|
|
{
|
|
|
|
MWWorld::ContainerStoreIterator it = invStore.getSlot(slot);
|
|
|
|
|
2017-02-05 07:01:33 +00:00
|
|
|
const string &dedicItem = equipedItems[slot].refId;
|
2016-01-12 03:41:44 +00:00
|
|
|
std::string item = "";
|
|
|
|
bool equal = false;
|
2016-08-17 15:20:36 +00:00
|
|
|
if (it != invStore.end())
|
2016-01-12 03:41:44 +00:00
|
|
|
{
|
|
|
|
item = it->getCellRef().getRefId();
|
2016-08-17 15:20:36 +00:00
|
|
|
if (!Misc::StringUtils::ciEqual(item, dedicItem)) // if other item equiped
|
2016-01-12 03:41:44 +00:00
|
|
|
{
|
|
|
|
MWWorld::ContainerStore &store = ptr.getClass().getContainerStore(ptr);
|
|
|
|
store.remove(item, store.count(item), ptr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
equal = true;
|
|
|
|
}
|
|
|
|
|
2016-08-17 15:04:35 +00:00
|
|
|
if (dedicItem.empty() || equal)
|
2016-01-12 03:41:44 +00:00
|
|
|
continue;
|
|
|
|
|
2017-01-25 15:06:15 +00:00
|
|
|
const int count = equipedItems[slot].count;
|
2016-01-12 03:41:44 +00:00
|
|
|
ptr.getClass().getContainerStore(ptr).add(dedicItem, count, ptr);
|
|
|
|
|
2017-06-27 14:25:29 +00:00
|
|
|
for (const auto &ptr : invStore)
|
2016-01-12 03:41:44 +00:00
|
|
|
{
|
2017-06-27 14:25:29 +00:00
|
|
|
if (::Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), dedicItem)) // equip item
|
2016-01-12 03:41:44 +00:00
|
|
|
{
|
2017-06-27 14:25:29 +00:00
|
|
|
std::shared_ptr<MWWorld::Action> action = ptr.getClass().use(ptr);
|
|
|
|
action->execute(this->ptr);
|
2016-01-12 03:41:44 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-14 07:52:44 +00:00
|
|
|
void DedicatedPlayer::setCell()
|
2016-01-12 03:41:44 +00:00
|
|
|
{
|
2016-08-17 04:27:40 +00:00
|
|
|
// Prevent cell update when player hasn't been instantiated yet
|
|
|
|
if (state == 0)
|
|
|
|
return;
|
2016-08-16 22:06:50 +00:00
|
|
|
|
2016-01-12 03:41:44 +00:00
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
2016-08-18 19:29:54 +00:00
|
|
|
|
2017-04-23 10:31:06 +00:00
|
|
|
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Server says DedicatedPlayer %s moved to %s",
|
2017-05-31 07:54:19 +00:00
|
|
|
npc.mName.c_str(), cell.getDescription().c_str());
|
2016-11-04 18:53:19 +00:00
|
|
|
|
2017-05-31 07:54:19 +00:00
|
|
|
MWWorld::CellStore *cellStore = Main::get().getCellController()->getCellStore(cell);
|
|
|
|
|
|
|
|
if (!cellStore)
|
2016-11-04 18:53:19 +00:00
|
|
|
{
|
|
|
|
LOG_APPEND(Log::LOG_INFO, "%s", "- Cell doesn't exist on this client");
|
2017-05-31 07:54:19 +00:00
|
|
|
world->disable(getPtr());
|
|
|
|
return;
|
2016-11-04 18:53:19 +00:00
|
|
|
}
|
2017-05-31 07:54:19 +00:00
|
|
|
else
|
|
|
|
world->enable(getPtr());
|
2016-07-20 00:26:25 +00:00
|
|
|
|
2016-11-04 18:53:19 +00:00
|
|
|
// Allow this player's reference to move across a cell now that a manual cell
|
|
|
|
// update has been called
|
2017-04-23 10:31:06 +00:00
|
|
|
setPtr(world->moveObject(ptr, cellStore, position.pos[0], position.pos[1], position.pos[2]));
|
2017-04-10 15:24:30 +00:00
|
|
|
|
2017-05-31 07:54:19 +00:00
|
|
|
// Remove the marker entirely if this player has moved to an interior that is inactive for us
|
|
|
|
if (!cell.isExterior() && !Main::get().getCellController()->isActiveWorldCell(cell))
|
2017-06-01 19:42:57 +00:00
|
|
|
removeMarker();
|
2017-05-31 07:54:19 +00:00
|
|
|
// Otherwise, update their marker so the player shows up in the right cell on the world map
|
|
|
|
else
|
|
|
|
updateMarker();
|
|
|
|
|
2017-05-27 15:55:14 +00:00
|
|
|
// If this player is now in a cell that we are the local authority over, we should send them all
|
2017-04-10 15:24:30 +00:00
|
|
|
// NPC data in that cell
|
2017-05-27 15:55:14 +00:00
|
|
|
if (Main::get().getCellController()->hasLocalAuthority(cell))
|
|
|
|
Main::get().getCellController()->getCell(cell)->updateLocal(true);
|
2016-01-12 03:41:44 +00:00
|
|
|
}
|
2016-10-22 09:06:26 +00:00
|
|
|
|
2017-07-15 06:02:19 +00:00
|
|
|
void DedicatedPlayer::setShapeshift()
|
|
|
|
{
|
2018-02-01 00:11:45 +00:00
|
|
|
MWBase::Environment::get().getWorld()->scaleObject(ptr, scale);
|
2017-07-15 06:02:19 +00:00
|
|
|
MWBase::Environment::get().getMechanicsManager()->setWerewolf(ptr, isWerewolf);
|
|
|
|
}
|
|
|
|
|
2016-10-22 09:06:26 +00:00
|
|
|
void DedicatedPlayer::updateMarker()
|
|
|
|
{
|
|
|
|
if (!markerEnabled)
|
|
|
|
return;
|
2016-10-24 13:26:51 +00:00
|
|
|
|
2016-10-22 09:06:26 +00:00
|
|
|
GUIController *gui = Main::get().getGUIController();
|
2016-10-24 13:26:51 +00:00
|
|
|
|
2016-10-30 14:39:59 +00:00
|
|
|
if (gui->mPlayerMarkers.contains(marker))
|
2016-10-22 09:06:26 +00:00
|
|
|
{
|
|
|
|
gui->mPlayerMarkers.deleteMarker(marker);
|
2017-05-31 05:37:11 +00:00
|
|
|
marker = gui->createMarker(guid);
|
2016-10-22 09:06:26 +00:00
|
|
|
gui->mPlayerMarkers.addMarker(marker);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
gui->mPlayerMarkers.addMarker(marker, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DedicatedPlayer::removeMarker()
|
|
|
|
{
|
|
|
|
if (!markerEnabled)
|
|
|
|
return;
|
2016-10-24 13:26:51 +00:00
|
|
|
|
2016-10-22 09:06:26 +00:00
|
|
|
markerEnabled = false;
|
2017-06-01 19:42:57 +00:00
|
|
|
GUIController *gui = Main::get().getGUIController();
|
|
|
|
|
|
|
|
if (gui->mPlayerMarkers.contains(marker))
|
|
|
|
Main::get().getGUIController()->mPlayerMarkers.deleteMarker(marker);
|
2016-10-22 09:06:26 +00:00
|
|
|
}
|
|
|
|
|
2016-10-24 12:10:32 +00:00
|
|
|
void DedicatedPlayer::setMarkerState(bool state)
|
2016-10-22 09:06:26 +00:00
|
|
|
{
|
2016-10-24 12:10:32 +00:00
|
|
|
if (state)
|
2016-10-24 13:26:51 +00:00
|
|
|
{
|
|
|
|
markerEnabled = true;
|
2016-10-22 09:06:26 +00:00
|
|
|
updateMarker();
|
2016-10-24 13:26:51 +00:00
|
|
|
}
|
2016-10-22 09:06:26 +00:00
|
|
|
else
|
|
|
|
removeMarker();
|
|
|
|
}
|
2016-11-12 11:39:04 +00:00
|
|
|
|
2017-10-27 06:10:29 +00:00
|
|
|
void DedicatedPlayer::playAnimation()
|
|
|
|
{
|
|
|
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(getPtr(),
|
|
|
|
animation.groupname, animation.mode, animation.count, animation.persist);
|
|
|
|
}
|
|
|
|
|
2017-10-31 13:19:14 +00:00
|
|
|
void DedicatedPlayer::playSpeech()
|
|
|
|
{
|
|
|
|
MWBase::Environment::get().getSoundManager()->say(getPtr(), sound);
|
|
|
|
|
|
|
|
MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
|
|
|
|
if (winMgr->getSubtitlesEnabled())
|
|
|
|
winMgr->messageBox(MWBase::Environment::get().getDialogueManager()->getVoiceCaption(sound), MWGui::ShowInDialogueMode_Never);
|
|
|
|
}
|
|
|
|
|
2018-04-08 07:56:33 +00:00
|
|
|
|
|
|
|
ESM::Creature DedicatedPlayer::getCreatureRecord()
|
2017-04-17 16:34:32 +00:00
|
|
|
{
|
2018-04-08 07:56:33 +00:00
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
|
|
|
|
ESM::Creature creature;
|
|
|
|
|
|
|
|
const ESM::Creature *tmpCreature = world->getStore().get<ESM::Creature>().search(creatureRefId);
|
|
|
|
|
|
|
|
creature = *tmpCreature;
|
|
|
|
creature.mScript = "";
|
|
|
|
if (!displayCreatureName)
|
|
|
|
creature.mName = npc.mName;
|
|
|
|
LOG_APPEND(Log::LOG_INFO, "Player %s looks like %s", npc.mName.c_str(), creatureRefId.c_str());
|
|
|
|
|
|
|
|
return creature;
|
|
|
|
}
|
|
|
|
|
|
|
|
ESM::NPC DedicatedPlayer::getNpcRecord()
|
|
|
|
{
|
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
|
|
|
|
MWWorld::Ptr player = world->getPlayerPtr();
|
|
|
|
|
|
|
|
ESM::NPC newNpc = *player.get<ESM::NPC>()->mBase;
|
|
|
|
|
|
|
|
// To avoid freezes caused by invalid races, only set race if we find it
|
|
|
|
// on our client
|
|
|
|
if (world->getStore().get<ESM::Race>().search(npc.mRace) != 0)
|
|
|
|
newNpc.mRace = npc.mRace;
|
|
|
|
|
|
|
|
newNpc.mHead = npc.mHead;
|
|
|
|
newNpc.mHair = npc.mHair;
|
|
|
|
newNpc.mClass = npc.mClass;
|
|
|
|
newNpc.mName = npc.mName;
|
|
|
|
newNpc.mFlags = npc.mFlags;
|
|
|
|
|
|
|
|
return newNpc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DedicatedPlayer::createReference(ESM::NPC& npc, ESM::Creature& creature, bool reset)
|
|
|
|
{
|
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
|
|
|
|
// Temporarily spawn or move player to the center of exterior 0, 0
|
|
|
|
ESM::Position spawnPos;
|
|
|
|
spawnPos.pos[0] = spawnPos.pos[1] = Main::get().getCellController()->getCellSize() / 2;
|
|
|
|
spawnPos.pos[2] = 0;
|
|
|
|
MWWorld::CellStore *cellStore = world->getExterior(0, 0);
|
|
|
|
|
|
|
|
string recid;
|
|
|
|
if (creatureRefId.empty())
|
|
|
|
{
|
|
|
|
LOG_APPEND(Log::LOG_INFO, "- Creating new NPC record");
|
|
|
|
npc.mId = "Dedicated Player";
|
|
|
|
recid = world->createRecord(npc)->mId;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_APPEND(Log::LOG_INFO, "- Creating new Creature record");
|
|
|
|
creature.mId = "Dedicated Player";
|
|
|
|
recid = world->createRecord(creature)->mId;
|
|
|
|
}
|
|
|
|
|
|
|
|
reference = new MWWorld::ManualRef(world->getStore(), recid, 1);
|
|
|
|
|
|
|
|
LOG_APPEND(Log::LOG_INFO, "- Creating new reference pointer for %s", this->npc.mName.c_str());
|
|
|
|
|
|
|
|
MWWorld::Ptr tmp;
|
|
|
|
|
|
|
|
if (reset)
|
|
|
|
{
|
|
|
|
if (cell.isExterior())
|
|
|
|
cellStore = world->getExterior(cell.mData.mX, cell.mData.mY);
|
|
|
|
else
|
|
|
|
cellStore = world->getInterior(cell.mName);
|
|
|
|
|
|
|
|
spawnPos = position;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = world->placeObject(reference->getPtr(), cellStore, spawnPos);
|
|
|
|
|
|
|
|
ptr.mCell = tmp.mCell;
|
|
|
|
ptr.mRef = tmp.mRef;
|
|
|
|
|
|
|
|
if (!reset)
|
|
|
|
{
|
|
|
|
cell = *ptr.getCell()->getCell();
|
|
|
|
position = ptr.getRefData().getPosition();
|
|
|
|
}
|
|
|
|
|
|
|
|
ESM::CustomMarker mEditingMarker = Main::get().getGUIController()->createMarker(guid);
|
|
|
|
marker = mEditingMarker;
|
|
|
|
setMarkerState(true);
|
2017-04-17 16:34:32 +00:00
|
|
|
}
|
|
|
|
|
2018-04-08 07:56:33 +00:00
|
|
|
void DedicatedPlayer::updateReference(ESM::NPC& npc, ESM::Creature& creature)
|
2017-04-17 16:34:32 +00:00
|
|
|
{
|
2018-04-08 07:56:33 +00:00
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
|
|
|
|
// Temporarily spawn or move player to the center of exterior 0, 0
|
|
|
|
ESM::Position spawnPos;
|
|
|
|
spawnPos.pos[0] = spawnPos.pos[1] = Main::get().getCellController()->getCellSize() / 2;
|
|
|
|
spawnPos.pos[2] = 0;
|
|
|
|
MWWorld::CellStore *cellStore = world->getExterior(0, 0);
|
|
|
|
|
|
|
|
LOG_APPEND(Log::LOG_INFO, "- Updating reference pointer for %s", npc.mName.c_str());
|
|
|
|
|
|
|
|
MWWorld::ESMStore *store = const_cast<MWWorld::ESMStore *>(&world->getStore());
|
|
|
|
MWWorld::Store<ESM::Creature> *creature_store = const_cast<MWWorld::Store<ESM::Creature> *> (&store->get<ESM::Creature>());
|
|
|
|
MWWorld::Store<ESM::NPC> *npc_store = const_cast<MWWorld::Store<ESM::NPC> *> (&store->get<ESM::NPC>());
|
|
|
|
|
|
|
|
if (!creatureRefId.empty())
|
|
|
|
{
|
|
|
|
if (!npc.mId.empty() || npc.mId != "Dedicated Player")
|
|
|
|
{
|
|
|
|
LOG_APPEND(Log::LOG_INFO, "- Deleting NPC record");
|
|
|
|
npc_store->erase(npc.mId);
|
|
|
|
npc.mId.clear();
|
|
|
|
}
|
|
|
|
creature.mId = ptr.get<ESM::Creature>()->mBase->mId;
|
|
|
|
creature_store->insert(creature);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!creature.mId.empty() || creature.mId != "Dedicated Player")
|
|
|
|
{
|
|
|
|
LOG_APPEND(Log::LOG_INFO, "- Deleting Creature record");
|
|
|
|
creature_store->erase(creature.mId);
|
|
|
|
creature.mId.clear();
|
|
|
|
}
|
|
|
|
npc.mId = ptr.get<ESM::NPC>()->mBase->mId;
|
|
|
|
npc_store->insert(npc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable Ptr to avoid graphical glitches caused by race changes
|
|
|
|
world->disable(ptr);
|
|
|
|
|
|
|
|
setPtr(world->moveObject(ptr, cellStore, spawnPos.pos[0], spawnPos.pos[1], spawnPos.pos[2]));
|
|
|
|
setCell();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DedicatedPlayer::deleteReference()
|
|
|
|
{
|
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
|
|
|
|
bool isNPC = reference->getPtr().getTypeName() == typeid(ESM::NPC).name();
|
|
|
|
if ((!creatureRefId.empty() && isNPC) ||
|
|
|
|
(creatureRefId.empty() && !isNPC))
|
|
|
|
{
|
|
|
|
LOG_APPEND(Log::LOG_INFO, "- Deleting old reference");
|
|
|
|
state = 0;
|
|
|
|
world->deleteObject(ptr);
|
|
|
|
delete reference;
|
|
|
|
reference = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MWWorld::Ptr DedicatedPlayer::getPtr()
|
|
|
|
{
|
|
|
|
return ptr;
|
2017-04-17 16:34:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MWWorld::ManualRef *DedicatedPlayer::getRef()
|
|
|
|
{
|
|
|
|
return reference;
|
|
|
|
}
|
|
|
|
|
2017-04-23 10:31:06 +00:00
|
|
|
void DedicatedPlayer::setPtr(const MWWorld::Ptr& newPtr)
|
2017-04-17 16:34:32 +00:00
|
|
|
{
|
2017-04-23 10:31:06 +00:00
|
|
|
ptr = newPtr;
|
2017-04-17 16:34:32 +00:00
|
|
|
}
|