forked from mirror/openmw-tes3mp
Merge remote-tracking branch 'scrawl/master'
This commit is contained in:
commit
f7c89015f9
64 changed files with 1160 additions and 945 deletions
|
@ -57,7 +57,7 @@ add_openmw_dir (mwworld
|
||||||
cells localscripts customdata weather inventorystore ptr actionopen actionread
|
cells localscripts customdata weather inventorystore ptr actionopen actionread
|
||||||
actionequip timestamp actionalchemy cellstore actionapply actioneat
|
actionequip timestamp actionalchemy cellstore actionapply actioneat
|
||||||
esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
|
esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
|
||||||
contentloader esmloader omwloader actiontrap cellreflist
|
contentloader esmloader omwloader actiontrap cellreflist projectilemanager
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwclass
|
add_openmw_dir (mwclass
|
||||||
|
|
|
@ -66,9 +66,13 @@ void OMW::Engine::executeLocalScripts()
|
||||||
|
|
||||||
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
|
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
|
||||||
{
|
{
|
||||||
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
if (MWBase::Environment::get().getStateManager()->getState()!=
|
||||||
MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame, paused);
|
MWBase::StateManager::State_NoGame)
|
||||||
MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame);
|
{
|
||||||
|
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||||
|
MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame, paused);
|
||||||
|
MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +114,12 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
||||||
|
|
||||||
|
|
||||||
// update actors
|
// update actors
|
||||||
MWBase::Environment::get().getMechanicsManager()->update(frametime,
|
if (MWBase::Environment::get().getStateManager()->getState()!=
|
||||||
paused);
|
MWBase::StateManager::State_NoGame)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->update(frametime,
|
||||||
|
paused);
|
||||||
|
}
|
||||||
|
|
||||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||||
MWBase::StateManager::State_Running)
|
MWBase::StateManager::State_Running)
|
||||||
|
@ -122,16 +130,24 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// update world
|
// update world
|
||||||
MWBase::Environment::get().getWorld()->update(frametime, paused);
|
if (MWBase::Environment::get().getStateManager()->getState()!=
|
||||||
|
MWBase::StateManager::State_NoGame)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->update(frametime, paused);
|
||||||
|
}
|
||||||
|
|
||||||
// update GUI
|
// update GUI
|
||||||
Ogre::RenderWindow* window = mOgre->getWindow();
|
if (MWBase::Environment::get().getStateManager()->getState()!=
|
||||||
unsigned int tri, batch;
|
MWBase::StateManager::State_NoGame)
|
||||||
MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch);
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch);
|
Ogre::RenderWindow* window = mOgre->getWindow();
|
||||||
|
unsigned int tri, batch;
|
||||||
|
MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch);
|
||||||
|
MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch);
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->onFrame(frametime);
|
MWBase::Environment::get().getWindowManager()->onFrame(frametime);
|
||||||
MWBase::Environment::get().getWindowManager()->update();
|
MWBase::Environment::get().getWindowManager()->update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -393,10 +409,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
mEnvironment.setJournal (new MWDialogue::Journal);
|
mEnvironment.setJournal (new MWDialogue::Journal);
|
||||||
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage));
|
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage));
|
||||||
|
|
||||||
mEnvironment.getWorld()->renderPlayer();
|
|
||||||
mechanics->buildPlayer();
|
|
||||||
window->updatePlayer();
|
|
||||||
|
|
||||||
mOgre->getRoot()->addFrameListener (this);
|
mOgre->getRoot()->addFrameListener (this);
|
||||||
|
|
||||||
// scripts
|
// scripts
|
||||||
|
|
|
@ -110,18 +110,25 @@ namespace MWBase
|
||||||
///< Play a sound, independently of 3D-position
|
///< Play a sound, independently of 3D-position
|
||||||
///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts.
|
///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts.
|
||||||
|
|
||||||
virtual SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId,
|
virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId,
|
||||||
float volume, float pitch, PlayType type=Play_TypeSfx,
|
float volume, float pitch, PlayType type=Play_TypeSfx,
|
||||||
PlayMode mode=Play_Normal, float offset=0) = 0;
|
PlayMode mode=Play_Normal, float offset=0) = 0;
|
||||||
///< Play a sound from an object
|
///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified.
|
||||||
///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts.
|
///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts.
|
||||||
|
|
||||||
|
virtual MWBase::SoundPtr playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId,
|
||||||
|
float volume, float pitch, PlayType type, PlayMode mode, float offset=0) = 0;
|
||||||
|
///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition.
|
||||||
|
|
||||||
virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0;
|
virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0;
|
||||||
///< Stop the given object from playing the given sound,
|
///< Stop the given object from playing the given sound,
|
||||||
|
|
||||||
virtual void stopSound3D(const MWWorld::Ptr &reference) = 0;
|
virtual void stopSound3D(const MWWorld::Ptr &reference) = 0;
|
||||||
///< Stop the given object from playing all sounds.
|
///< Stop the given object from playing all sounds.
|
||||||
|
|
||||||
|
virtual void stopSound(MWBase::SoundPtr sound) = 0;
|
||||||
|
///< Stop the given sound handle
|
||||||
|
|
||||||
virtual void stopSound(const MWWorld::CellStore *cell) = 0;
|
virtual void stopSound(const MWWorld::CellStore *cell) = 0;
|
||||||
///< Stop all sounds for the given cell.
|
///< Stop all sounds for the given cell.
|
||||||
|
|
||||||
|
|
|
@ -193,9 +193,9 @@ namespace MWBase
|
||||||
virtual void setDragDrop(bool dragDrop) = 0;
|
virtual void setDragDrop(bool dragDrop) = 0;
|
||||||
virtual bool getWorldMouseOver() = 0;
|
virtual bool getWorldMouseOver() = 0;
|
||||||
|
|
||||||
virtual void toggleFogOfWar() = 0;
|
virtual bool toggleFogOfWar() = 0;
|
||||||
|
|
||||||
virtual void toggleFullHelp() = 0;
|
virtual bool toggleFullHelp() = 0;
|
||||||
///< show extra info in item tooltips (owner, script)
|
///< show extra info in item tooltips (owner, script)
|
||||||
|
|
||||||
virtual bool getFullHelp() const = 0;
|
virtual bool getFullHelp() const = 0;
|
||||||
|
|
|
@ -126,7 +126,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void setWaterHeight(const float height) = 0;
|
virtual void setWaterHeight(const float height) = 0;
|
||||||
|
|
||||||
virtual void toggleWater() = 0;
|
virtual bool toggleWater() = 0;
|
||||||
|
|
||||||
virtual void adjustSky() = 0;
|
virtual void adjustSky() = 0;
|
||||||
|
|
||||||
|
@ -255,7 +255,8 @@ namespace MWBase
|
||||||
virtual void changeToExteriorCell (const ESM::Position& position) = 0;
|
virtual void changeToExteriorCell (const ESM::Position& position) = 0;
|
||||||
///< Move to exterior cell.
|
///< Move to exterior cell.
|
||||||
|
|
||||||
virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position) = 0;
|
virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool detectWorldSpaceChange=true) = 0;
|
||||||
|
///< @param detectWorldSpaceChange if true, clean up worldspace-specific data when the world space changes
|
||||||
|
|
||||||
virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0;
|
virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0;
|
||||||
///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
|
///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
|
||||||
|
@ -354,15 +355,14 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void update (float duration, bool paused) = 0;
|
virtual void update (float duration, bool paused) = 0;
|
||||||
|
|
||||||
virtual bool placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0;
|
virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0;
|
||||||
///< copy and place an object into the gameworld at the specified cursor position
|
///< copy and place an object into the gameworld at the specified cursor position
|
||||||
/// @param object
|
/// @param object
|
||||||
/// @param cursor X (relative 0-1)
|
/// @param cursor X (relative 0-1)
|
||||||
/// @param cursor Y (relative 0-1)
|
/// @param cursor Y (relative 0-1)
|
||||||
/// @param number of objects to place
|
/// @param number of objects to place
|
||||||
/// @return true if the object was placed, or false if it was rejected because the position is too far away
|
|
||||||
|
|
||||||
virtual void dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount) = 0;
|
virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount) = 0;
|
||||||
///< copy and place an object into the gameworld at the given actor's position
|
///< copy and place an object into the gameworld at the given actor's position
|
||||||
/// @param actor giving the dropped object position
|
/// @param actor giving the dropped object position
|
||||||
/// @param object
|
/// @param object
|
||||||
|
@ -468,7 +468,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void launchMagicBolt (const std::string& id, bool stack, const ESM::EffectList& effects,
|
virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId,
|
||||||
|
float speed, bool stack, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
||||||
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
|
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
|
||||||
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0;
|
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0;
|
||||||
|
@ -514,7 +515,7 @@ namespace MWBase
|
||||||
/// Spawn a blood effect for \a ptr at \a worldPosition
|
/// Spawn a blood effect for \a ptr at \a worldPosition
|
||||||
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
|
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
|
||||||
|
|
||||||
virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects,
|
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
|
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,16 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Container::respawn(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
MWWorld::LiveCellRef<ESM::Container> *ref =
|
||||||
|
ptr.get<ESM::Container>();
|
||||||
|
if (ref->mBase->mFlags & ESM::Container::Respawn)
|
||||||
|
{
|
||||||
|
ptr.getRefData().setCustomData(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||||
{
|
{
|
||||||
const std::string model = getModel(ptr);
|
const std::string model = getModel(ptr);
|
||||||
|
|
|
@ -64,6 +64,8 @@ namespace MWClass
|
||||||
|
|
||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
|
virtual void respawn (const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -822,6 +822,26 @@ namespace MWClass
|
||||||
return ptr.get<ESM::Creature>()->mBase->mData.mGold;
|
return ptr.get<ESM::Creature>()->mBase->mData.mGold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Creature::respawn(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
if (ptr.get<ESM::Creature>()->mBase->mFlags & ESM::Creature::Respawn)
|
||||||
|
{
|
||||||
|
// Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell.
|
||||||
|
// This also means we cannot respawn dynamically placed references with no content file connection.
|
||||||
|
if (ptr.getCellRef().mRefNum.mContentFile != -1)
|
||||||
|
{
|
||||||
|
if (ptr.getRefData().getCount() == 0)
|
||||||
|
ptr.getRefData().setCount(1);
|
||||||
|
|
||||||
|
// Reset to original position
|
||||||
|
ESM::Position& pos = ptr.getRefData().getPosition();
|
||||||
|
pos = ptr.getCellRef().mPos;
|
||||||
|
|
||||||
|
ptr.getRefData().setCustomData(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
||||||
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
|
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
|
||||||
const ESM::GameSetting *Creature::fEncumberedMoveEffect;
|
const ESM::GameSetting *Creature::fEncumberedMoveEffect;
|
||||||
|
|
|
@ -143,6 +143,8 @@ namespace MWClass
|
||||||
///< Write additional state from \a ptr into \a state.
|
///< Write additional state from \a ptr into \a state.
|
||||||
|
|
||||||
virtual int getBaseGold(const MWWorld::Ptr& ptr) const;
|
virtual int getBaseGold(const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
|
virtual void respawn (const MWWorld::Ptr& ptr) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace
|
||||||
{
|
{
|
||||||
// actorId of the creature we spawned
|
// actorId of the creature we spawned
|
||||||
int mSpawnActorId;
|
int mSpawnActorId;
|
||||||
|
bool mSpawn; // Should a new creature be spawned?
|
||||||
|
|
||||||
virtual MWWorld::CustomData *clone() const;
|
virtual MWWorld::CustomData *clone() const;
|
||||||
};
|
};
|
||||||
|
@ -31,6 +32,14 @@ namespace MWClass
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CreatureLevList::respawn(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
ensureCustomData(ptr);
|
||||||
|
|
||||||
|
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
||||||
|
customData.mSpawn = true;
|
||||||
|
}
|
||||||
|
|
||||||
void CreatureLevList::registerSelf()
|
void CreatureLevList::registerSelf()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Class> instance (new CreatureLevList);
|
boost::shared_ptr<Class> instance (new CreatureLevList);
|
||||||
|
@ -43,9 +52,8 @@ namespace MWClass
|
||||||
ensureCustomData(ptr);
|
ensureCustomData(ptr);
|
||||||
|
|
||||||
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
||||||
if (customData.mSpawnActorId != -1)
|
if (!customData.mSpawn)
|
||||||
return; // TODO: handle respawning
|
return;
|
||||||
|
|
||||||
|
|
||||||
MWWorld::LiveCellRef<ESM::CreatureLevList> *ref =
|
MWWorld::LiveCellRef<ESM::CreatureLevList> *ref =
|
||||||
ptr.get<ESM::CreatureLevList>();
|
ptr.get<ESM::CreatureLevList>();
|
||||||
|
@ -54,11 +62,21 @@ namespace MWClass
|
||||||
|
|
||||||
if (!id.empty())
|
if (!id.empty())
|
||||||
{
|
{
|
||||||
|
// Delete the previous creature
|
||||||
|
if (customData.mSpawnActorId != -1)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr creature = MWBase::Environment::get().getWorld()->searchPtrViaActorId(customData.mSpawnActorId);
|
||||||
|
if (!creature.isEmpty())
|
||||||
|
MWBase::Environment::get().getWorld()->deleteObject(creature);
|
||||||
|
customData.mSpawnActorId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
MWWorld::ManualRef ref(store, id);
|
MWWorld::ManualRef ref(store, id);
|
||||||
ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos;
|
ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos;
|
||||||
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().mPos);
|
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().mPos);
|
||||||
customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId();
|
customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId();
|
||||||
|
customData.mSpawn = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +86,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::auto_ptr<CreatureLevListCustomData> data (new CreatureLevListCustomData);
|
std::auto_ptr<CreatureLevListCustomData> data (new CreatureLevListCustomData);
|
||||||
data->mSpawnActorId = -1;
|
data->mSpawnActorId = -1;
|
||||||
|
data->mSpawn = true;
|
||||||
|
|
||||||
ptr.getRefData().setCustomData(data.release());
|
ptr.getRefData().setCustomData(data.release());
|
||||||
}
|
}
|
||||||
|
@ -81,6 +100,7 @@ namespace MWClass
|
||||||
ensureCustomData(ptr);
|
ensureCustomData(ptr);
|
||||||
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
||||||
customData.mSpawnActorId = state2.mSpawnActorId;
|
customData.mSpawnActorId = state2.mSpawnActorId;
|
||||||
|
customData.mSpawn = state2.mSpawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureLevList::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
void CreatureLevList::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||||
|
@ -91,5 +111,6 @@ namespace MWClass
|
||||||
ensureCustomData(ptr);
|
ensureCustomData(ptr);
|
||||||
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
||||||
state2.mSpawnActorId = customData.mSpawnActorId;
|
state2.mSpawnActorId = customData.mSpawnActorId;
|
||||||
|
state2.mSpawn = customData.mSpawn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ namespace MWClass
|
||||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||||
const;
|
const;
|
||||||
///< Write additional state from \a ptr into \a state.
|
///< Write additional state from \a ptr into \a state.
|
||||||
|
|
||||||
|
virtual void respawn (const MWWorld::Ptr& ptr) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -621,7 +621,8 @@ namespace MWClass
|
||||||
|
|
||||||
// Attacking peaceful NPCs is a crime
|
// Attacking peaceful NPCs is a crime
|
||||||
// anything below 80 is considered peaceful (see Actors::updateActor)
|
// anything below 80 is considered peaceful (see Actors::updateActor)
|
||||||
if (!attacker.isEmpty() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80)
|
if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).isHostile() &&
|
||||||
|
ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80)
|
||||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
|
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
|
||||||
|
|
||||||
getCreatureStats(ptr).setAttacked(true);
|
getCreatureStats(ptr).setAttacked(true);
|
||||||
|
@ -1309,6 +1310,26 @@ namespace MWClass
|
||||||
return Misc::StringUtils::ciEqual(ptr.get<ESM::NPC>()->mBase->mClass, className);
|
return Misc::StringUtils::ciEqual(ptr.get<ESM::NPC>()->mBase->mClass, className);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Npc::respawn(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
if (ptr.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Respawn)
|
||||||
|
{
|
||||||
|
// Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell.
|
||||||
|
// This also means we cannot respawn dynamically placed references with no content file connection.
|
||||||
|
if (ptr.getCellRef().mRefNum.mContentFile != -1)
|
||||||
|
{
|
||||||
|
if (ptr.getRefData().getCount() == 0)
|
||||||
|
ptr.getRefData().setCount(1);
|
||||||
|
|
||||||
|
// Reset to original position
|
||||||
|
ESM::Position& pos = ptr.getRefData().getPosition();
|
||||||
|
pos = ptr.getCellRef().mPos;
|
||||||
|
|
||||||
|
ptr.getRefData().setCustomData(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
||||||
const ESM::GameSetting *Npc::fMaxWalkSpeed;
|
const ESM::GameSetting *Npc::fMaxWalkSpeed;
|
||||||
const ESM::GameSetting *Npc::fEncumberedMoveEffect;
|
const ESM::GameSetting *Npc::fEncumberedMoveEffect;
|
||||||
|
|
|
@ -178,6 +178,8 @@ namespace MWClass
|
||||||
virtual bool canWalk (const MWWorld::Ptr &ptr) const {
|
virtual bool canWalk (const MWWorld::Ptr &ptr) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void respawn (const MWWorld::Ptr& ptr) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,8 @@ namespace MWGui
|
||||||
mSourceModel->update();
|
mSourceModel->update();
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
targetView->update();
|
if (targetView)
|
||||||
|
targetView->update();
|
||||||
|
|
||||||
// We need to update the view since an other item could be auto-equipped.
|
// We need to update the view since an other item could be auto-equipped.
|
||||||
mSourceView->update();
|
mSourceView->update();
|
||||||
|
|
|
@ -17,9 +17,47 @@
|
||||||
#include "itemmodel.hpp"
|
#include "itemmodel.hpp"
|
||||||
#include "container.hpp"
|
#include "container.hpp"
|
||||||
|
|
||||||
|
#include "itemmodel.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes it possible to use ItemModel::moveItem to move an item from an inventory to the world.
|
||||||
|
*/
|
||||||
|
class WorldItemModel : public ItemModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WorldItemModel(float left, float top) : mLeft(left), mTop(top) {}
|
||||||
|
virtual ~WorldItemModel() {}
|
||||||
|
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false)
|
||||||
|
{
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
|
MWWorld::Ptr dropped;
|
||||||
|
if (world->canPlaceObject(mLeft, mTop))
|
||||||
|
dropped = world->placeObject(item.mBase, mLeft, mTop, count);
|
||||||
|
else
|
||||||
|
dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count);
|
||||||
|
if (setNewOwner)
|
||||||
|
dropped.getCellRef().mOwner = "";
|
||||||
|
|
||||||
|
return dropped;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void removeItem (const ItemStack& item, size_t count) { throw std::runtime_error("removeItem not implemented"); }
|
||||||
|
virtual ModelIndex getIndex (ItemStack item) { throw std::runtime_error("getIndex not implemented"); }
|
||||||
|
virtual void update() {}
|
||||||
|
virtual size_t getItemCount() { return 0; }
|
||||||
|
virtual ItemStack getItem (ModelIndex index) { throw std::runtime_error("getItem not implemented"); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Where to drop the item
|
||||||
|
float mLeft;
|
||||||
|
float mTop;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
|
HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
|
||||||
: Layout("openmw_hud.layout")
|
: Layout("openmw_hud.layout")
|
||||||
, mHealth(NULL)
|
, mHealth(NULL)
|
||||||
|
@ -229,10 +267,6 @@ namespace MWGui
|
||||||
if (mDragAndDrop->mIsOnDragAndDrop)
|
if (mDragAndDrop->mIsOnDragAndDrop)
|
||||||
{
|
{
|
||||||
// drop item into the gameworld
|
// drop item into the gameworld
|
||||||
MWWorld::Ptr object = mDragAndDrop->mItem.mBase;
|
|
||||||
|
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->breakInvisibility(
|
MWBase::Environment::get().getWorld()->breakInvisibility(
|
||||||
MWBase::Environment::get().getWorld()->getPlayerPtr());
|
MWBase::Environment::get().getWorld()->getPlayerPtr());
|
||||||
|
|
||||||
|
@ -241,20 +275,10 @@ namespace MWGui
|
||||||
float mouseX = cursorPosition.left / float(viewSize.width);
|
float mouseX = cursorPosition.left / float(viewSize.width);
|
||||||
float mouseY = cursorPosition.top / float(viewSize.height);
|
float mouseY = cursorPosition.top / float(viewSize.height);
|
||||||
|
|
||||||
if (world->canPlaceObject(mouseX, mouseY))
|
WorldItemModel drop (mouseX, mouseY);
|
||||||
world->placeObject(object, mouseX, mouseY, mDragAndDrop->mDraggedCount);
|
mDragAndDrop->drop(&drop, NULL);
|
||||||
else
|
|
||||||
world->dropObjectOnGround(world->getPlayerPtr(), object, mDragAndDrop->mDraggedCount);
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->changePointer("arrow");
|
MWBase::Environment::get().getWindowManager()->changePointer("arrow");
|
||||||
|
|
||||||
std::string sound = MWWorld::Class::get(object).getDownSoundId(object);
|
|
||||||
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
|
|
||||||
|
|
||||||
// remove object from the container it was coming from
|
|
||||||
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
|
|
||||||
mDragAndDrop->finish();
|
|
||||||
mDragAndDrop->mSourceModel->update();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -89,10 +89,11 @@ namespace MWGui
|
||||||
mChanged = true;
|
mChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMapBase::toggleFogOfWar()
|
bool LocalMapBase::toggleFogOfWar()
|
||||||
{
|
{
|
||||||
mFogOfWar = !mFogOfWar;
|
mFogOfWar = !mFogOfWar;
|
||||||
applyFogOfWar();
|
applyFogOfWar();
|
||||||
|
return mFogOfWar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMapBase::applyFogOfWar()
|
void LocalMapBase::applyFogOfWar()
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace MWGui
|
||||||
void setPlayerDir(const float x, const float y);
|
void setPlayerDir(const float x, const float y);
|
||||||
void setPlayerPos(const float x, const float y);
|
void setPlayerPos(const float x, const float y);
|
||||||
|
|
||||||
void toggleFogOfWar();
|
bool toggleFogOfWar();
|
||||||
|
|
||||||
struct MarkerPosition
|
struct MarkerPosition
|
||||||
{
|
{
|
||||||
|
|
|
@ -547,9 +547,10 @@ namespace MWGui
|
||||||
return " (" + boost::lexical_cast<std::string>(value) + ")";
|
return " (" + boost::lexical_cast<std::string>(value) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolTips::toggleFullHelp()
|
bool ToolTips::toggleFullHelp()
|
||||||
{
|
{
|
||||||
mFullHelp = !mFullHelp;
|
mFullHelp = !mFullHelp;
|
||||||
|
return mFullHelp;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ToolTips::getFullHelp() const
|
bool ToolTips::getFullHelp() const
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace MWGui
|
||||||
|
|
||||||
void setEnabled(bool enabled);
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
void toggleFullHelp(); ///< show extra info in item tooltips (owner, script)
|
bool toggleFullHelp(); ///< show extra info in item tooltips (owner, script)
|
||||||
bool getFullHelp() const;
|
bool getFullHelp() const;
|
||||||
|
|
||||||
void setDelay(float delay);
|
void setDelay(float delay);
|
||||||
|
|
|
@ -814,10 +814,10 @@ namespace MWGui
|
||||||
mHud->setMinimapVisible (visible);
|
mHud->setMinimapVisible (visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::toggleFogOfWar()
|
bool WindowManager::toggleFogOfWar()
|
||||||
{
|
{
|
||||||
mMap->toggleFogOfWar();
|
mMap->toggleFogOfWar();
|
||||||
mHud->toggleFogOfWar();
|
return mHud->toggleFogOfWar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::setFocusObject(const MWWorld::Ptr& focus)
|
void WindowManager::setFocusObject(const MWWorld::Ptr& focus)
|
||||||
|
@ -830,9 +830,9 @@ namespace MWGui
|
||||||
mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y);
|
mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::toggleFullHelp()
|
bool WindowManager::toggleFullHelp()
|
||||||
{
|
{
|
||||||
mToolTips->toggleFullHelp();
|
return mToolTips->toggleFullHelp();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindowManager::getFullHelp() const
|
bool WindowManager::getFullHelp() const
|
||||||
|
|
|
@ -188,8 +188,8 @@ namespace MWGui
|
||||||
virtual void setDragDrop(bool dragDrop);
|
virtual void setDragDrop(bool dragDrop);
|
||||||
virtual bool getWorldMouseOver();
|
virtual bool getWorldMouseOver();
|
||||||
|
|
||||||
virtual void toggleFogOfWar();
|
virtual bool toggleFogOfWar();
|
||||||
virtual void toggleFullHelp(); ///< show extra info in item tooltips (owner, script)
|
virtual bool toggleFullHelp(); ///< show extra info in item tooltips (owner, script)
|
||||||
virtual bool getFullHelp() const;
|
virtual bool getFullHelp() const;
|
||||||
|
|
||||||
virtual void setActiveMap(int x, int y, bool interior);
|
virtual void setActiveMap(int x, int y, bool interior);
|
||||||
|
|
|
@ -540,7 +540,7 @@ namespace MWMechanics
|
||||||
MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr());
|
MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr());
|
||||||
|
|
||||||
// Make the summoned creature follow its master and help in fights
|
// Make the summoned creature follow its master and help in fights
|
||||||
AiFollow package(ptr);
|
AiFollow package(ptr.getRefData().getHandle());
|
||||||
summonedCreatureStats.getAiSequence().stack(package, ref.getPtr());
|
summonedCreatureStats.getAiSequence().stack(package, ref.getPtr());
|
||||||
int creatureActorId = summonedCreatureStats.getActorId();
|
int creatureActorId = summonedCreatureStats.getActorId();
|
||||||
|
|
||||||
|
@ -785,7 +785,7 @@ namespace MWMechanics
|
||||||
// Update witness crime id
|
// Update witness crime id
|
||||||
npcStats.setCrimeId(-1);
|
npcStats.setCrimeId(-1);
|
||||||
}
|
}
|
||||||
else if (!creatureStats.isHostile())
|
else if (!creatureStats.isHostile() && creatureStats.getAiSequence().getTypeId() != AiPackage::TypeIdPursue)
|
||||||
{
|
{
|
||||||
if (ptr.getClass().isClass(ptr, "Guard"))
|
if (ptr.getClass().isClass(ptr, "Guard"))
|
||||||
creatureStats.getAiSequence().stack(AiPursue(player), ptr);
|
creatureStats.getAiSequence().stack(AiPursue(player), ptr);
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/timestamp.hpp"
|
#include "../mwworld/timestamp.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
|
||||||
|
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
|
@ -21,8 +19,8 @@
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
AiEscort::AiEscort(const MWWorld::Ptr& actor, int duration, float x, float y, float z)
|
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
|
||||||
: mActorId(actor.getClass().getCreatureStats(actor).getActorId()), mX(x), mY(y), mZ(z), mDuration(duration)
|
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||||
, mCellX(std::numeric_limits<int>::max())
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
, mCellY(std::numeric_limits<int>::max())
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
|
@ -40,8 +38,8 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AiEscort::AiEscort(const MWWorld::Ptr& actor, const std::string &cellId,int duration, float x, float y, float z)
|
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z)
|
||||||
: mActorId(actor.getClass().getCreatureStats(actor).getActorId()), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
|
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||||
, mCellX(std::numeric_limits<int>::max())
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
, mCellY(std::numeric_limits<int>::max())
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
|
@ -77,14 +75,7 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId);
|
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
||||||
if (follower.isEmpty())
|
|
||||||
{
|
|
||||||
// The follower disappeared
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float* const leaderPos = actor.getRefData().getPosition().pos;
|
const float* const leaderPos = actor.getRefData().getPosition().pos;
|
||||||
const float* const followerPos = follower.getRefData().getPosition().pos;
|
const float* const followerPos = follower.getRefData().getPosition().pos;
|
||||||
double differenceBetween[3];
|
double differenceBetween[3];
|
||||||
|
@ -98,7 +89,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
||||||
{
|
{
|
||||||
if(pathTo(actor,ESM::Pathgrid::Point(mX,mY,mZ),duration)) //Returns true on path complete
|
if(pathTo(actor,ESM::Pathgrid::Point(mX,mY,mZ),duration)) //Returns true on path complete
|
||||||
return true;
|
return true;
|
||||||
mMaxDist = 470;
|
mMaxDist = 470;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@ namespace MWMechanics
|
||||||
/// Implementation of AiEscort
|
/// Implementation of AiEscort
|
||||||
/** The Actor will escort the specified actor to the world position x, y, z until they reach their position, or they run out of time
|
/** The Actor will escort the specified actor to the world position x, y, z until they reach their position, or they run out of time
|
||||||
\implement AiEscort **/
|
\implement AiEscort **/
|
||||||
AiEscort(const MWWorld::Ptr& actor,int duration, float x, float y, float z);
|
AiEscort(const std::string &actorId,int duration, float x, float y, float z);
|
||||||
/// Implementation of AiEscortCell
|
/// Implementation of AiEscortCell
|
||||||
/** The Actor will escort the specified actor to the cell position x, y, z until they reach their position, or they run out of time
|
/** The Actor will escort the specified actor to the cell position x, y, z until they reach their position, or they run out of time
|
||||||
\implement AiEscortCell **/
|
\implement AiEscortCell **/
|
||||||
AiEscort(const MWWorld::Ptr& actor,const std::string &cellId,int duration, float x, float y, float z);
|
AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z);
|
||||||
|
|
||||||
virtual AiEscort *clone() const;
|
virtual AiEscort *clone() const;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace MWMechanics
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int mActorId;
|
std::string mActorId;
|
||||||
std::string mCellId;
|
std::string mCellId;
|
||||||
float mX;
|
float mX;
|
||||||
float mY;
|
float mY;
|
||||||
|
|
|
@ -11,26 +11,23 @@
|
||||||
|
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const MWWorld::Ptr& actor,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mCellId(""), AiPackage()
|
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), AiPackage()
|
||||||
{
|
{
|
||||||
mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
|
||||||
}
|
}
|
||||||
MWMechanics::AiFollow::AiFollow(const MWWorld::Ptr& actor,const std::string &cellId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mCellId(cellId), AiPackage()
|
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), AiPackage()
|
||||||
{
|
{
|
||||||
mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const MWWorld::Ptr& actor)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId)
|
||||||
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mCellId(""), AiPackage()
|
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId(""), AiPackage()
|
||||||
{
|
{
|
||||||
mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); //The target to follow
|
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mActorId, false); //The target to follow
|
||||||
|
|
||||||
if(target == MWWorld::Ptr()) return true; //Target doesn't exist
|
if(target == MWWorld::Ptr()) return true; //Target doesn't exist
|
||||||
|
|
||||||
|
@ -78,8 +75,7 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
|
|
||||||
std::string MWMechanics::AiFollow::getFollowedActor()
|
std::string MWMechanics::AiFollow::getFollowedActor()
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); //The target to follow
|
return mActorId;
|
||||||
return target.getCellRef().mRefID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||||
|
|
|
@ -10,16 +10,16 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief AiPackage for an actor to follow another actor/the PC
|
/// \brief AiPackage for an actor to follow another actor/the PC
|
||||||
/** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
|
/** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
|
||||||
**/
|
**/
|
||||||
class AiFollow : public AiPackage
|
class AiFollow : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Follow Actor for duration or until you arrive at a world position
|
/// Follow Actor for duration or until you arrive at a world position
|
||||||
AiFollow(const MWWorld::Ptr& actor,float duration, float X, float Y, float Z);
|
AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z);
|
||||||
/// Follow Actor for duration or until you arrive at a position in a cell
|
/// Follow Actor for duration or until you arrive at a position in a cell
|
||||||
AiFollow(const MWWorld::Ptr& actor,const std::string &CellId,float duration, float X, float Y, float Z);
|
AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z);
|
||||||
/// Follow Actor indefinitively
|
/// Follow Actor indefinitively
|
||||||
AiFollow(const MWWorld::Ptr& actor);
|
AiFollow(const std::string &ActorId);
|
||||||
|
|
||||||
virtual AiFollow *clone() const;
|
virtual AiFollow *clone() const;
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@ namespace MWMechanics
|
||||||
float mX;
|
float mX;
|
||||||
float mY;
|
float mY;
|
||||||
float mZ;
|
float mZ;
|
||||||
int mActorId; // The actor we should follow
|
std::string mActorId;
|
||||||
std::string mCellId;
|
std::string mCellId;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -175,8 +175,7 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
|
||||||
else if (it->mType == ESM::AI_Escort)
|
else if (it->mType == ESM::AI_Escort)
|
||||||
{
|
{
|
||||||
ESM::AITarget data = it->mTarget;
|
ESM::AITarget data = it->mTarget;
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(data.mId.toString(), false);
|
package = new MWMechanics::AiEscort(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
|
||||||
package = new MWMechanics::AiEscort(target, data.mDuration, data.mX, data.mY, data.mZ);
|
|
||||||
}
|
}
|
||||||
else if (it->mType == ESM::AI_Travel)
|
else if (it->mType == ESM::AI_Travel)
|
||||||
{
|
{
|
||||||
|
@ -191,8 +190,7 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
|
||||||
else //if (it->mType == ESM::AI_Follow)
|
else //if (it->mType == ESM::AI_Follow)
|
||||||
{
|
{
|
||||||
ESM::AITarget data = it->mTarget;
|
ESM::AITarget data = it->mTarget;
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(data.mId.toString(), false);
|
package = new MWMechanics::AiFollow(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
|
||||||
package = new MWMechanics::AiFollow(target, data.mDuration, data.mX, data.mY, data.mZ);
|
|
||||||
}
|
}
|
||||||
mPackages.push_back(package);
|
mPackages.push_back(package);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,41 @@
|
||||||
#include "magiceffects.hpp"
|
#include "magiceffects.hpp"
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Get projectile properties (model, sound and speed) for a spell with the given effects
|
||||||
|
/// If \a model is empty, the spell has no ranged effects and should not spawn a projectile.
|
||||||
|
void getProjectileInfo (const ESM::EffectList& effects, std::string& model, std::string& sound, float& speed)
|
||||||
|
{
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
||||||
|
iter!=effects.mList.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (iter->mRange != ESM::RT_Target)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
|
iter->mEffectID);
|
||||||
|
|
||||||
|
model = magicEffect->mBolt;
|
||||||
|
if (model.empty())
|
||||||
|
model = "VFX_DefaultBolt";
|
||||||
|
|
||||||
|
static const std::string schools[] = {
|
||||||
|
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||||
|
};
|
||||||
|
if (!magicEffect->mBoltSound.empty())
|
||||||
|
sound = magicEffect->mBoltSound;
|
||||||
|
else
|
||||||
|
sound = schools[magicEffect->mData.mSchool] + " bolt";
|
||||||
|
|
||||||
|
speed = magicEffect->mData.mSpeed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -409,7 +444,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!exploded)
|
if (!exploded)
|
||||||
MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, mTarget, effects, caster, mId, mSourceName);
|
MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, mId, mSourceName);
|
||||||
|
|
||||||
if (!reflectedEffects.mList.empty())
|
if (!reflectedEffects.mList.empty())
|
||||||
inflict(caster, target, reflectedEffects, range, true);
|
inflict(caster, target, reflectedEffects, range, true);
|
||||||
|
@ -603,7 +638,13 @@ namespace MWMechanics
|
||||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, enchantment->mEffects, mCaster, mSourceName);
|
std::string projectileModel;
|
||||||
|
std::string sound;
|
||||||
|
float speed = 0;
|
||||||
|
getProjectileInfo(enchantment->mEffects, projectileModel, sound, speed);
|
||||||
|
if (!projectileModel.empty())
|
||||||
|
MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed,
|
||||||
|
false, enchantment->mEffects, mCaster, mSourceName);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -682,7 +723,15 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, spell->mEffects, mCaster, mSourceName);
|
|
||||||
|
std::string projectileModel;
|
||||||
|
std::string sound;
|
||||||
|
float speed = 0;
|
||||||
|
getProjectileInfo(spell->mEffects, projectileModel, sound, speed);
|
||||||
|
if (!projectileModel.empty())
|
||||||
|
MWBase::Environment::get().getWorld()->launchMagicBolt(projectileModel, sound, mId, speed,
|
||||||
|
false, spell->mEffects, mCaster, mSourceName);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,18 +11,6 @@
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
class EffectAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
float mTime;
|
|
||||||
public:
|
|
||||||
EffectAnimationTime() : mTime(0) { }
|
|
||||||
void addTime(float time) { mTime += time; }
|
|
||||||
|
|
||||||
virtual Ogre::Real getValue() const { return mTime; }
|
|
||||||
virtual void setValue(Ogre::Real value) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
EffectManager::EffectManager(Ogre::SceneManager *sceneMgr)
|
EffectManager::EffectManager(Ogre::SceneManager *sceneMgr)
|
||||||
: mSceneMgr(sceneMgr)
|
: mSceneMgr(sceneMgr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,20 @@
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class EffectAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
float mTime;
|
||||||
|
public:
|
||||||
|
EffectAnimationTime() : mTime(0) { }
|
||||||
|
void addTime(float time) { mTime += time; }
|
||||||
|
|
||||||
|
virtual Ogre::Real getValue() const { return mTime; }
|
||||||
|
virtual void setValue(Ogre::Real value) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Note: effects attached to another object should be managed by MWRender::Animation::addEffect.
|
// Note: effects attached to another object should be managed by MWRender::Animation::addEffect.
|
||||||
// This class manages "free" effects, i.e. attached to a dedicated scene node in the world.
|
// This class manages "free" effects, i.e. attached to a dedicated scene node in the world.
|
||||||
class EffectManager
|
class EffectManager
|
||||||
|
|
|
@ -234,9 +234,9 @@ void RenderingManager::removeWater ()
|
||||||
mWater->setActive(false);
|
mWater->setActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::toggleWater()
|
bool RenderingManager::toggleWater()
|
||||||
{
|
{
|
||||||
mWater->toggle();
|
return mWater->toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::cellAdded (MWWorld::CellStore *store)
|
void RenderingManager::cellAdded (MWWorld::CellStore *store)
|
||||||
|
@ -694,15 +694,8 @@ Shadows* RenderingManager::getShadows()
|
||||||
return mShadows;
|
return mShadows;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::switchToInterior()
|
void RenderingManager::notifyWorldSpaceChanged()
|
||||||
{
|
{
|
||||||
// TODO: also do this when switching worldspace
|
|
||||||
mEffectManager->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderingManager::switchToExterior()
|
|
||||||
{
|
|
||||||
// TODO: also do this when switching worldspace
|
|
||||||
mEffectManager->clear();
|
mEffectManager->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1061,6 +1054,7 @@ void RenderingManager::spawnEffect(const std::string &model, const std::string &
|
||||||
void RenderingManager::clear()
|
void RenderingManager::clear()
|
||||||
{
|
{
|
||||||
mLocalMap->clear();
|
mLocalMap->clear();
|
||||||
|
notifyWorldSpaceChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -127,7 +127,7 @@ public:
|
||||||
void rotateObject (const MWWorld::Ptr& ptr);
|
void rotateObject (const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
void setWaterHeight(const float height);
|
void setWaterHeight(const float height);
|
||||||
void toggleWater();
|
bool toggleWater();
|
||||||
|
|
||||||
/// Updates object rendering after cell change
|
/// Updates object rendering after cell change
|
||||||
/// \param old Object reference in previous cell
|
/// \param old Object reference in previous cell
|
||||||
|
@ -163,8 +163,7 @@ public:
|
||||||
|
|
||||||
Shadows* getShadows();
|
Shadows* getShadows();
|
||||||
|
|
||||||
void switchToInterior();
|
void notifyWorldSpaceChanged();
|
||||||
void switchToExterior();
|
|
||||||
|
|
||||||
void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches);
|
void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches);
|
||||||
|
|
||||||
|
|
|
@ -326,10 +326,11 @@ void Water::setHeight(const float height)
|
||||||
sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(height)));
|
sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(height)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Water::toggle()
|
bool Water::toggle()
|
||||||
{
|
{
|
||||||
mToggled = !mToggled;
|
mToggled = !mToggled;
|
||||||
updateVisible();
|
updateVisible();
|
||||||
|
return mToggled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -150,7 +150,7 @@ namespace MWRender {
|
||||||
|
|
||||||
void setActive(bool active);
|
void setActive(bool active);
|
||||||
|
|
||||||
void toggle();
|
bool toggle();
|
||||||
void update(float dt, Ogre::Vector3 player);
|
void update(float dt, Ogre::Vector3 player);
|
||||||
void frameStarted(float dt);
|
void frameStarted(float dt);
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,6 @@ namespace MWScript
|
||||||
|
|
||||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true);
|
|
||||||
|
|
||||||
Interpreter::Type_Float duration = runtime[0].mFloat;
|
Interpreter::Type_Float duration = runtime[0].mFloat;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
@ -108,7 +107,7 @@ namespace MWScript
|
||||||
// discard additional arguments (reset), because we have no idea what they mean.
|
// discard additional arguments (reset), because we have no idea what they mean.
|
||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiEscort escortPackage(actor, duration, x, y, z);
|
MWMechanics::AiEscort escortPackage(actorID, duration, x, y, z);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
|
||||||
|
|
||||||
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
||||||
|
@ -127,7 +126,6 @@ namespace MWScript
|
||||||
|
|
||||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true);
|
|
||||||
|
|
||||||
std::string cellID = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string cellID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
@ -147,7 +145,7 @@ namespace MWScript
|
||||||
// discard additional arguments (reset), because we have no idea what they mean.
|
// discard additional arguments (reset), because we have no idea what they mean.
|
||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiEscort escortPackage(actor, cellID, duration, x, y, z);
|
MWMechanics::AiEscort escortPackage(actorID, cellID, duration, x, y, z);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
|
||||||
|
|
||||||
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
||||||
|
@ -283,7 +281,6 @@ namespace MWScript
|
||||||
|
|
||||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true);
|
|
||||||
|
|
||||||
Interpreter::Type_Float duration = runtime[0].mFloat;
|
Interpreter::Type_Float duration = runtime[0].mFloat;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
@ -300,7 +297,7 @@ namespace MWScript
|
||||||
// discard additional arguments (reset), because we have no idea what they mean.
|
// discard additional arguments (reset), because we have no idea what they mean.
|
||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiFollow followPackage(actor, duration, x, y ,z);
|
MWMechanics::AiFollow followPackage(actorID, duration, x, y ,z);
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
|
||||||
|
|
||||||
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
||||||
|
@ -319,7 +316,6 @@ namespace MWScript
|
||||||
|
|
||||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true);
|
|
||||||
|
|
||||||
std::string cellID = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string cellID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
@ -339,8 +335,8 @@ namespace MWScript
|
||||||
// discard additional arguments (reset), because we have no idea what they mean.
|
// discard additional arguments (reset), because we have no idea what they mean.
|
||||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AiFollow followPackage(actor, cellID, duration, x, y ,z);
|
MWMechanics::AiFollow followPackage(actorID, cellID, duration, x, y ,z);
|
||||||
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
|
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
|
||||||
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime)
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->toggleFogOfWar();
|
runtime.getContext().report(MWBase::Environment::get().getWindowManager()->toggleFogOfWar() ? "Fog of war -> On"
|
||||||
|
: "Fog of war -> Off");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -102,7 +103,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime)
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->toggleFullHelp();
|
runtime.getContext().report(MWBase::Environment::get().getWindowManager()->toggleFullHelp() ? "Full help -> On"
|
||||||
|
: "Full help -> Off");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -275,7 +275,8 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime)
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->toggleWater();
|
runtime.getContext().report(MWBase::Environment::get().getWorld()->toggleWater() ? "Water -> On"
|
||||||
|
: "Water -> Off");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -356,6 +356,44 @@ namespace MWSound
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWBase::SoundPtr SoundManager::playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId,
|
||||||
|
float volume, float pitch, PlayType type, PlayMode mode, float offset)
|
||||||
|
{
|
||||||
|
MWBase::SoundPtr sound;
|
||||||
|
if(!mOutput->isInitialized())
|
||||||
|
return sound;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Look up the sound in the ESM data
|
||||||
|
float basevol = volumeFromType(type);
|
||||||
|
float min, max;
|
||||||
|
std::string file = lookup(soundId, volume, min, max);
|
||||||
|
|
||||||
|
sound = mOutput->playSound3D(file, initialPos, volume, basevol, pitch, min, max, mode|type, offset);
|
||||||
|
mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId);
|
||||||
|
}
|
||||||
|
catch(std::exception &e)
|
||||||
|
{
|
||||||
|
//std::cout <<"Sound Error: "<<e.what()<< std::endl;
|
||||||
|
}
|
||||||
|
return sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundManager::stopSound (MWBase::SoundPtr sound)
|
||||||
|
{
|
||||||
|
SoundMap::iterator snditer = mActiveSounds.begin();
|
||||||
|
while(snditer != mActiveSounds.end())
|
||||||
|
{
|
||||||
|
if(snditer->first == sound)
|
||||||
|
{
|
||||||
|
snditer->first->stop();
|
||||||
|
mActiveSounds.erase(snditer++);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++snditer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId)
|
void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId)
|
||||||
{
|
{
|
||||||
SoundMap::iterator snditer = mActiveSounds.begin();
|
SoundMap::iterator snditer = mActiveSounds.begin();
|
||||||
|
|
|
@ -115,6 +115,13 @@ namespace MWSound
|
||||||
virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId,
|
virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId,
|
||||||
float volume, float pitch, PlayType type=Play_TypeSfx,
|
float volume, float pitch, PlayType type=Play_TypeSfx,
|
||||||
PlayMode mode=Play_Normal, float offset=0);
|
PlayMode mode=Play_Normal, float offset=0);
|
||||||
|
///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified.
|
||||||
|
///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts.
|
||||||
|
|
||||||
|
virtual MWBase::SoundPtr playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId,
|
||||||
|
float volume, float pitch, PlayType type, PlayMode mode, float offset=0);
|
||||||
|
///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition.
|
||||||
|
|
||||||
///< Play a sound from an object
|
///< Play a sound from an object
|
||||||
///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end.
|
///< @param offset value from [0,1], when to start playback. 0 is beginning, 1 is end.
|
||||||
|
|
||||||
|
@ -124,6 +131,9 @@ namespace MWSound
|
||||||
virtual void stopSound3D(const MWWorld::Ptr &reference);
|
virtual void stopSound3D(const MWWorld::Ptr &reference);
|
||||||
///< Stop the given object from playing all sounds.
|
///< Stop the given object from playing all sounds.
|
||||||
|
|
||||||
|
virtual void stopSound(MWBase::SoundPtr sound);
|
||||||
|
///< Stop the given sound handle
|
||||||
|
|
||||||
virtual void stopSound(const MWWorld::CellStore *cell);
|
virtual void stopSound(const MWWorld::CellStore *cell);
|
||||||
///< Stop all sounds for the given cell.
|
///< Stop all sounds for the given cell.
|
||||||
|
|
||||||
|
|
|
@ -319,6 +319,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
|
||||||
case ESM::REC_WTHR:
|
case ESM::REC_WTHR:
|
||||||
case ESM::REC_DYNA:
|
case ESM::REC_DYNA:
|
||||||
case ESM::REC_ACTC:
|
case ESM::REC_ACTC:
|
||||||
|
case ESM::REC_PROJ:
|
||||||
|
case ESM::REC_MPRJ:
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap);
|
MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap);
|
||||||
break;
|
break;
|
||||||
|
@ -361,7 +363,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
|
||||||
|
|
||||||
ESM::CellId cellId = ptr.getCell()->getCell()->getCellId();
|
ESM::CellId cellId = ptr.getCell()->getCell()->getCellId();
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition());
|
// Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again
|
||||||
|
MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition(), false);
|
||||||
|
|
||||||
|
// Do not trigger erroneous cellChanged events
|
||||||
|
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -169,7 +169,7 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
CellStore::CellStore (const ESM::Cell *cell)
|
CellStore::CellStore (const ESM::Cell *cell)
|
||||||
: mCell (cell), mState (State_Unloaded), mHasState (false)
|
: mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
|
||||||
{
|
{
|
||||||
mWaterLevel = cell->mWater;
|
mWaterLevel = cell->mWater;
|
||||||
}
|
}
|
||||||
|
@ -555,6 +555,7 @@ namespace MWWorld
|
||||||
mWaterLevel = state.mWaterLevel;
|
mWaterLevel = state.mWaterLevel;
|
||||||
|
|
||||||
mWaterLevel = state.mWaterLevel;
|
mWaterLevel = state.mWaterLevel;
|
||||||
|
mLastRespawn = MWWorld::TimeStamp(state.mLastRespawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellStore::saveState (ESM::CellState& state) const
|
void CellStore::saveState (ESM::CellState& state) const
|
||||||
|
@ -566,6 +567,7 @@ namespace MWWorld
|
||||||
|
|
||||||
state.mWaterLevel = mWaterLevel;
|
state.mWaterLevel = mWaterLevel;
|
||||||
state.mHasFogOfWar = (mFogState.get() ? 1 : 0);
|
state.mHasFogOfWar = (mFogState.get() ? 1 : 0);
|
||||||
|
state.mLastRespawn = mLastRespawn.toEsm();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellStore::writeFog(ESM::ESMWriter &writer) const
|
void CellStore::writeFog(ESM::ESMWriter &writer) const
|
||||||
|
@ -754,4 +756,36 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
return mFogState.get();
|
return mFogState.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CellStore::respawn()
|
||||||
|
{
|
||||||
|
if (mState == State_Loaded)
|
||||||
|
{
|
||||||
|
static int iMonthsToRespawn = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iMonthsToRespawn")->getInt();
|
||||||
|
if (MWBase::Environment::get().getWorld()->getTimeStamp() - mLastRespawn > 24*30*iMonthsToRespawn)
|
||||||
|
{
|
||||||
|
mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
|
for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr (&*it, this);
|
||||||
|
ptr.getClass().respawn(ptr);
|
||||||
|
}
|
||||||
|
for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr (&*it, this);
|
||||||
|
ptr.getClass().respawn(ptr);
|
||||||
|
}
|
||||||
|
for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr (&*it, this);
|
||||||
|
ptr.getClass().respawn(ptr);
|
||||||
|
}
|
||||||
|
for (CellRefList<ESM::CreatureLevList>::List::iterator it (mCreatureLists.mList.begin()); it!=mCreatureLists.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr (&*it, this);
|
||||||
|
ptr.getClass().respawn(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld
|
#include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld
|
||||||
|
|
||||||
|
#include "timestamp.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct CellState;
|
struct CellState;
|
||||||
|
@ -48,6 +50,8 @@ namespace MWWorld
|
||||||
std::vector<std::string> mIds;
|
std::vector<std::string> mIds;
|
||||||
float mWaterLevel;
|
float mWaterLevel;
|
||||||
|
|
||||||
|
MWWorld::TimeStamp mLastRespawn;
|
||||||
|
|
||||||
CellRefList<ESM::Activator> mActivators;
|
CellRefList<ESM::Activator> mActivators;
|
||||||
CellRefList<ESM::Potion> mPotions;
|
CellRefList<ESM::Potion> mPotions;
|
||||||
CellRefList<ESM::Apparatus> mAppas;
|
CellRefList<ESM::Apparatus> mAppas;
|
||||||
|
@ -161,6 +165,9 @@ namespace MWWorld
|
||||||
|
|
||||||
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap);
|
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap);
|
||||||
|
|
||||||
|
void respawn ();
|
||||||
|
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
CellRefList<T>& get() {
|
CellRefList<T>& get() {
|
||||||
throw std::runtime_error ("Storage for this type not exist in cells");
|
throw std::runtime_error ("Storage for this type not exist in cells");
|
||||||
|
|
|
@ -341,6 +341,8 @@ namespace MWWorld
|
||||||
virtual int getDoorState (const MWWorld::Ptr &ptr) const;
|
virtual int getDoorState (const MWWorld::Ptr &ptr) const;
|
||||||
/// This does not actually cause the door to move. Use World::activateDoor instead.
|
/// This does not actually cause the door to move. Use World::activateDoor instead.
|
||||||
virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const;
|
virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const;
|
||||||
|
|
||||||
|
virtual void respawn (const MWWorld::Ptr& ptr) const {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
400
apps/openmw/mwworld/projectilemanager.cpp
Normal file
400
apps/openmw/mwworld/projectilemanager.cpp
Normal file
|
@ -0,0 +1,400 @@
|
||||||
|
#include "projectilemanager.hpp"
|
||||||
|
|
||||||
|
#include <OgreSceneManager.h>
|
||||||
|
|
||||||
|
#include <libs/openengine/bullet/physic.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/projectilestate.hpp>
|
||||||
|
|
||||||
|
#include "../mwworld/manualref.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/combat.hpp"
|
||||||
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
|
#include "../mwrender/effectmanager.hpp"
|
||||||
|
|
||||||
|
#include "../mwsound/sound.hpp"
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
|
||||||
|
ProjectileManager::ProjectileManager(Ogre::SceneManager* sceneMgr, OEngine::Physic::PhysicEngine &engine)
|
||||||
|
: mPhysEngine(engine)
|
||||||
|
, mSceneMgr(sceneMgr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileManager::createModel(State &state, const std::string &model)
|
||||||
|
{
|
||||||
|
state.mObject = NifOgre::Loader::createObjects(state.mNode, model);
|
||||||
|
for(size_t i = 0;i < state.mObject->mControllers.size();i++)
|
||||||
|
{
|
||||||
|
if(state.mObject->mControllers[i].getSource().isNull())
|
||||||
|
state.mObject->mControllers[i].setSource(Ogre::SharedPtr<MWRender::EffectAnimationTime> (new MWRender::EffectAnimationTime()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileManager::update(NifOgre::ObjectScenePtr object, float duration)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < object->mControllers.size() ;i++)
|
||||||
|
{
|
||||||
|
MWRender::EffectAnimationTime* value = dynamic_cast<MWRender::EffectAnimationTime*>(object->mControllers[i].getSource().get());
|
||||||
|
if (value)
|
||||||
|
value->addTime(duration);
|
||||||
|
|
||||||
|
object->mControllers[i].update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileManager::launchMagicBolt(const std::string &model, const std::string &sound,
|
||||||
|
const std::string &spellId, float speed, bool stack,
|
||||||
|
const ESM::EffectList &effects, const Ptr &actor, const std::string &sourceName)
|
||||||
|
{
|
||||||
|
// Spawn at 0.75 * ActorHeight
|
||||||
|
float height = mPhysEngine.getCharacter(actor.getRefData().getHandle())->getHalfExtents().z * 2 * 0.75;
|
||||||
|
|
||||||
|
Ogre::Vector3 pos(actor.getRefData().getPosition().pos);
|
||||||
|
pos.z += height;
|
||||||
|
|
||||||
|
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
|
||||||
|
Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
|
||||||
|
|
||||||
|
MagicBoltState state;
|
||||||
|
state.mSourceName = sourceName;
|
||||||
|
state.mId = model;
|
||||||
|
state.mSpellId = spellId;
|
||||||
|
state.mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||||
|
state.mSpeed = speed;
|
||||||
|
state.mStack = stack;
|
||||||
|
state.mSoundId = sound;
|
||||||
|
|
||||||
|
// Only interested in "on target" effects
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
||||||
|
iter!=effects.mList.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (iter->mRange == ESM::RT_Target)
|
||||||
|
state.mEffects.mList.push_back(*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), model);
|
||||||
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
|
||||||
|
state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(pos, orient);
|
||||||
|
createModel(state, ptr.getClass().getModel(ptr));
|
||||||
|
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
state.mSound = sndMgr->playManualSound3D(pos, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
||||||
|
|
||||||
|
mMagicBolts.push_back(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileManager::launchProjectile(Ptr actor, Ptr projectile, const Ogre::Vector3 &pos,
|
||||||
|
const Ogre::Quaternion &orient, Ptr bow, float speed)
|
||||||
|
{
|
||||||
|
ProjectileState state;
|
||||||
|
state.mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||||
|
state.mBowId = bow.getCellRef().mRefID;
|
||||||
|
state.mVelocity = orient.yAxis() * speed;
|
||||||
|
state.mId = projectile.getCellRef().mRefID;
|
||||||
|
|
||||||
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().mRefID);
|
||||||
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
|
||||||
|
state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(pos, orient);
|
||||||
|
createModel(state, ptr.getClass().getModel(ptr));
|
||||||
|
|
||||||
|
mProjectiles.push_back(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileManager::update(float dt)
|
||||||
|
{
|
||||||
|
moveProjectiles(dt);
|
||||||
|
moveMagicBolts(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileManager::moveMagicBolts(float duration)
|
||||||
|
{
|
||||||
|
for (std::vector<MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();)
|
||||||
|
{
|
||||||
|
Ogre::Quaternion orient = it->mNode->getOrientation();
|
||||||
|
static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
|
.find("fTargetSpellMaxSpeed")->getFloat();
|
||||||
|
float speed = fTargetSpellMaxSpeed * it->mSpeed;
|
||||||
|
|
||||||
|
Ogre::Vector3 direction = orient.yAxis();
|
||||||
|
direction.normalise();
|
||||||
|
Ogre::Vector3 pos(it->mNode->getPosition());
|
||||||
|
Ogre::Vector3 newPos = pos + direction * duration * speed;
|
||||||
|
|
||||||
|
it->mSound->setPosition(newPos);
|
||||||
|
|
||||||
|
it->mNode->setPosition(newPos);
|
||||||
|
|
||||||
|
update(it->mObject, duration);
|
||||||
|
|
||||||
|
// Check for impact
|
||||||
|
// TODO: use a proper btRigidBody / btGhostObject?
|
||||||
|
btVector3 from(pos.x, pos.y, pos.z);
|
||||||
|
btVector3 to(newPos.x, newPos.y, newPos.z);
|
||||||
|
std::vector<std::pair<float, std::string> > collisions = mPhysEngine.rayTest2(from, to);
|
||||||
|
bool hit=false;
|
||||||
|
|
||||||
|
for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr obstacle = MWBase::Environment::get().getWorld()->searchPtrViaHandle(cIt->second);
|
||||||
|
|
||||||
|
MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId);
|
||||||
|
if (caster.isEmpty())
|
||||||
|
caster = obstacle;
|
||||||
|
|
||||||
|
if (obstacle.isEmpty())
|
||||||
|
{
|
||||||
|
// Terrain
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MWMechanics::CastSpell cast(caster, obstacle);
|
||||||
|
cast.mHitPosition = pos;
|
||||||
|
cast.mId = it->mSpellId;
|
||||||
|
cast.mSourceName = it->mSourceName;
|
||||||
|
cast.mStack = it->mStack;
|
||||||
|
cast.inflict(obstacle, caster, it->mEffects, ESM::RT_Target, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
if (hit)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId);
|
||||||
|
MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, it->mSpellId, it->mSourceName);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getSoundManager()->stopSound(it->mSound);
|
||||||
|
|
||||||
|
mSceneMgr->destroySceneNode(it->mNode);
|
||||||
|
|
||||||
|
it = mMagicBolts.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileManager::moveProjectiles(float duration)
|
||||||
|
{
|
||||||
|
for (std::vector<ProjectileState>::iterator it = mProjectiles.begin(); it != mProjectiles.end();)
|
||||||
|
{
|
||||||
|
// gravity constant - must be way lower than the gravity affecting actors, since we're not
|
||||||
|
// simulating aerodynamics at all
|
||||||
|
it->mVelocity -= Ogre::Vector3(0, 0, 627.2f * 0.1f) * duration;
|
||||||
|
|
||||||
|
Ogre::Vector3 pos(it->mNode->getPosition());
|
||||||
|
Ogre::Vector3 newPos = pos + it->mVelocity * duration;
|
||||||
|
|
||||||
|
Ogre::Quaternion orient = Ogre::Vector3::UNIT_Y.getRotationTo(it->mVelocity);
|
||||||
|
it->mNode->setOrientation(orient);
|
||||||
|
it->mNode->setPosition(newPos);
|
||||||
|
|
||||||
|
update(it->mObject, duration);
|
||||||
|
|
||||||
|
// Check for impact
|
||||||
|
// TODO: use a proper btRigidBody / btGhostObject?
|
||||||
|
btVector3 from(pos.x, pos.y, pos.z);
|
||||||
|
btVector3 to(newPos.x, newPos.y, newPos.z);
|
||||||
|
std::vector<std::pair<float, std::string> > collisions = mPhysEngine.rayTest2(from, to);
|
||||||
|
bool hit=false;
|
||||||
|
|
||||||
|
for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr obstacle = MWBase::Environment::get().getWorld()->searchPtrViaHandle(cIt->second);
|
||||||
|
|
||||||
|
MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId);
|
||||||
|
|
||||||
|
// Arrow intersects with player immediately after shooting :/
|
||||||
|
if (obstacle == caster)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (obstacle.isEmpty())
|
||||||
|
{
|
||||||
|
// Terrain
|
||||||
|
}
|
||||||
|
else if (obstacle.getClass().isActor())
|
||||||
|
{
|
||||||
|
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId);
|
||||||
|
|
||||||
|
// Try to get a Ptr to the bow that was used. It might no longer exist.
|
||||||
|
MWWorld::Ptr bow = projectileRef.getPtr();
|
||||||
|
if (!caster.isEmpty())
|
||||||
|
{
|
||||||
|
MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster);
|
||||||
|
MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().mRefID, it->mBowId))
|
||||||
|
bow = *invIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caster.isEmpty())
|
||||||
|
caster = obstacle;
|
||||||
|
|
||||||
|
MWMechanics::projectileHit(caster, obstacle, bow, projectileRef.getPtr(), pos + (newPos - pos) * cIt->first);
|
||||||
|
}
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
if (hit)
|
||||||
|
{
|
||||||
|
mSceneMgr->destroySceneNode(it->mNode);
|
||||||
|
|
||||||
|
it = mProjectiles.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileManager::clear()
|
||||||
|
{
|
||||||
|
for (std::vector<ProjectileState>::iterator it = mProjectiles.begin(); it != mProjectiles.end(); ++it)
|
||||||
|
{
|
||||||
|
mSceneMgr->destroySceneNode(it->mNode);
|
||||||
|
}
|
||||||
|
mProjectiles.clear();
|
||||||
|
for (std::vector<MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getSoundManager()->stopSound(it->mSound);
|
||||||
|
mSceneMgr->destroySceneNode(it->mNode);
|
||||||
|
}
|
||||||
|
mMagicBolts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileManager::write(ESM::ESMWriter &writer, Loading::Listener &progress) const
|
||||||
|
{
|
||||||
|
for (std::vector<ProjectileState>::const_iterator it = mProjectiles.begin(); it != mProjectiles.end(); ++it)
|
||||||
|
{
|
||||||
|
writer.startRecord(ESM::REC_PROJ);
|
||||||
|
|
||||||
|
ESM::ProjectileState state;
|
||||||
|
state.mId = it->mId;
|
||||||
|
state.mPosition = it->mNode->getPosition();
|
||||||
|
state.mOrientation = it->mNode->getOrientation();
|
||||||
|
state.mActorId = it->mActorId;
|
||||||
|
|
||||||
|
state.mBowId = it->mBowId;
|
||||||
|
state.mVelocity = it->mVelocity;
|
||||||
|
|
||||||
|
state.save(writer);
|
||||||
|
|
||||||
|
writer.endRecord(ESM::REC_PROJ);
|
||||||
|
|
||||||
|
progress.increaseProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::vector<MagicBoltState>::const_iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it)
|
||||||
|
{
|
||||||
|
writer.startRecord(ESM::REC_MPRJ);
|
||||||
|
|
||||||
|
ESM::MagicBoltState state;
|
||||||
|
state.mId = it->mId;
|
||||||
|
state.mPosition = it->mNode->getPosition();
|
||||||
|
state.mOrientation = it->mNode->getOrientation();
|
||||||
|
state.mActorId = it->mActorId;
|
||||||
|
|
||||||
|
state.mSpellId = it->mSpellId;
|
||||||
|
state.mEffects = it->mEffects;
|
||||||
|
state.mSound = it->mSoundId;
|
||||||
|
state.mSourceName = it->mSourceName;
|
||||||
|
state.mSpeed = it->mSpeed;
|
||||||
|
state.mStack = it->mStack;
|
||||||
|
|
||||||
|
state.save(writer);
|
||||||
|
|
||||||
|
writer.endRecord(ESM::REC_MPRJ);
|
||||||
|
|
||||||
|
progress.increaseProgress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProjectileManager::readRecord(ESM::ESMReader &reader, int32_t type)
|
||||||
|
{
|
||||||
|
if (type == ESM::REC_PROJ)
|
||||||
|
{
|
||||||
|
ESM::ProjectileState esm;
|
||||||
|
esm.load(reader);
|
||||||
|
|
||||||
|
ProjectileState state;
|
||||||
|
state.mActorId = esm.mActorId;
|
||||||
|
state.mBowId = esm.mBowId;
|
||||||
|
state.mVelocity = esm.mVelocity;
|
||||||
|
state.mId = esm.mId;
|
||||||
|
|
||||||
|
std::string model;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId);
|
||||||
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
model = ptr.getClass().getModel(ptr);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(esm.mPosition, esm.mOrientation);
|
||||||
|
createModel(state, model);
|
||||||
|
|
||||||
|
mProjectiles.push_back(state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (type == ESM::REC_MPRJ)
|
||||||
|
{
|
||||||
|
ESM::MagicBoltState esm;
|
||||||
|
esm.load(reader);
|
||||||
|
|
||||||
|
MagicBoltState state;
|
||||||
|
state.mSourceName = esm.mSourceName;
|
||||||
|
state.mId = esm.mId;
|
||||||
|
state.mSpellId = esm.mSpellId;
|
||||||
|
state.mActorId = esm.mActorId;
|
||||||
|
state.mSpeed = esm.mSpeed;
|
||||||
|
state.mStack = esm.mStack;
|
||||||
|
state.mEffects = esm.mEffects;
|
||||||
|
|
||||||
|
std::string model;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId);
|
||||||
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
model = ptr.getClass().getModel(ptr);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(esm.mPosition, esm.mOrientation);
|
||||||
|
createModel(state, model);
|
||||||
|
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f,
|
||||||
|
MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
||||||
|
|
||||||
|
mMagicBolts.push_back(state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ProjectileManager::countSavedGameRecords() const
|
||||||
|
{
|
||||||
|
return mMagicBolts.size() + mProjectiles.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
111
apps/openmw/mwworld/projectilemanager.hpp
Normal file
111
apps/openmw/mwworld/projectilemanager.hpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#ifndef OPENMW_MWWORLD_PROJECTILEMANAGER_H
|
||||||
|
#define OPENMW_MWWORLD_PROJECTILEMANAGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
|
#include <components/esm/effectlist.hpp>
|
||||||
|
#include <components/nifogre/ogrenifloader.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
|
#include "ptr.hpp"
|
||||||
|
|
||||||
|
namespace OEngine
|
||||||
|
{
|
||||||
|
namespace Physic
|
||||||
|
{
|
||||||
|
class PhysicEngine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Loading
|
||||||
|
{
|
||||||
|
class Listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Ogre
|
||||||
|
{
|
||||||
|
class SceneManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
|
||||||
|
class ProjectileManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProjectileManager (Ogre::SceneManager* sceneMgr,
|
||||||
|
OEngine::Physic::PhysicEngine& engine);
|
||||||
|
|
||||||
|
void launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId,
|
||||||
|
float speed, bool stack, const ESM::EffectList& effects,
|
||||||
|
const MWWorld::Ptr& actor, const std::string& sourceName);
|
||||||
|
|
||||||
|
void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
|
||||||
|
const Ogre::Vector3& pos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed);
|
||||||
|
|
||||||
|
void update(float dt);
|
||||||
|
|
||||||
|
/// Removes all current projectiles. Should be called when switching to a new worldspace.
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
|
||||||
|
bool readRecord (ESM::ESMReader& reader, int32_t type);
|
||||||
|
int countSavedGameRecords() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
OEngine::Physic::PhysicEngine& mPhysEngine;
|
||||||
|
Ogre::SceneManager* mSceneMgr;
|
||||||
|
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
NifOgre::ObjectScenePtr mObject;
|
||||||
|
Ogre::SceneNode* mNode;
|
||||||
|
|
||||||
|
// Actor who shot this projectile
|
||||||
|
int mActorId;
|
||||||
|
|
||||||
|
// MW-id of this projectile
|
||||||
|
std::string mId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MagicBoltState : public State
|
||||||
|
{
|
||||||
|
std::string mSpellId;
|
||||||
|
|
||||||
|
// Name of item to display as effect source in magic menu (in case we casted an enchantment)
|
||||||
|
std::string mSourceName;
|
||||||
|
|
||||||
|
ESM::EffectList mEffects;
|
||||||
|
|
||||||
|
float mSpeed;
|
||||||
|
|
||||||
|
bool mStack;
|
||||||
|
|
||||||
|
MWBase::SoundPtr mSound;
|
||||||
|
std::string mSoundId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProjectileState : public State
|
||||||
|
{
|
||||||
|
// RefID of the bow or crossbow the actor was using when this projectile was fired (may be empty)
|
||||||
|
std::string mBowId;
|
||||||
|
|
||||||
|
Ogre::Vector3 mVelocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<MagicBoltState> mMagicBolts;
|
||||||
|
std::vector<ProjectileState> mProjectiles;
|
||||||
|
|
||||||
|
void moveProjectiles(float dt);
|
||||||
|
void moveMagicBolts(float dt);
|
||||||
|
|
||||||
|
void createModel (State& state, const std::string& model);
|
||||||
|
void update (NifOgre::ObjectScenePtr object, float duration);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -165,6 +165,8 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cell->respawn();
|
||||||
|
|
||||||
// ... then references. This is important for adjustPosition to work correctly.
|
// ... then references. This is important for adjustPosition to work correctly.
|
||||||
/// \todo rescale depending on the state of a new GMST
|
/// \todo rescale depending on the state of a new GMST
|
||||||
insertCell (*cell, true, loadingListener);
|
insertCell (*cell, true, loadingListener);
|
||||||
|
@ -344,8 +346,6 @@ namespace MWWorld
|
||||||
// Sky system
|
// Sky system
|
||||||
MWBase::Environment::get().getWorld()->adjustSky();
|
MWBase::Environment::get().getWorld()->adjustSky();
|
||||||
|
|
||||||
mRendering.switchToExterior();
|
|
||||||
|
|
||||||
mCellChanged = true;
|
mCellChanged = true;
|
||||||
|
|
||||||
loadingListener->removeWallpaper();
|
loadingListener->removeWallpaper();
|
||||||
|
@ -439,7 +439,6 @@ namespace MWWorld
|
||||||
mCurrentCell = cell;
|
mCurrentCell = cell;
|
||||||
|
|
||||||
// adjust fog
|
// adjust fog
|
||||||
mRendering.switchToInterior();
|
|
||||||
mRendering.configureFog(*mCurrentCell);
|
mRendering.configureFog(*mCurrentCell);
|
||||||
|
|
||||||
// adjust player
|
// adjust player
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "containerstore.hpp"
|
#include "containerstore.hpp"
|
||||||
#include "inventorystore.hpp"
|
#include "inventorystore.hpp"
|
||||||
#include "actionteleport.hpp"
|
#include "actionteleport.hpp"
|
||||||
|
#include "projectilemanager.hpp"
|
||||||
|
|
||||||
#include "contentloader.hpp"
|
#include "contentloader.hpp"
|
||||||
#include "esmloader.hpp"
|
#include "esmloader.hpp"
|
||||||
|
@ -136,6 +137,8 @@ namespace MWWorld
|
||||||
mPhysics = new PhysicsSystem(renderer);
|
mPhysics = new PhysicsSystem(renderer);
|
||||||
mPhysEngine = mPhysics->getEngine();
|
mPhysEngine = mPhysics->getEngine();
|
||||||
|
|
||||||
|
mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine));
|
||||||
|
|
||||||
mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback);
|
mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback);
|
||||||
|
|
||||||
mPhysEngine->setSceneManager(renderer.getScene());
|
mPhysEngine->setSceneManager(renderer.getScene());
|
||||||
|
@ -234,6 +237,8 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
mRendering->clear();
|
mRendering->clear();
|
||||||
|
|
||||||
|
mProjectileManager->clear();
|
||||||
|
|
||||||
mLocalScripts.clear();
|
mLocalScripts.clear();
|
||||||
mPlayer->clear();
|
mPlayer->clear();
|
||||||
|
|
||||||
|
@ -255,8 +260,6 @@ namespace MWWorld
|
||||||
|
|
||||||
mCells.clear();
|
mCells.clear();
|
||||||
|
|
||||||
mMagicBolts.clear();
|
|
||||||
mProjectiles.clear();
|
|
||||||
mDoorStates.clear();
|
mDoorStates.clear();
|
||||||
|
|
||||||
mGodMode = false;
|
mGodMode = false;
|
||||||
|
@ -274,6 +277,7 @@ namespace MWWorld
|
||||||
mCells.countSavedGameRecords()
|
mCells.countSavedGameRecords()
|
||||||
+mStore.countSavedGameRecords()
|
+mStore.countSavedGameRecords()
|
||||||
+mGlobalVariables.countSavedGameRecords()
|
+mGlobalVariables.countSavedGameRecords()
|
||||||
|
+mProjectileManager->countSavedGameRecords()
|
||||||
+1 // player record
|
+1 // player record
|
||||||
+1 // weather record
|
+1 // weather record
|
||||||
+1; // actorId counter
|
+1; // actorId counter
|
||||||
|
@ -297,6 +301,7 @@ namespace MWWorld
|
||||||
mGlobalVariables.write (writer, progress);
|
mGlobalVariables.write (writer, progress);
|
||||||
mPlayer->write (writer, progress);
|
mPlayer->write (writer, progress);
|
||||||
mWeatherManager->write (writer, progress);
|
mWeatherManager->write (writer, progress);
|
||||||
|
mProjectileManager->write (writer, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::readRecord (ESM::ESMReader& reader, int32_t type,
|
void World::readRecord (ESM::ESMReader& reader, int32_t type,
|
||||||
|
@ -312,7 +317,8 @@ namespace MWWorld
|
||||||
!mGlobalVariables.readRecord (reader, type) &&
|
!mGlobalVariables.readRecord (reader, type) &&
|
||||||
!mPlayer->readRecord (reader, type) &&
|
!mPlayer->readRecord (reader, type) &&
|
||||||
!mWeatherManager->readRecord (reader, type) &&
|
!mWeatherManager->readRecord (reader, type) &&
|
||||||
!mCells.readRecord (reader, type, contentFileMap))
|
!mCells.readRecord (reader, type, contentFileMap) &&
|
||||||
|
!mProjectileManager->readRecord (reader, type))
|
||||||
{
|
{
|
||||||
throw std::runtime_error ("unknown record in saved game");
|
throw std::runtime_error ("unknown record in saved game");
|
||||||
}
|
}
|
||||||
|
@ -807,6 +813,14 @@ namespace MWWorld
|
||||||
|
|
||||||
void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position)
|
void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position)
|
||||||
{
|
{
|
||||||
|
if (mCurrentWorldSpace != cellName)
|
||||||
|
{
|
||||||
|
// changed worldspace
|
||||||
|
mProjectileManager->clear();
|
||||||
|
mRendering->notifyWorldSpaceChanged();
|
||||||
|
mCurrentWorldSpace = cellName;
|
||||||
|
}
|
||||||
|
|
||||||
removeContainerScripts(getPlayerPtr());
|
removeContainerScripts(getPlayerPtr());
|
||||||
mWorldScene->changeToInteriorCell(cellName, position);
|
mWorldScene->changeToInteriorCell(cellName, position);
|
||||||
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
||||||
|
@ -814,13 +828,22 @@ namespace MWWorld
|
||||||
|
|
||||||
void World::changeToExteriorCell (const ESM::Position& position)
|
void World::changeToExteriorCell (const ESM::Position& position)
|
||||||
{
|
{
|
||||||
|
if (mCurrentWorldSpace != "sys::default") // FIXME
|
||||||
|
{
|
||||||
|
// changed worldspace
|
||||||
|
mProjectileManager->clear();
|
||||||
|
mRendering->notifyWorldSpaceChanged();
|
||||||
|
}
|
||||||
removeContainerScripts(getPlayerPtr());
|
removeContainerScripts(getPlayerPtr());
|
||||||
mWorldScene->changeToExteriorCell(position);
|
mWorldScene->changeToExteriorCell(position);
|
||||||
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::changeToCell (const ESM::CellId& cellId, const ESM::Position& position)
|
void World::changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool detectWorldSpaceChange)
|
||||||
{
|
{
|
||||||
|
if (!detectWorldSpaceChange)
|
||||||
|
mCurrentWorldSpace = cellId.mWorldspace;
|
||||||
|
|
||||||
if (cellId.mPaged)
|
if (cellId.mPaged)
|
||||||
changeToExteriorCell (position);
|
changeToExteriorCell (position);
|
||||||
else
|
else
|
||||||
|
@ -949,8 +972,6 @@ namespace MWWorld
|
||||||
MWWorld::Ptr newPtr = MWWorld::Class::get(ptr)
|
MWWorld::Ptr newPtr = MWWorld::Class::get(ptr)
|
||||||
.copyToCell(ptr, *newCell);
|
.copyToCell(ptr, *newCell);
|
||||||
newPtr.getRefData().setBaseNode(0);
|
newPtr.getRefData().setBaseNode(0);
|
||||||
|
|
||||||
objectLeftActiveCell(ptr, newPtr);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1172,8 +1193,7 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
processDoors(duration);
|
processDoors(duration);
|
||||||
|
|
||||||
moveMagicBolts(duration);
|
mProjectileManager->update(duration);
|
||||||
moveProjectiles(duration);
|
|
||||||
|
|
||||||
const PtrVelocityList &results = mPhysics->applyQueuedMovement(duration);
|
const PtrVelocityList &results = mPhysics->applyQueuedMovement(duration);
|
||||||
PtrVelocityList::const_iterator player(results.end());
|
PtrVelocityList::const_iterator player(results.end());
|
||||||
|
@ -1553,9 +1573,9 @@ namespace MWWorld
|
||||||
mRendering->setWaterHeight(height);
|
mRendering->setWaterHeight(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::toggleWater()
|
bool World::toggleWater()
|
||||||
{
|
{
|
||||||
mRendering->toggleWater();
|
return mRendering->toggleWater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::PCDropped (const Ptr& item)
|
void World::PCDropped (const Ptr& item)
|
||||||
|
@ -1567,12 +1587,12 @@ namespace MWWorld
|
||||||
item.getRefData().getLocals().setVarByInt(script, "onpcdrop", 1);
|
item.getRefData().getLocals().setVarByInt(script, "onpcdrop", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount)
|
MWWorld::Ptr World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount)
|
||||||
{
|
{
|
||||||
std::pair<bool, Ogre::Vector3> result = mPhysics->castRay(cursorX, cursorY);
|
std::pair<bool, Ogre::Vector3> result = mPhysics->castRay(cursorX, cursorY);
|
||||||
|
|
||||||
if (!result.first)
|
if (!result.first)
|
||||||
return false;
|
return MWWorld::Ptr();
|
||||||
|
|
||||||
CellStore* cell = getPlayerPtr().getCell();
|
CellStore* cell = getPlayerPtr().getCell();
|
||||||
|
|
||||||
|
@ -1593,7 +1613,7 @@ namespace MWWorld
|
||||||
// only the player place items in the world, so no need to check actor
|
// only the player place items in the world, so no need to check actor
|
||||||
PCDropped(dropped);
|
PCDropped(dropped);
|
||||||
|
|
||||||
return true;
|
return dropped;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::canPlaceObject(float cursorX, float cursorY)
|
bool World::canPlaceObject(float cursorX, float cursorY)
|
||||||
|
@ -1644,7 +1664,7 @@ namespace MWWorld
|
||||||
return dropped;
|
return dropped;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::dropObjectOnGround (const Ptr& actor, const Ptr& object, int amount)
|
MWWorld::Ptr World::dropObjectOnGround (const Ptr& actor, const Ptr& object, int amount)
|
||||||
{
|
{
|
||||||
MWWorld::CellStore* cell = actor.getCell();
|
MWWorld::CellStore* cell = actor.getCell();
|
||||||
|
|
||||||
|
@ -1673,6 +1693,7 @@ namespace MWWorld
|
||||||
|
|
||||||
if(actor == mPlayer->getPlayer()) // Only call if dropped by player
|
if(actor == mPlayer->getPlayer()) // Only call if dropped by player
|
||||||
PCDropped(dropped);
|
PCDropped(dropped);
|
||||||
|
return dropped;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::processChangedSettings(const Settings::CategorySettingVector& settings)
|
void World::processChangedSettings(const Settings::CategorySettingVector& settings)
|
||||||
|
@ -2253,306 +2274,14 @@ namespace MWWorld
|
||||||
void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
|
void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
|
||||||
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed)
|
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed)
|
||||||
{
|
{
|
||||||
ProjectileState state;
|
mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed);
|
||||||
state.mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
|
||||||
state.mBow = bow;
|
|
||||||
state.mVelocity = orient.yAxis() * speed;
|
|
||||||
|
|
||||||
MWWorld::ManualRef ref(getStore(), projectile.getCellRef().mRefID);
|
|
||||||
|
|
||||||
ESM::Position pos;
|
|
||||||
pos.pos[0] = worldPos.x;
|
|
||||||
pos.pos[1] = worldPos.y;
|
|
||||||
pos.pos[2] = worldPos.z;
|
|
||||||
|
|
||||||
// Do NOT copy actor rotation! actors use a different rotation order, and this will not produce the same facing direction.
|
|
||||||
Ogre::Matrix3 mat;
|
|
||||||
orient.ToRotationMatrix(mat);
|
|
||||||
Ogre::Radian xr,yr,zr;
|
|
||||||
mat.ToEulerAnglesXYZ(xr, yr, zr);
|
|
||||||
pos.rot[0] = -xr.valueRadians();
|
|
||||||
pos.rot[1] = -yr.valueRadians();
|
|
||||||
pos.rot[2] = -zr.valueRadians();
|
|
||||||
|
|
||||||
MWWorld::Ptr ptr = copyObjectToCell(ref.getPtr(), actor.getCell(), pos, false);
|
|
||||||
ptr.getRefData().setCount(1);
|
|
||||||
|
|
||||||
mProjectiles[ptr] = state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::launchMagicBolt (const std::string& id, bool stack, const ESM::EffectList& effects,
|
void World::launchMagicBolt (const std::string& model, const std::string &sound, const std::string &spellId,
|
||||||
|
float speed, bool stack, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& actor, const std::string& sourceName)
|
const MWWorld::Ptr& actor, const std::string& sourceName)
|
||||||
{
|
{
|
||||||
std::string projectileModel;
|
mProjectileManager->launchMagicBolt(model, sound, spellId, speed, stack, effects, actor, sourceName);
|
||||||
std::string sound;
|
|
||||||
float speed = 0;
|
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
|
||||||
iter!=effects.mList.end(); ++iter)
|
|
||||||
{
|
|
||||||
if (iter->mRange != ESM::RT_Target)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const ESM::MagicEffect *magicEffect = getStore().get<ESM::MagicEffect>().find (
|
|
||||||
iter->mEffectID);
|
|
||||||
|
|
||||||
projectileModel = magicEffect->mBolt;
|
|
||||||
if (projectileModel.empty())
|
|
||||||
projectileModel = "VFX_DefaultBolt";
|
|
||||||
|
|
||||||
static const std::string schools[] = {
|
|
||||||
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!magicEffect->mBoltSound.empty())
|
|
||||||
sound = magicEffect->mBoltSound;
|
|
||||||
else
|
|
||||||
sound = schools[magicEffect->mData.mSchool] + " bolt";
|
|
||||||
|
|
||||||
speed = magicEffect->mData.mSpeed;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (projectileModel.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Spawn at 0.75 * ActorHeight
|
|
||||||
float height = mPhysEngine->getCharacter(actor.getRefData().getHandle())->getHalfExtents().z * 2 * 0.75;
|
|
||||||
|
|
||||||
MWWorld::ManualRef ref(getStore(), projectileModel);
|
|
||||||
ESM::Position pos;
|
|
||||||
pos.pos[0] = actor.getRefData().getPosition().pos[0];
|
|
||||||
pos.pos[1] = actor.getRefData().getPosition().pos[1];
|
|
||||||
pos.pos[2] = actor.getRefData().getPosition().pos[2] + height;
|
|
||||||
|
|
||||||
// Do NOT copy rotation directly! actors use a different rotation order, and this will not produce the same facing direction.
|
|
||||||
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
|
|
||||||
Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
|
|
||||||
Ogre::Matrix3 mat;
|
|
||||||
orient.ToRotationMatrix(mat);
|
|
||||||
Ogre::Radian xr,yr,zr;
|
|
||||||
mat.ToEulerAnglesXYZ(xr, yr, zr);
|
|
||||||
pos.rot[0] = -xr.valueRadians();
|
|
||||||
pos.rot[1] = -yr.valueRadians();
|
|
||||||
pos.rot[2] = -zr.valueRadians();
|
|
||||||
|
|
||||||
ref.getPtr().getCellRef().mPos = pos;
|
|
||||||
CellStore* cell = actor.getCell();
|
|
||||||
MWWorld::Ptr ptr = copyObjectToCell(ref.getPtr(), cell, pos);
|
|
||||||
|
|
||||||
MagicBoltState state;
|
|
||||||
state.mSourceName = sourceName;
|
|
||||||
state.mId = id;
|
|
||||||
state.mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
|
||||||
state.mSpeed = speed;
|
|
||||||
state.mStack = stack;
|
|
||||||
|
|
||||||
// Only interested in "on target" effects
|
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
|
||||||
iter!=effects.mList.end(); ++iter)
|
|
||||||
{
|
|
||||||
if (iter->mRange == ESM::RT_Target)
|
|
||||||
state.mEffects.mList.push_back(*iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
|
||||||
sndMgr->playSound3D(ptr, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
|
||||||
|
|
||||||
mMagicBolts[ptr] = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::moveProjectiles(float duration)
|
|
||||||
{
|
|
||||||
std::map<std::string, ProjectileState> moved;
|
|
||||||
for (std::map<MWWorld::Ptr, ProjectileState>::iterator it = mProjectiles.begin(); it != mProjectiles.end();)
|
|
||||||
{
|
|
||||||
if (!mWorldScene->isCellActive(*it->first.getCell()))
|
|
||||||
{
|
|
||||||
deleteObject(it->first);
|
|
||||||
mProjectiles.erase(it++);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MWWorld::Ptr ptr = it->first;
|
|
||||||
|
|
||||||
// gravity constant - must be way lower than the gravity affecting actors, since we're not
|
|
||||||
// simulating aerodynamics at all
|
|
||||||
it->second.mVelocity -= Ogre::Vector3(0, 0, 627.2f * 0.1f) * duration;
|
|
||||||
|
|
||||||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
|
||||||
Ogre::Vector3 newPos = pos + it->second.mVelocity * duration;
|
|
||||||
|
|
||||||
Ogre::Quaternion orient = Ogre::Vector3::UNIT_Y.getRotationTo(it->second.mVelocity);
|
|
||||||
Ogre::Matrix3 mat;
|
|
||||||
orient.ToRotationMatrix(mat);
|
|
||||||
Ogre::Radian xr,yr,zr;
|
|
||||||
mat.ToEulerAnglesXYZ(xr, yr, zr);
|
|
||||||
rotateObject(ptr, -xr.valueDegrees(), -yr.valueDegrees(), -zr.valueDegrees());
|
|
||||||
|
|
||||||
// Check for impact
|
|
||||||
btVector3 from(pos.x, pos.y, pos.z);
|
|
||||||
btVector3 to(newPos.x, newPos.y, newPos.z);
|
|
||||||
std::vector<std::pair<float, std::string> > collisions = mPhysEngine->rayTest2(from, to);
|
|
||||||
bool hit=false;
|
|
||||||
|
|
||||||
// HACK: query against the shape as well, since the ray does not take the volume into account
|
|
||||||
// really, this should be a convex cast, but the whole physics system needs a rewrite
|
|
||||||
std::vector<std::string> col2 = mPhysEngine->getCollisions(ptr.getRefData().getHandle());
|
|
||||||
for (std::vector<std::string>::iterator ci = col2.begin(); ci != col2.end(); ++ci)
|
|
||||||
collisions.push_back(std::make_pair(0.f,*ci));
|
|
||||||
|
|
||||||
for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr obstacle = searchPtrViaHandle(cIt->second);
|
|
||||||
if (obstacle == ptr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
MWWorld::Ptr caster = searchPtrViaActorId(it->second.mActorId);
|
|
||||||
|
|
||||||
// Arrow intersects with player immediately after shooting :/
|
|
||||||
if (obstacle == caster)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (caster.isEmpty())
|
|
||||||
caster = obstacle;
|
|
||||||
|
|
||||||
if (obstacle.isEmpty())
|
|
||||||
{
|
|
||||||
// Terrain
|
|
||||||
}
|
|
||||||
else if (obstacle.getClass().isActor())
|
|
||||||
{
|
|
||||||
MWMechanics::projectileHit(caster, obstacle, it->second.mBow, ptr, pos + (newPos - pos) * cIt->first);
|
|
||||||
}
|
|
||||||
hit = true;
|
|
||||||
}
|
|
||||||
if (hit)
|
|
||||||
{
|
|
||||||
deleteObject(ptr);
|
|
||||||
mProjectiles.erase(it++);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string handle = ptr.getRefData().getHandle();
|
|
||||||
|
|
||||||
moveObject(ptr, newPos.x, newPos.y, newPos.z);
|
|
||||||
|
|
||||||
// HACK: Re-fetch Ptrs if necessary, since the cell might have changed
|
|
||||||
if (!ptr.getRefData().getCount())
|
|
||||||
{
|
|
||||||
moved[handle] = it->second;
|
|
||||||
mProjectiles.erase(it++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK: Re-fetch Ptrs if necessary, since the cell might have changed
|
|
||||||
for (std::map<std::string, ProjectileState>::iterator it = moved.begin(); it != moved.end(); ++it)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr newPtr = searchPtrViaHandle(it->first);
|
|
||||||
if (newPtr.isEmpty()) // The projectile went into an inactive cell and was deleted
|
|
||||||
continue;
|
|
||||||
mProjectiles[getPtrViaHandle(it->first)] = it->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::moveMagicBolts(float duration)
|
|
||||||
{
|
|
||||||
std::map<std::string, MagicBoltState> moved;
|
|
||||||
for (std::map<MWWorld::Ptr, MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();)
|
|
||||||
{
|
|
||||||
if (!mWorldScene->isCellActive(*it->first.getCell()))
|
|
||||||
{
|
|
||||||
deleteObject(it->first);
|
|
||||||
mMagicBolts.erase(it++);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MWWorld::Ptr ptr = it->first;
|
|
||||||
|
|
||||||
Ogre::Vector3 rot(ptr.getRefData().getPosition().rot);
|
|
||||||
|
|
||||||
Ogre::Quaternion orient = ptr.getRefData().getBaseNode()->getOrientation();
|
|
||||||
static float fTargetSpellMaxSpeed = getStore().get<ESM::GameSetting>().find("fTargetSpellMaxSpeed")->getFloat();
|
|
||||||
float speed = fTargetSpellMaxSpeed * it->second.mSpeed;
|
|
||||||
|
|
||||||
Ogre::Vector3 direction = orient.yAxis();
|
|
||||||
direction.normalise();
|
|
||||||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
|
||||||
Ogre::Vector3 newPos = pos + direction * duration * speed;
|
|
||||||
|
|
||||||
// Check for impact
|
|
||||||
btVector3 from(pos.x, pos.y, pos.z);
|
|
||||||
btVector3 to(newPos.x, newPos.y, newPos.z);
|
|
||||||
std::vector<std::pair<float, std::string> > collisions = mPhysEngine->rayTest2(from, to);
|
|
||||||
bool explode = false;
|
|
||||||
for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end() && !explode; ++cIt)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr obstacle = searchPtrViaHandle(cIt->second);
|
|
||||||
if (obstacle == ptr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
MWWorld::Ptr caster = searchPtrViaActorId(it->second.mActorId);
|
|
||||||
if (caster.isEmpty())
|
|
||||||
caster = obstacle;
|
|
||||||
|
|
||||||
if (obstacle.isEmpty())
|
|
||||||
{
|
|
||||||
// Terrain
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MWMechanics::CastSpell cast(caster, obstacle);
|
|
||||||
cast.mHitPosition = pos;
|
|
||||||
cast.mId = it->second.mId;
|
|
||||||
cast.mSourceName = it->second.mSourceName;
|
|
||||||
cast.mStack = it->second.mStack;
|
|
||||||
cast.inflict(obstacle, caster, it->second.mEffects, ESM::RT_Target, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
explode = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (explode)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr caster = searchPtrViaActorId(it->second.mActorId);
|
|
||||||
explodeSpell(Ogre::Vector3(ptr.getRefData().getPosition().pos), ptr, it->second.mEffects, caster, it->second.mId, it->second.mSourceName);
|
|
||||||
|
|
||||||
deleteObject(ptr);
|
|
||||||
mMagicBolts.erase(it++);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string handle = ptr.getRefData().getHandle();
|
|
||||||
|
|
||||||
moveObject(ptr, newPos.x, newPos.y, newPos.z);
|
|
||||||
|
|
||||||
// HACK: Re-fetch Ptrs if necessary, since the cell might have changed
|
|
||||||
if (!ptr.getRefData().getCount())
|
|
||||||
{
|
|
||||||
moved[handle] = it->second;
|
|
||||||
mMagicBolts.erase(it++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK: Re-fetch Ptrs if necessary, since the cell might have changed
|
|
||||||
for (std::map<std::string, MagicBoltState>::iterator it = moved.begin(); it != moved.end(); ++it)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr newPtr = searchPtrViaHandle(it->first);
|
|
||||||
if (newPtr.isEmpty()) // The projectile went into an inactive cell and was deleted
|
|
||||||
continue;
|
|
||||||
mMagicBolts[getPtrViaHandle(it->first)] = it->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::objectLeftActiveCell(Ptr object, Ptr movedPtr)
|
|
||||||
{
|
|
||||||
// For now, projectiles moved to an inactive cell are just deleted, because there's no reliable way to hold on to the meta information
|
|
||||||
if (mMagicBolts.find(object) != mMagicBolts.end())
|
|
||||||
deleteObject(movedPtr);
|
|
||||||
if (mProjectiles.find(object) != mProjectiles.end())
|
|
||||||
deleteObject(movedPtr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& World::getContentFiles() const
|
const std::vector<std::string>& World::getContentFiles() const
|
||||||
|
@ -2934,7 +2663,7 @@ namespace MWWorld
|
||||||
mRendering->spawnEffect(model, texture, worldPosition);
|
mRendering->spawnEffect(model, texture, worldPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::explodeSpell(const Vector3 &origin, const MWWorld::Ptr& object, const ESM::EffectList &effects, const Ptr &caster,
|
void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster,
|
||||||
const std::string& id, const std::string& sourceName)
|
const std::string& id, const std::string& sourceName)
|
||||||
{
|
{
|
||||||
std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
|
std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
|
||||||
|
@ -2959,12 +2688,13 @@ namespace MWWorld
|
||||||
static const std::string schools[] = {
|
static const std::string schools[] = {
|
||||||
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||||
};
|
};
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
{
|
||||||
if(!effect->mAreaSound.empty())
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
sndMgr->playSound3D(object, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack);
|
if(!effect->mAreaSound.empty())
|
||||||
else
|
sndMgr->playManualSound3D(origin, effect->mAreaSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack);
|
||||||
sndMgr->playSound3D(object, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack);
|
else
|
||||||
|
sndMgr->playManualSound3D(origin, schools[effect->mData.mSchool]+" area", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoTrack);
|
||||||
|
}
|
||||||
// Get the actors in range of the effect
|
// Get the actors in range of the effect
|
||||||
std::vector<MWWorld::Ptr> objects;
|
std::vector<MWWorld::Ptr> objects;
|
||||||
MWBase::Environment::get().getMechanicsManager()->getObjectsInRange(
|
MWBase::Environment::get().getMechanicsManager()->getObjectsInRange(
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "../mwrender/debugging.hpp"
|
#include "../mwrender/debugging.hpp"
|
||||||
|
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include "ptr.hpp"
|
#include "ptr.hpp"
|
||||||
#include "scene.hpp"
|
#include "scene.hpp"
|
||||||
#include "esmstore.hpp"
|
#include "esmstore.hpp"
|
||||||
|
@ -51,6 +53,7 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
class WeatherManager;
|
class WeatherManager;
|
||||||
class Player;
|
class Player;
|
||||||
|
class ProjectileManager;
|
||||||
|
|
||||||
/// \brief The game world and its visual representation
|
/// \brief The game world and its visual representation
|
||||||
|
|
||||||
|
@ -72,8 +75,12 @@ namespace MWWorld
|
||||||
|
|
||||||
Cells mCells;
|
Cells mCells;
|
||||||
|
|
||||||
|
std::string mCurrentWorldSpace;
|
||||||
|
|
||||||
OEngine::Physic::PhysicEngine* mPhysEngine;
|
OEngine::Physic::PhysicEngine* mPhysEngine;
|
||||||
|
|
||||||
|
boost::shared_ptr<ProjectileManager> mProjectileManager;
|
||||||
|
|
||||||
bool mGodMode;
|
bool mGodMode;
|
||||||
std::vector<std::string> mContentFiles;
|
std::vector<std::string> mContentFiles;
|
||||||
|
|
||||||
|
@ -90,37 +97,6 @@ namespace MWWorld
|
||||||
std::map<MWWorld::Ptr, int> mDoorStates;
|
std::map<MWWorld::Ptr, int> mDoorStates;
|
||||||
///< only holds doors that are currently moving. 1 = opening, 2 = closing
|
///< only holds doors that are currently moving. 1 = opening, 2 = closing
|
||||||
|
|
||||||
struct MagicBoltState
|
|
||||||
{
|
|
||||||
// Id of spell or enchantment to apply when it hits
|
|
||||||
std::string mId;
|
|
||||||
|
|
||||||
// Actor who casted this projectile
|
|
||||||
int mActorId;
|
|
||||||
|
|
||||||
// Name of item to display as effect source in magic menu (in case we casted an enchantment)
|
|
||||||
std::string mSourceName;
|
|
||||||
|
|
||||||
ESM::EffectList mEffects;
|
|
||||||
|
|
||||||
float mSpeed;
|
|
||||||
|
|
||||||
bool mStack;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProjectileState
|
|
||||||
{
|
|
||||||
// Actor who shot this projectile
|
|
||||||
int mActorId;
|
|
||||||
|
|
||||||
MWWorld::Ptr mBow; // bow or crossbow the projectile was fired from
|
|
||||||
|
|
||||||
Ogre::Vector3 mVelocity;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<MWWorld::Ptr, MagicBoltState> mMagicBolts;
|
|
||||||
std::map<MWWorld::Ptr, ProjectileState> mProjectiles;
|
|
||||||
|
|
||||||
std::string mStartCell;
|
std::string mStartCell;
|
||||||
|
|
||||||
void updateWeather(float duration);
|
void updateWeather(float duration);
|
||||||
|
@ -148,9 +124,6 @@ namespace MWWorld
|
||||||
void processDoors(float duration);
|
void processDoors(float duration);
|
||||||
///< Run physics simulation and modify \a world accordingly.
|
///< Run physics simulation and modify \a world accordingly.
|
||||||
|
|
||||||
void moveMagicBolts(float duration);
|
|
||||||
void moveProjectiles(float duration);
|
|
||||||
|
|
||||||
void doPhysics(float duration);
|
void doPhysics(float duration);
|
||||||
///< Run physics simulation and modify \a world accordingly.
|
///< Run physics simulation and modify \a world accordingly.
|
||||||
|
|
||||||
|
@ -171,9 +144,6 @@ namespace MWWorld
|
||||||
bool mLevitationEnabled;
|
bool mLevitationEnabled;
|
||||||
bool mGoToJail;
|
bool mGoToJail;
|
||||||
|
|
||||||
/// Called when \a object is moved to an inactive cell
|
|
||||||
void objectLeftActiveCell (MWWorld::Ptr object, MWWorld::Ptr movedPtr);
|
|
||||||
|
|
||||||
float feetToGameUnits(float feet);
|
float feetToGameUnits(float feet);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -213,7 +183,7 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual void setWaterHeight(const float height);
|
virtual void setWaterHeight(const float height);
|
||||||
|
|
||||||
virtual void toggleWater();
|
virtual bool toggleWater();
|
||||||
|
|
||||||
virtual void adjustSky();
|
virtual void adjustSky();
|
||||||
|
|
||||||
|
@ -343,7 +313,8 @@ namespace MWWorld
|
||||||
virtual void changeToExteriorCell (const ESM::Position& position);
|
virtual void changeToExteriorCell (const ESM::Position& position);
|
||||||
///< Move to exterior cell.
|
///< Move to exterior cell.
|
||||||
|
|
||||||
virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position);
|
virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool detectWorldSpaceChange=true);
|
||||||
|
///< @param detectWorldSpaceChange if true, clean up worldspace-specific data when the world space changes
|
||||||
|
|
||||||
virtual const ESM::Cell *getExterior (const std::string& cellName) const;
|
virtual const ESM::Cell *getExterior (const std::string& cellName) const;
|
||||||
///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
|
///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
|
||||||
|
@ -439,15 +410,14 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual void update (float duration, bool paused);
|
virtual void update (float duration, bool paused);
|
||||||
|
|
||||||
virtual bool placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount);
|
virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount);
|
||||||
///< copy and place an object into the gameworld at the specified cursor position
|
///< copy and place an object into the gameworld at the specified cursor position
|
||||||
/// @param object
|
/// @param object
|
||||||
/// @param cursor X (relative 0-1)
|
/// @param cursor X (relative 0-1)
|
||||||
/// @param cursor Y (relative 0-1)
|
/// @param cursor Y (relative 0-1)
|
||||||
/// @param number of objects to place
|
/// @param number of objects to place
|
||||||
/// @return true if the object was placed, or false if it was rejected because the position is too far away
|
|
||||||
|
|
||||||
virtual void dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount);
|
virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount);
|
||||||
///< copy and place an object into the gameworld at the given actor's position
|
///< copy and place an object into the gameworld at the given actor's position
|
||||||
/// @param actor giving the dropped object position
|
/// @param actor giving the dropped object position
|
||||||
/// @param object
|
/// @param object
|
||||||
|
@ -573,7 +543,8 @@ namespace MWWorld
|
||||||
*/
|
*/
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor);
|
virtual void castSpell (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
virtual void launchMagicBolt (const std::string& id, bool stack, const ESM::EffectList& effects,
|
virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId,
|
||||||
|
float speed, bool stack, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& actor, const std::string& sourceName);
|
const MWWorld::Ptr& actor, const std::string& sourceName);
|
||||||
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
|
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
|
||||||
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed);
|
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed);
|
||||||
|
@ -613,7 +584,7 @@ namespace MWWorld
|
||||||
/// Spawn a blood effect for \a ptr at \a worldPosition
|
/// Spawn a blood effect for \a ptr at \a worldPosition
|
||||||
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition);
|
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition);
|
||||||
|
|
||||||
virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects,
|
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
|
||||||
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName);
|
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ if (GTEST_FOUND AND GMOCK_FOUND)
|
||||||
|
|
||||||
file(GLOB UNITTEST_SRC_FILES
|
file(GLOB UNITTEST_SRC_FILES
|
||||||
components/misc/test_*.cpp
|
components/misc/test_*.cpp
|
||||||
components/file_finder/test_*.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES})
|
source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES})
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include "components/file_finder/file_finder.hpp"
|
|
||||||
|
|
||||||
struct FileFinderTest : public ::testing::Test
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
FileFinderTest()
|
|
||||||
: mTestDir("./filefinder_test_dir/")
|
|
||||||
, mTestFile("test.txt")
|
|
||||||
, mTestFileUppercase("TEST.TXT")
|
|
||||||
, mTestFileNotFound("foobarbaz.txt")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void SetUp()
|
|
||||||
{
|
|
||||||
boost::filesystem::create_directory(boost::filesystem::path(mTestDir));
|
|
||||||
|
|
||||||
std::ofstream ofs(std::string(mTestDir + mTestFile).c_str(), std::ofstream::out);
|
|
||||||
ofs << std::endl;
|
|
||||||
ofs.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void TearDown()
|
|
||||||
{
|
|
||||||
boost::filesystem::remove_all(boost::filesystem::path(mTestDir));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string mTestDir;
|
|
||||||
std::string mTestFile;
|
|
||||||
std::string mTestFileUppercase;
|
|
||||||
std::string mTestFileNotFound;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(FileFinderTest, FileFinder_has_file)
|
|
||||||
{
|
|
||||||
FileFinder::FileFinder fileFinder(mTestDir);
|
|
||||||
ASSERT_TRUE(fileFinder.has(mTestFile));
|
|
||||||
ASSERT_TRUE(fileFinder.has(mTestFileUppercase));
|
|
||||||
ASSERT_TRUE(fileFinder.lookup(mTestFile) == std::string(mTestDir + mTestFile));
|
|
||||||
ASSERT_TRUE(fileFinder.lookup(mTestFileUppercase) == std::string(mTestDir + mTestFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FileFinderTest, FileFinder_does_not_have_file)
|
|
||||||
{
|
|
||||||
FileFinder::FileFinder fileFinder(mTestDir);
|
|
||||||
ASSERT_FALSE(fileFinder.has(mTestFileNotFound));
|
|
||||||
ASSERT_TRUE(fileFinder.lookup(mTestFileNotFound).empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FileFinderTest, FileFinderStrict_has_file)
|
|
||||||
{
|
|
||||||
FileFinder::FileFinderStrict fileFinder(mTestDir);
|
|
||||||
ASSERT_TRUE(fileFinder.has(mTestFile));
|
|
||||||
ASSERT_FALSE(fileFinder.has(mTestFileUppercase));
|
|
||||||
ASSERT_TRUE(fileFinder.lookup(mTestFile) == std::string(mTestDir + mTestFile));
|
|
||||||
ASSERT_FALSE(fileFinder.lookup(mTestFileUppercase) == std::string(mTestDir + mTestFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FileFinderTest, FileFinderStrict_does_not_have_file)
|
|
||||||
{
|
|
||||||
FileFinder::FileFinderStrict fileFinder(mTestDir);
|
|
||||||
ASSERT_FALSE(fileFinder.has(mTestFileNotFound));
|
|
||||||
ASSERT_TRUE(fileFinder.lookup(mTestFileNotFound).empty());
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#include "components/file_finder/search.hpp"
|
|
||||||
|
|
||||||
struct SearchTest : public ::testing::Test
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
SearchTest()
|
|
||||||
: mTestDir("./search_test_dir/")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void SetUp()
|
|
||||||
{
|
|
||||||
boost::filesystem::create_directory(boost::filesystem::path(mTestDir));
|
|
||||||
|
|
||||||
std::ofstream ofs(std::string(mTestDir + "test2.txt").c_str(), std::ofstream::out);
|
|
||||||
ofs << std::endl;
|
|
||||||
ofs.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void TearDown()
|
|
||||||
{
|
|
||||||
boost::filesystem::remove_all(boost::filesystem::path(mTestDir));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string mTestDir;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(SearchTest, file_not_found)
|
|
||||||
{
|
|
||||||
struct Result : public FileFinder::ReturnPath
|
|
||||||
{
|
|
||||||
Result(const boost::filesystem::path& expectedPath)
|
|
||||||
: mExpectedPath(expectedPath)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(const boost::filesystem::path& p)
|
|
||||||
{
|
|
||||||
ASSERT_FALSE(p == mExpectedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::filesystem::path mExpectedPath;
|
|
||||||
|
|
||||||
} r(boost::filesystem::path(mTestDir + "test.txt"));
|
|
||||||
|
|
||||||
FileFinder::find(mTestDir, r, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SearchTest, file_found)
|
|
||||||
{
|
|
||||||
struct Result : public FileFinder::ReturnPath
|
|
||||||
{
|
|
||||||
Result(const boost::filesystem::path& expectedPath)
|
|
||||||
: mExpectedPath(expectedPath)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(const boost::filesystem::path& p)
|
|
||||||
{
|
|
||||||
ASSERT_TRUE(p == mExpectedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::filesystem::path mExpectedPath;
|
|
||||||
|
|
||||||
} r(boost::filesystem::path(mTestDir + "test2.txt"));
|
|
||||||
|
|
||||||
FileFinder::find(mTestDir, r, false);
|
|
||||||
}
|
|
|
@ -34,10 +34,6 @@ add_component_dir (to_utf8
|
||||||
to_utf8
|
to_utf8
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (file_finder
|
|
||||||
file_finder filename_less search
|
|
||||||
)
|
|
||||||
|
|
||||||
add_component_dir (esm
|
add_component_dir (esm
|
||||||
attr defs esmcommon esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell
|
attr defs esmcommon esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell
|
||||||
loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst
|
loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst
|
||||||
|
@ -45,7 +41,7 @@ add_component_dir (esm
|
||||||
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
||||||
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
|
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
|
||||||
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate
|
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate
|
||||||
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate
|
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (misc
|
add_component_dir (misc
|
||||||
|
|
|
@ -11,6 +11,10 @@ void ESM::CellState::load (ESMReader &esm)
|
||||||
|
|
||||||
mHasFogOfWar = false;
|
mHasFogOfWar = false;
|
||||||
esm.getHNOT (mHasFogOfWar, "HFOW");
|
esm.getHNOT (mHasFogOfWar, "HFOW");
|
||||||
|
|
||||||
|
mLastRespawn.mDay = 0;
|
||||||
|
mLastRespawn.mHour = 0;
|
||||||
|
esm.getHNOT (mLastRespawn, "RESP");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESM::CellState::save (ESMWriter &esm) const
|
void ESM::CellState::save (ESMWriter &esm) const
|
||||||
|
@ -18,5 +22,7 @@ void ESM::CellState::save (ESMWriter &esm) const
|
||||||
if (!mId.mPaged)
|
if (!mId.mPaged)
|
||||||
esm.writeHNT ("WLVL", mWaterLevel);
|
esm.writeHNT ("WLVL", mWaterLevel);
|
||||||
|
|
||||||
esm.writeHNT("HFOW", mHasFogOfWar);
|
esm.writeHNT ("HFOW", mHasFogOfWar);
|
||||||
|
|
||||||
|
esm.writeHNT ("RESP", mLastRespawn);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "cellid.hpp"
|
#include "cellid.hpp"
|
||||||
|
|
||||||
|
#include "defs.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
class ESMReader;
|
class ESMReader;
|
||||||
|
@ -19,6 +21,8 @@ namespace ESM
|
||||||
|
|
||||||
int mHasFogOfWar; // Do we have fog of war state (0 or 1)? (see fogstate.hpp)
|
int mHasFogOfWar; // Do we have fog of war state (0 or 1)? (see fogstate.hpp)
|
||||||
|
|
||||||
|
ESM::TimeStamp mLastRespawn;
|
||||||
|
|
||||||
void load (ESMReader &esm);
|
void load (ESMReader &esm);
|
||||||
void save (ESMWriter &esm) const;
|
void save (ESMWriter &esm) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,9 @@ namespace ESM
|
||||||
|
|
||||||
mSpawnActorId = -1;
|
mSpawnActorId = -1;
|
||||||
esm.getHNOT (mSpawnActorId, "SPAW");
|
esm.getHNOT (mSpawnActorId, "SPAW");
|
||||||
|
|
||||||
|
mSpawn = false;
|
||||||
|
esm.getHNOT (mSpawn, "RESP");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureLevListState::save(ESMWriter &esm, bool inInventory) const
|
void CreatureLevListState::save(ESMWriter &esm, bool inInventory) const
|
||||||
|
@ -20,6 +23,9 @@ namespace ESM
|
||||||
|
|
||||||
if (mSpawnActorId != -1)
|
if (mSpawnActorId != -1)
|
||||||
esm.writeHNT ("SPAW", mSpawnActorId);
|
esm.writeHNT ("SPAW", mSpawnActorId);
|
||||||
|
|
||||||
|
if (mSpawn)
|
||||||
|
esm.writeHNT ("RESP", mSpawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace ESM
|
||||||
struct CreatureLevListState : public ObjectState
|
struct CreatureLevListState : public ObjectState
|
||||||
{
|
{
|
||||||
int mSpawnActorId;
|
int mSpawnActorId;
|
||||||
|
bool mSpawn;
|
||||||
|
|
||||||
virtual void load (ESMReader &esm);
|
virtual void load (ESMReader &esm);
|
||||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||||
|
|
|
@ -109,6 +109,8 @@ enum RecNameInts
|
||||||
REC_DYNA = FourCC<'D','Y','N','A'>::value,
|
REC_DYNA = FourCC<'D','Y','N','A'>::value,
|
||||||
REC_ASPL = FourCC<'A','S','P','L'>::value,
|
REC_ASPL = FourCC<'A','S','P','L'>::value,
|
||||||
REC_ACTC = FourCC<'A','C','T','C'>::value,
|
REC_ACTC = FourCC<'A','C','T','C'>::value,
|
||||||
|
REC_MPRJ = FourCC<'M','P','R','J'>::value,
|
||||||
|
REC_PROJ = FourCC<'P','R','O','J'>::value,
|
||||||
|
|
||||||
// format 1
|
// format 1
|
||||||
REC_FILT = 0x544C4946
|
REC_FILT = 0x544C4946
|
||||||
|
|
65
components/esm/projectilestate.cpp
Normal file
65
components/esm/projectilestate.cpp
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#include "projectilestate.hpp"
|
||||||
|
|
||||||
|
#include "esmwriter.hpp"
|
||||||
|
#include "esmreader.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
void BaseProjectileState::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNString ("ID__", mId);
|
||||||
|
esm.writeHNT ("VEC3", mPosition);
|
||||||
|
esm.writeHNT ("QUAT", mOrientation);
|
||||||
|
esm.writeHNT ("ACTO", mActorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseProjectileState::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
mId = esm.getHNString("ID__");
|
||||||
|
esm.getHNT (mPosition, "VEC3");
|
||||||
|
esm.getHNT (mOrientation, "QUAT");
|
||||||
|
esm.getHNT (mActorId, "ACTO");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MagicBoltState::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
BaseProjectileState::save(esm);
|
||||||
|
|
||||||
|
esm.writeHNString ("SPEL", mSpellId);
|
||||||
|
esm.writeHNString ("SRCN", mSourceName);
|
||||||
|
mEffects.save(esm);
|
||||||
|
esm.writeHNT ("SPED", mSpeed);
|
||||||
|
esm.writeHNT ("STCK", mStack);
|
||||||
|
esm.writeHNString ("SOUN", mSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MagicBoltState::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
BaseProjectileState::load(esm);
|
||||||
|
|
||||||
|
mSpellId = esm.getHNString("SPEL");
|
||||||
|
mSourceName = esm.getHNString ("SRCN");
|
||||||
|
mEffects.load(esm);
|
||||||
|
esm.getHNT (mSpeed, "SPED");
|
||||||
|
esm.getHNT (mStack, "STCK");
|
||||||
|
mSound = esm.getHNString ("SOUN");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileState::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
BaseProjectileState::save(esm);
|
||||||
|
|
||||||
|
esm.writeHNString ("BOW_", mBowId);
|
||||||
|
esm.writeHNT ("VEL_", mVelocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectileState::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
BaseProjectileState::load(esm);
|
||||||
|
|
||||||
|
mBowId = esm.getHNString ("BOW_");
|
||||||
|
esm.getHNT (mVelocity, "VEL_");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
90
components/esm/projectilestate.hpp
Normal file
90
components/esm/projectilestate.hpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#ifndef OPENMW_ESM_PROJECTILESTATE_H
|
||||||
|
#define OPENMW_ESM_PROJECTILESTATE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
#include <OgreQuaternion.h>
|
||||||
|
|
||||||
|
#include "effectlist.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
|
||||||
|
// format 0, savegames only
|
||||||
|
|
||||||
|
struct Quaternion
|
||||||
|
{
|
||||||
|
float mValues[4];
|
||||||
|
|
||||||
|
Quaternion() {}
|
||||||
|
Quaternion (Ogre::Quaternion q)
|
||||||
|
{
|
||||||
|
mValues[0] = q.w;
|
||||||
|
mValues[1] = q.x;
|
||||||
|
mValues[2] = q.y;
|
||||||
|
mValues[3] = q.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator Ogre::Quaternion () const
|
||||||
|
{
|
||||||
|
return Ogre::Quaternion(mValues[0], mValues[1], mValues[2], mValues[3]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vector3
|
||||||
|
{
|
||||||
|
float mValues[3];
|
||||||
|
|
||||||
|
Vector3() {}
|
||||||
|
Vector3 (Ogre::Vector3 v)
|
||||||
|
{
|
||||||
|
mValues[0] = v.x;
|
||||||
|
mValues[1] = v.y;
|
||||||
|
mValues[2] = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator Ogre::Vector3 () const
|
||||||
|
{
|
||||||
|
return Ogre::Vector3(&mValues[0]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BaseProjectileState
|
||||||
|
{
|
||||||
|
std::string mId;
|
||||||
|
|
||||||
|
Vector3 mPosition;
|
||||||
|
Quaternion mOrientation;
|
||||||
|
|
||||||
|
int mActorId;
|
||||||
|
|
||||||
|
void load (ESMReader &esm);
|
||||||
|
void save (ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MagicBoltState : public BaseProjectileState
|
||||||
|
{
|
||||||
|
std::string mSpellId;
|
||||||
|
std::string mSourceName;
|
||||||
|
ESM::EffectList mEffects;
|
||||||
|
float mSpeed;
|
||||||
|
bool mStack;
|
||||||
|
std::string mSound;
|
||||||
|
|
||||||
|
void load (ESMReader &esm);
|
||||||
|
void save (ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProjectileState : public BaseProjectileState
|
||||||
|
{
|
||||||
|
std::string mBowId;
|
||||||
|
Vector3 mVelocity;
|
||||||
|
|
||||||
|
void load (ESMReader &esm);
|
||||||
|
void save (ESMWriter &esm) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,142 +0,0 @@
|
||||||
#ifndef FILE_FINDER_MAIN_H
|
|
||||||
#define FILE_FINDER_MAIN_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "search.hpp"
|
|
||||||
#include "filename_less.hpp"
|
|
||||||
#include <components/files/multidircollection.hpp>
|
|
||||||
|
|
||||||
namespace FileFinder
|
|
||||||
{
|
|
||||||
|
|
||||||
template <typename LESS>
|
|
||||||
class FileFinderT
|
|
||||||
{
|
|
||||||
typedef std::map<std::string, std::string, LESS> TableContainer;
|
|
||||||
TableContainer table;
|
|
||||||
|
|
||||||
struct Inserter : ReturnPath
|
|
||||||
{
|
|
||||||
FileFinderT<LESS> *owner;
|
|
||||||
int cut;
|
|
||||||
|
|
||||||
void add(const boost::filesystem::path &pth)
|
|
||||||
{
|
|
||||||
std::string file = pth.string();
|
|
||||||
std::string key = file.substr(cut);
|
|
||||||
owner->table[key] = file;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Inserter inserter;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FileFinderT(const boost::filesystem::path &path, bool recurse=true)
|
|
||||||
{
|
|
||||||
inserter.owner = this;
|
|
||||||
|
|
||||||
// Remember the original path length, so we can cut it away from
|
|
||||||
// the relative paths used as keys
|
|
||||||
const std::string& pstring = path.string();
|
|
||||||
inserter.cut = pstring.size();
|
|
||||||
|
|
||||||
// If the path does not end in a slash, then boost will add one
|
|
||||||
// later, which means one more character we have to remove.
|
|
||||||
char last = *pstring.rbegin();
|
|
||||||
if(last != '\\' && last != '/')
|
|
||||||
inserter.cut++;
|
|
||||||
|
|
||||||
// Fill the map
|
|
||||||
find(path, inserter, recurse);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has(const std::string& file) const
|
|
||||||
{
|
|
||||||
return table.find(file) != table.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the full path from a relative path.
|
|
||||||
const std::string &lookup(const std::string& file) const
|
|
||||||
{
|
|
||||||
static std::string empty;
|
|
||||||
typename TableContainer::const_iterator it = table.find(file);
|
|
||||||
return (it != table.end()) ? it->second : empty;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template
|
|
||||||
<
|
|
||||||
class LESS
|
|
||||||
>
|
|
||||||
struct TreeFileFinder
|
|
||||||
{
|
|
||||||
typedef TreeFileFinder<LESS> finder_t;
|
|
||||||
|
|
||||||
TreeFileFinder(const Files::PathContainer& paths, bool recurse = true)
|
|
||||||
{
|
|
||||||
struct : ReturnPath
|
|
||||||
{
|
|
||||||
finder_t *owner;
|
|
||||||
int cut;
|
|
||||||
|
|
||||||
void add(const boost::filesystem::path &pth)
|
|
||||||
{
|
|
||||||
std::string file = pth.string();
|
|
||||||
std::string key = file.substr(cut);
|
|
||||||
owner->mTable[key] = file;
|
|
||||||
}
|
|
||||||
} inserter;
|
|
||||||
|
|
||||||
inserter.owner = this;
|
|
||||||
|
|
||||||
for (Files::PathContainer::const_iterator it = paths.begin(); it != paths.end(); ++it)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Remember the original path length, so we can cut it away from
|
|
||||||
// the relative paths used as keys
|
|
||||||
const std::string& pstring = it->string();
|
|
||||||
inserter.cut = pstring.size();
|
|
||||||
|
|
||||||
// If the path does not end in a slash, then boost will add one
|
|
||||||
// later, which means one more character we have to remove.
|
|
||||||
char last = *pstring.rbegin();
|
|
||||||
if (last != '\\' && last != '/')
|
|
||||||
{
|
|
||||||
inserter.cut++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the map
|
|
||||||
find(*it, inserter, recurse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has(const std::string& file) const
|
|
||||||
{
|
|
||||||
return mTable.find(file) != mTable.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& lookup(const std::string& file) const
|
|
||||||
{
|
|
||||||
static std::string empty;
|
|
||||||
typename TableContainer::const_iterator it = mTable.find(file);
|
|
||||||
return (it != mTable.end()) ? it->second : empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef std::map<std::string, std::string, LESS> TableContainer;
|
|
||||||
TableContainer mTable;
|
|
||||||
|
|
||||||
// Inserter inserter;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// The default is to use path_less for equality checks
|
|
||||||
typedef FileFinderT<path_less> FileFinder;
|
|
||||||
typedef FileFinderT<path_slash> FileFinderStrict;
|
|
||||||
|
|
||||||
typedef TreeFileFinder<path_less> LessTreeFileFinder;
|
|
||||||
typedef TreeFileFinder<path_slash> StrictTreeFileFinder;
|
|
||||||
|
|
||||||
} /* namespace FileFinder */
|
|
||||||
#endif /* FILE_FINDER_MAIN_H */
|
|
|
@ -1,84 +0,0 @@
|
||||||
#ifndef FILE_FINDER_LESS_H
|
|
||||||
#define FILE_FINDER_LESS_H
|
|
||||||
|
|
||||||
#include <libs/platform/strings.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace FileFinder{
|
|
||||||
|
|
||||||
// Used for maps of file paths. Compares file paths, but ignores case
|
|
||||||
// AND treats \ and / as the same character.
|
|
||||||
struct path_less
|
|
||||||
{
|
|
||||||
int compareChar(char a, char b) const
|
|
||||||
{
|
|
||||||
if(a>b) return 1;
|
|
||||||
else if(a<b) return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int comparePathChar(char a, char b) const
|
|
||||||
{
|
|
||||||
if(a >= 'a' && a <= 'z') a += 'A'-'a';
|
|
||||||
else if(a == '\\') a = '/';
|
|
||||||
if(b >= 'a' && b <= 'z') b += 'A'-'a';
|
|
||||||
else if(b == '\\') b = '/';
|
|
||||||
return compareChar(a,b);
|
|
||||||
}
|
|
||||||
|
|
||||||
int compareString(const char *a, const char *b) const
|
|
||||||
{
|
|
||||||
while(*a && *b)
|
|
||||||
{
|
|
||||||
int i = comparePathChar(*a,*b);
|
|
||||||
if(i != 0) return i;
|
|
||||||
a++; b++;
|
|
||||||
}
|
|
||||||
// At this point, one or both of the chars is a null terminator.
|
|
||||||
// Normal char comparison will get the correct final result here.
|
|
||||||
return compareChar(*a,*b);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator() (const std::string& a, const std::string& b) const
|
|
||||||
{
|
|
||||||
return compareString(a.c_str(), b.c_str()) < 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct path_slash
|
|
||||||
{
|
|
||||||
int compareChar(char a, char b) const
|
|
||||||
{
|
|
||||||
if(a>b) return 1;
|
|
||||||
else if(a<b) return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int comparePathChar(char a, char b) const
|
|
||||||
{
|
|
||||||
if(a == '\\') a = '/';
|
|
||||||
if(b == '\\') b = '/';
|
|
||||||
return compareChar(a,b);
|
|
||||||
}
|
|
||||||
|
|
||||||
int compareString(const char *a, const char *b) const
|
|
||||||
{
|
|
||||||
while(*a && *b)
|
|
||||||
{
|
|
||||||
int i = comparePathChar(*a,*b);
|
|
||||||
if(i != 0) return i;
|
|
||||||
a++; b++;
|
|
||||||
}
|
|
||||||
// At this point, one or both of the chars is a null terminator.
|
|
||||||
// Normal char comparison will get the correct final result here.
|
|
||||||
return compareChar(*a,*b);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator() (const std::string& a, const std::string& b) const
|
|
||||||
{
|
|
||||||
return compareString(a.c_str(), b.c_str()) < 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,36 +0,0 @@
|
||||||
#include "search.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
void FileFinder::find(const boost::filesystem::path & dir_path, ReturnPath &ret, bool recurse)
|
|
||||||
{
|
|
||||||
if (boost::filesystem::exists(dir_path))
|
|
||||||
{
|
|
||||||
if (!recurse)
|
|
||||||
{
|
|
||||||
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
|
|
||||||
for (boost::filesystem::directory_iterator itr(dir_path); itr != end_itr; ++itr)
|
|
||||||
{
|
|
||||||
if (!boost::filesystem::is_directory( *itr ))
|
|
||||||
{
|
|
||||||
ret.add(*itr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
boost::filesystem::recursive_directory_iterator end_itr; // default construction yields past-the-end
|
|
||||||
for (boost::filesystem::recursive_directory_iterator itr(dir_path); itr != end_itr; ++itr)
|
|
||||||
{
|
|
||||||
if (!boost::filesystem::is_directory(*itr))
|
|
||||||
{
|
|
||||||
ret.add(*itr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout << "Path " << dir_path << " not found" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#ifndef FILE_FINDER_SEARCH_H
|
|
||||||
#define FILE_FINDER_SEARCH_H
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace FileFinder
|
|
||||||
{
|
|
||||||
struct ReturnPath
|
|
||||||
{
|
|
||||||
virtual void add(const boost::filesystem::path &pth) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Search the given path and return all file paths through 'ret'. If
|
|
||||||
recurse==true, all files in subdirectories are returned as well.
|
|
||||||
*/
|
|
||||||
void find(const boost::filesystem::path & dir_path, ReturnPath &ret, bool recurse=true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -33,6 +33,7 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="MWScrollBar" skin="MW_HScroll" position="122 20 210 13" name="MagnitudeMinSlider">
|
<Widget type="MWScrollBar" skin="MW_HScroll" position="122 20 210 13" name="MagnitudeMinSlider">
|
||||||
<Property key="Range" value="100"/>
|
<Property key="Range" value="100"/>
|
||||||
|
<Property key="Page" value="1"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
<Widget type="TextBox" skin="SandText" position="122 32 210 20" name="MagnitudeMaxValue">
|
<Widget type="TextBox" skin="SandText" position="122 32 210 20" name="MagnitudeMaxValue">
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="MWScrollBar" skin="MW_HScroll" position="122 52 210 13" name="MagnitudeMaxSlider">
|
<Widget type="MWScrollBar" skin="MW_HScroll" position="122 52 210 13" name="MagnitudeMaxSlider">
|
||||||
<Property key="Range" value="100"/>
|
<Property key="Range" value="100"/>
|
||||||
|
<Property key="Page" value="1"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
|
@ -58,6 +60,7 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="MWScrollBar" skin="MW_HScroll" position="122 20 210 13" name="DurationSlider">
|
<Widget type="MWScrollBar" skin="MW_HScroll" position="122 20 210 13" name="DurationSlider">
|
||||||
<Property key="Range" value="1440"/>
|
<Property key="Range" value="1440"/>
|
||||||
|
<Property key="Page" value="1"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
|
@ -74,6 +77,7 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="MWScrollBar" skin="MW_HScroll" position="122 20 210 13" name="AreaSlider">
|
<Widget type="MWScrollBar" skin="MW_HScroll" position="122 20 210 13" name="AreaSlider">
|
||||||
<Property key="Range" value="51"/>
|
<Property key="Range" value="51"/>
|
||||||
|
<Property key="Page" value="1"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue