forked from mirror/openmw-tes3mp
Merge remote-tracking branch 'scrawl/master'
This commit is contained in:
commit
3b2ba4f6cd
69 changed files with 897 additions and 277 deletions
|
@ -200,6 +200,9 @@ namespace MWBase
|
|||
virtual MWWorld::Ptr searchPtrViaHandle (const std::string& handle) = 0;
|
||||
///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found
|
||||
|
||||
virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0;
|
||||
///< Search is limited to the active cells.
|
||||
|
||||
/// \todo enable reference in the OGRE scene
|
||||
virtual void enable (const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
|
@ -390,14 +393,10 @@ namespace MWBase
|
|||
virtual void setupPlayer() = 0;
|
||||
virtual void renderPlayer() = 0;
|
||||
|
||||
/// if activated, should this door be opened or closed?
|
||||
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door) = 0;
|
||||
|
||||
/// activate (open or close) an non-teleport door
|
||||
/// open or close a non-teleport door (depending on current state)
|
||||
virtual void activateDoor(const MWWorld::Ptr& door) = 0;
|
||||
|
||||
/// Is door currently opening/closing?
|
||||
virtual bool getIsMovingDoor(const MWWorld::Ptr& door) = 0;
|
||||
/// open or close a non-teleport door as specified
|
||||
virtual void activateDoor(const MWWorld::Ptr& door, bool open) = 0;
|
||||
|
||||
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object
|
||||
virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
|
||||
|
|
|
@ -164,7 +164,11 @@ namespace MWClass
|
|||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty())
|
||||
{
|
||||
physics.addActor(ptr);
|
||||
if (getCreatureStats(ptr).isDead())
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false);
|
||||
}
|
||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "creaturelevlist.hpp"
|
||||
|
||||
#include <components/esm/loadlevlist.hpp>
|
||||
#include <components/esm/creaturelevliststate.hpp>
|
||||
|
||||
#include "../mwmechanics/levelledlist.hpp"
|
||||
|
||||
|
@ -11,7 +12,9 @@ namespace
|
|||
{
|
||||
struct CreatureLevListCustomData : public MWWorld::CustomData
|
||||
{
|
||||
// TODO: save the creature we spawned here
|
||||
// actorId of the creature we spawned
|
||||
int mSpawnActorId;
|
||||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
|
||||
|
@ -38,6 +41,25 @@ namespace MWClass
|
|||
void CreatureLevList::insertObjectRendering(const MWWorld::Ptr &ptr, MWRender::RenderingInterface &renderingInterface) const
|
||||
{
|
||||
ensureCustomData(ptr);
|
||||
|
||||
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
||||
if (customData.mSpawnActorId != -1)
|
||||
return; // TODO: handle respawning
|
||||
|
||||
|
||||
MWWorld::LiveCellRef<ESM::CreatureLevList> *ref =
|
||||
ptr.get<ESM::CreatureLevList>();
|
||||
|
||||
std::string id = MWMechanics::getLevelledItem(ref->mBase, true);
|
||||
|
||||
if (!id.empty())
|
||||
{
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
MWWorld::ManualRef ref(store, id);
|
||||
ref.getPtr().getCellRef().mPos = 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();
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureLevList::ensureCustomData(const MWWorld::Ptr &ptr) const
|
||||
|
@ -45,22 +67,29 @@ namespace MWClass
|
|||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<CreatureLevListCustomData> data (new CreatureLevListCustomData);
|
||||
|
||||
MWWorld::LiveCellRef<ESM::CreatureLevList> *ref =
|
||||
ptr.get<ESM::CreatureLevList>();
|
||||
|
||||
std::string id = MWMechanics::getLevelledItem(ref->mBase, true);
|
||||
|
||||
if (!id.empty())
|
||||
{
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
MWWorld::ManualRef ref(store, id);
|
||||
ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos;
|
||||
// TODO: hold on to this for respawn purposes later
|
||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().mPos);
|
||||
}
|
||||
data->mSpawnActorId = -1;
|
||||
|
||||
ptr.getRefData().setCustomData(data.release());
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureLevList::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::CreatureLevListState& state2 = dynamic_cast<const ESM::CreatureLevListState&> (state);
|
||||
|
||||
ensureCustomData(ptr);
|
||||
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
||||
customData.mSpawnActorId = state2.mSpawnActorId;
|
||||
}
|
||||
|
||||
void CreatureLevList::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::CreatureLevListState& state2 = dynamic_cast<ESM::CreatureLevListState&> (state);
|
||||
|
||||
ensureCustomData(ptr);
|
||||
CreatureLevListCustomData& customData = dynamic_cast<CreatureLevListCustomData&> (*ptr.getRefData().getCustomData());
|
||||
state2.mSpawnActorId = customData.mSpawnActorId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,14 @@ namespace MWClass
|
|||
|
||||
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
|
||||
///< Add reference into a cell for rendering
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "door.hpp"
|
||||
|
||||
#include <components/esm/loaddoor.hpp>
|
||||
#include <components/esm/doorstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -17,12 +18,28 @@
|
|||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/actiontrap.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct DoorCustomData : public MWWorld::CustomData
|
||||
{
|
||||
int mDoorState; // 0 = nothing, 1 = opening, 2 = closing
|
||||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
|
||||
MWWorld::CustomData *DoorCustomData::clone() const
|
||||
{
|
||||
return new DoorCustomData (*this);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
void Door::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||
|
@ -38,6 +55,14 @@ namespace MWClass
|
|||
const std::string model = getModel(ptr);
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
|
||||
// Resume the door's opening/closing animation if it wasn't finished
|
||||
ensureCustomData(ptr);
|
||||
const DoorCustomData& customData = dynamic_cast<const DoorCustomData&>(*ptr.getRefData().getCustomData());
|
||||
if (customData.mDoorState > 0)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState == 1 ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Door::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
@ -125,7 +150,14 @@ namespace MWClass
|
|||
{
|
||||
// animated door
|
||||
boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionDoor(ptr));
|
||||
if (MWBase::Environment::get().getWorld()->getOpenOrCloseDoor(ptr))
|
||||
int doorstate = getDoorState(ptr);
|
||||
bool opening = true;
|
||||
if (doorstate == 1)
|
||||
opening = false;
|
||||
if (doorstate == 0 && ptr.getRefData().getLocalRotation().rot[2] != 0)
|
||||
opening = false;
|
||||
|
||||
if (opening)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr,
|
||||
closeSound, 0.5);
|
||||
|
@ -262,4 +294,48 @@ namespace MWClass
|
|||
|
||||
return MWWorld::Ptr(&cell.get<ESM::Door>().insert(*ref), &cell);
|
||||
}
|
||||
|
||||
void Door::ensureCustomData(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<DoorCustomData> data(new DoorCustomData);
|
||||
|
||||
data->mDoorState = 0;
|
||||
ptr.getRefData().setCustomData(data.release());
|
||||
}
|
||||
}
|
||||
|
||||
int Door::getDoorState (const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
ensureCustomData(ptr);
|
||||
const DoorCustomData& customData = dynamic_cast<const DoorCustomData&>(*ptr.getRefData().getCustomData());
|
||||
return customData.mDoorState;
|
||||
}
|
||||
|
||||
void Door::setDoorState (const MWWorld::Ptr &ptr, int state) const
|
||||
{
|
||||
ensureCustomData(ptr);
|
||||
DoorCustomData& customData = dynamic_cast<DoorCustomData&>(*ptr.getRefData().getCustomData());
|
||||
customData.mDoorState = state;
|
||||
}
|
||||
|
||||
void Door::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const
|
||||
{
|
||||
ensureCustomData(ptr);
|
||||
DoorCustomData& customData = dynamic_cast<DoorCustomData&>(*ptr.getRefData().getCustomData());
|
||||
|
||||
const ESM::DoorState& state2 = dynamic_cast<const ESM::DoorState&>(state);
|
||||
customData.mDoorState = state2.mDoorState;
|
||||
}
|
||||
|
||||
void Door::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const
|
||||
{
|
||||
ensureCustomData(ptr);
|
||||
const DoorCustomData& customData = dynamic_cast<const DoorCustomData&>(*ptr.getRefData().getCustomData());
|
||||
|
||||
ESM::DoorState& state2 = dynamic_cast<ESM::DoorState&>(state);
|
||||
state2.mDoorState = customData.mDoorState;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ namespace MWClass
|
|||
{
|
||||
class Door : public MWWorld::Class
|
||||
{
|
||||
void ensureCustomData (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual MWWorld::Ptr
|
||||
copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const;
|
||||
|
||||
|
@ -48,7 +50,20 @@ namespace MWClass
|
|||
static void registerSelf();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
private:
|
||||
|
||||
/// 0 = nothing, 1 = opening, 2 = closing
|
||||
virtual int getDoorState (const MWWorld::Ptr &ptr) const;
|
||||
/// 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 readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -388,6 +388,8 @@ namespace MWClass
|
|||
{
|
||||
physics.addActor(ptr);
|
||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||
if (getCreatureStats(ptr).isDead())
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false);
|
||||
}
|
||||
|
||||
bool Npc::isPersistent(const MWWorld::Ptr &actor) const
|
||||
|
@ -618,7 +620,8 @@ namespace MWClass
|
|||
// NOTE: 'object' and/or 'attacker' may be empty.
|
||||
|
||||
// Attacking peaceful NPCs is a crime
|
||||
if (!attacker.isEmpty() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() <= 30)
|
||||
// anything below 80 is considered peaceful (see Actors::updateActor)
|
||||
if (!attacker.isEmpty() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80)
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
|
||||
|
||||
getCreatureStats(ptr).setAttacked(true);
|
||||
|
|
|
@ -10,23 +10,23 @@ namespace MWGui
|
|||
{
|
||||
}
|
||||
|
||||
void CompanionItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner=false)
|
||||
MWWorld::Ptr CompanionItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner=false)
|
||||
{
|
||||
if (mActor.getClass().isNpc())
|
||||
{
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
|
||||
stats.modifyProfit(MWWorld::Class::get(item.mBase).getValue(item.mBase) * count);
|
||||
MWMechanics::NpcStats& stats = mActor.getClass().getNpcStats(mActor);
|
||||
stats.modifyProfit(item.mBase.getClass().getValue(item.mBase) * count);
|
||||
}
|
||||
|
||||
InventoryItemModel::copyItem(item, count, setNewOwner);
|
||||
return InventoryItemModel::copyItem(item, count, setNewOwner);
|
||||
}
|
||||
|
||||
void CompanionItemModel::removeItem (const ItemStack& item, size_t count)
|
||||
{
|
||||
if (mActor.getClass().isNpc())
|
||||
{
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
|
||||
stats.modifyProfit(-MWWorld::Class::get(item.mBase).getValue(item.mBase) * count);
|
||||
MWMechanics::NpcStats& stats = mActor.getClass().getNpcStats(mActor);
|
||||
stats.modifyProfit(-item.mBase.getClass().getValue(item.mBase) * count);
|
||||
}
|
||||
|
||||
InventoryItemModel::removeItem(item, count);
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace MWGui
|
|||
public:
|
||||
CompanionItemModel (const MWWorld::Ptr& actor);
|
||||
|
||||
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner);
|
||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner);
|
||||
virtual void removeItem (const ItemStack& item, size_t count);
|
||||
};
|
||||
|
||||
|
|
|
@ -71,12 +71,12 @@ ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item)
|
|||
return -1;
|
||||
}
|
||||
|
||||
void ContainerItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
|
||||
MWWorld::Ptr ContainerItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
|
||||
{
|
||||
const MWWorld::Ptr& source = mItemSources[mItemSources.size()-1];
|
||||
if (item.mBase.getContainerStore() == &source.getClass().getContainerStore(source))
|
||||
throw std::runtime_error("Item to copy needs to be from a different container!");
|
||||
source.getClass().getContainerStore(source).add(item.mBase, count, source);
|
||||
return *source.getClass().getContainerStore(source).add(item.mBase, count, source);
|
||||
}
|
||||
|
||||
void ContainerItemModel::removeItem (const ItemStack& item, size_t count)
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace MWGui
|
|||
virtual ModelIndex getIndex (ItemStack item);
|
||||
virtual size_t getItemCount();
|
||||
|
||||
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
|
||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
|
||||
virtual void removeItem (const ItemStack& item, size_t count);
|
||||
|
||||
virtual void update();
|
||||
|
|
|
@ -40,11 +40,11 @@ ItemModel::ModelIndex InventoryItemModel::getIndex (ItemStack item)
|
|||
return -1;
|
||||
}
|
||||
|
||||
void InventoryItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
|
||||
MWWorld::Ptr InventoryItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
|
||||
{
|
||||
if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor))
|
||||
throw std::runtime_error("Item to copy needs to be from a different container!");
|
||||
mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor, setNewOwner);
|
||||
return *mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor, setNewOwner);
|
||||
}
|
||||
|
||||
|
||||
|
@ -59,16 +59,20 @@ void InventoryItemModel::removeItem (const ItemStack& item, size_t count)
|
|||
throw std::runtime_error("Not enough items in the stack to remove");
|
||||
}
|
||||
|
||||
void InventoryItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel)
|
||||
MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel)
|
||||
{
|
||||
bool setNewOwner = false;
|
||||
|
||||
// Are you dead? Then you wont need that anymore
|
||||
if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead())
|
||||
if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()
|
||||
// Make sure that the item is actually owned by the dead actor
|
||||
// Prevents a potential exploit for resetting the owner of any item, by placing the item in a corpse
|
||||
&& Misc::StringUtils::ciEqual(item.mBase.getCellRef().mOwner, mActor.getCellRef().mRefID))
|
||||
setNewOwner = true;
|
||||
|
||||
otherModel->copyItem(item, count, setNewOwner);
|
||||
MWWorld::Ptr ret = otherModel->copyItem(item, count, setNewOwner);
|
||||
removeItem(item, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void InventoryItemModel::update()
|
||||
|
|
|
@ -15,11 +15,11 @@ namespace MWGui
|
|||
virtual ModelIndex getIndex (ItemStack item);
|
||||
virtual size_t getItemCount();
|
||||
|
||||
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
|
||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
|
||||
virtual void removeItem (const ItemStack& item, size_t count);
|
||||
|
||||
/// Move items from this model to \a otherModel.
|
||||
virtual void moveItem (const ItemStack& item, size_t count, ItemModel* otherModel);
|
||||
virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel);
|
||||
|
||||
virtual void update();
|
||||
|
||||
|
|
|
@ -408,14 +408,8 @@ namespace MWGui
|
|||
|
||||
if (mDragAndDrop->mSourceModel != mTradeModel)
|
||||
{
|
||||
// add item to the player's inventory
|
||||
MWWorld::ContainerStore& invStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
|
||||
MWWorld::ContainerStoreIterator it = invStore.begin();
|
||||
|
||||
it = invStore.add(ptr, mDragAndDrop->mDraggedCount, mPtr);
|
||||
|
||||
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
|
||||
ptr = *it;
|
||||
// Move item to the player's inventory
|
||||
ptr = mDragAndDrop->mSourceModel->moveItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount, mTradeModel);
|
||||
}
|
||||
useItem(ptr);
|
||||
}
|
||||
|
|
|
@ -71,10 +71,11 @@ namespace MWGui
|
|||
{
|
||||
}
|
||||
|
||||
void ItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel)
|
||||
MWWorld::Ptr ItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel)
|
||||
{
|
||||
otherModel->copyItem(item, count);
|
||||
MWWorld::Ptr ret = otherModel->copyItem(item, count);
|
||||
removeItem(item, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -83,10 +84,9 @@ namespace MWGui
|
|||
delete mSourceModel;
|
||||
}
|
||||
|
||||
void ProxyItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
|
||||
MWWorld::Ptr ProxyItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
|
||||
{
|
||||
// no need to use mapToSource since itemIndex refers to an index in the sourceModel
|
||||
mSourceModel->copyItem (item, count, setNewOwner);
|
||||
return mSourceModel->copyItem (item, count, setNewOwner);
|
||||
}
|
||||
|
||||
void ProxyItemModel::removeItem (const ItemStack& item, size_t count)
|
||||
|
|
|
@ -56,10 +56,10 @@ namespace MWGui
|
|||
virtual void update() = 0;
|
||||
|
||||
/// Move items from this model to \a otherModel.
|
||||
virtual void moveItem (const ItemStack& item, size_t count, ItemModel* otherModel);
|
||||
virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel);
|
||||
|
||||
/// @param setNewOwner Set the copied item's owner to the actor we are copying to, or keep the original owner?
|
||||
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0;
|
||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0;
|
||||
virtual void removeItem (const ItemStack& item, size_t count) = 0;
|
||||
|
||||
private:
|
||||
|
@ -73,7 +73,7 @@ namespace MWGui
|
|||
{
|
||||
public:
|
||||
virtual ~ProxyItemModel();
|
||||
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
|
||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
|
||||
virtual void removeItem (const ItemStack& item, size_t count);
|
||||
virtual ModelIndex getIndex (ItemStack item);
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace MWGui
|
|||
{
|
||||
|
||||
void EffectSourceVisitor::visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, const std::string& casterHandle,
|
||||
const std::string& sourceName, int casterActorId,
|
||||
float magnitude, float remainingTime)
|
||||
{
|
||||
MagicEffectInfo newEffectSource;
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace MWGui
|
|||
virtual ~EffectSourceVisitor() {}
|
||||
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, const std::string& casterHandle,
|
||||
const std::string& sourceName, int casterActorId,
|
||||
float magnitude, float remainingTime = -1);
|
||||
};
|
||||
|
||||
|
|
|
@ -53,9 +53,9 @@ namespace MWMechanics
|
|||
{
|
||||
const MWWorld::TimeStamp& start = iter->second.mTimeStamp;
|
||||
|
||||
const std::vector<Effect>& effects = iter->second.mEffects;
|
||||
const std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
||||
|
||||
for (std::vector<Effect>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||
for (std::vector<ActiveEffect>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||
{
|
||||
int duration = effectIt->mDuration;
|
||||
MWWorld::TimeStamp end = start;
|
||||
|
@ -63,7 +63,7 @@ namespace MWMechanics
|
|||
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
||||
|
||||
if (end>now)
|
||||
mEffects.add(effectIt->mKey, MWMechanics::EffectParam(effectIt->mMagnitude));
|
||||
mEffects.add(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), MWMechanics::EffectParam(effectIt->mMagnitude));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,11 +91,11 @@ namespace MWMechanics
|
|||
|
||||
double ActiveSpells::timeToExpire (const TIterator& iterator) const
|
||||
{
|
||||
const std::vector<Effect>& effects = iterator->second.mEffects;
|
||||
const std::vector<ActiveEffect>& effects = iterator->second.mEffects;
|
||||
|
||||
int duration = 0;
|
||||
|
||||
for (std::vector<Effect>::const_iterator iter (effects.begin());
|
||||
for (std::vector<ActiveEffect>::const_iterator iter (effects.begin());
|
||||
iter!=effects.end(); ++iter)
|
||||
{
|
||||
if (iter->mDuration > duration)
|
||||
|
@ -132,8 +132,8 @@ namespace MWMechanics
|
|||
return mSpells;
|
||||
}
|
||||
|
||||
void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector<Effect> effects,
|
||||
const std::string &displayName, const std::string& casterHandle)
|
||||
void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector<ActiveEffect> effects,
|
||||
const std::string &displayName, int casterActorId)
|
||||
{
|
||||
bool exists = false;
|
||||
for (TContainer::const_iterator it = begin(); it != end(); ++it)
|
||||
|
@ -146,7 +146,7 @@ namespace MWMechanics
|
|||
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
params.mEffects = effects;
|
||||
params.mDisplayName = displayName;
|
||||
params.mCasterHandle = casterHandle;
|
||||
params.mCasterActorId = casterActorId;
|
||||
|
||||
if (!exists || stack)
|
||||
mSpells.insert (std::make_pair(id, params));
|
||||
|
@ -168,7 +168,7 @@ namespace MWMechanics
|
|||
{
|
||||
float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
||||
|
||||
for (std::vector<Effect>::const_iterator effectIt = it->second.mEffects.begin();
|
||||
for (std::vector<ActiveEffect>::const_iterator effectIt = it->second.mEffects.begin();
|
||||
effectIt != it->second.mEffects.end(); ++effectIt)
|
||||
{
|
||||
std::string name = it->second.mDisplayName;
|
||||
|
@ -178,7 +178,7 @@ namespace MWMechanics
|
|||
float magnitude = effectIt->mMagnitude;
|
||||
|
||||
if (magnitude)
|
||||
visitor.visit(effectIt->mKey, name, it->second.mCasterHandle, magnitude, remainingTime);
|
||||
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->second.mCasterActorId, magnitude, remainingTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,10 +200,10 @@ namespace MWMechanics
|
|||
{
|
||||
for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it)
|
||||
{
|
||||
for (std::vector<Effect>::iterator effectIt = it->second.mEffects.begin();
|
||||
for (std::vector<ActiveEffect>::iterator effectIt = it->second.mEffects.begin();
|
||||
effectIt != it->second.mEffects.end();)
|
||||
{
|
||||
if (effectIt->mKey.mId == effectId)
|
||||
if (effectIt->mEffectId == effectId)
|
||||
effectIt = it->second.mEffects.erase(effectIt);
|
||||
else
|
||||
++effectIt;
|
||||
|
@ -212,16 +212,16 @@ namespace MWMechanics
|
|||
mSpellsChanged = true;
|
||||
}
|
||||
|
||||
void ActiveSpells::purge(const std::string &actorHandle)
|
||||
void ActiveSpells::purge(int casterActorId)
|
||||
{
|
||||
for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it)
|
||||
{
|
||||
for (std::vector<Effect>::iterator effectIt = it->second.mEffects.begin();
|
||||
for (std::vector<ActiveEffect>::iterator effectIt = it->second.mEffects.begin();
|
||||
effectIt != it->second.mEffects.end();)
|
||||
{
|
||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mKey.mId);
|
||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectId);
|
||||
if (effect->mData.mFlags & ESM::MagicEffect::CasterLinked
|
||||
&& it->second.mCasterHandle == actorHandle)
|
||||
&& it->second.mCasterActorId == casterActorId)
|
||||
effectIt = it->second.mEffects.erase(effectIt);
|
||||
else
|
||||
++effectIt;
|
||||
|
@ -229,4 +229,41 @@ namespace MWMechanics
|
|||
}
|
||||
mSpellsChanged = true;
|
||||
}
|
||||
|
||||
void ActiveSpells::clear()
|
||||
{
|
||||
mSpells.clear();
|
||||
mSpellsChanged = true;
|
||||
}
|
||||
|
||||
void ActiveSpells::writeState(ESM::ActiveSpells &state) const
|
||||
{
|
||||
for (TContainer::const_iterator it = mSpells.begin(); it != mSpells.end(); ++it)
|
||||
{
|
||||
// Stupid copying of almost identical structures. ESM::TimeStamp <-> MWWorld::TimeStamp
|
||||
ESM::ActiveSpells::ActiveSpellParams params;
|
||||
params.mEffects = it->second.mEffects;
|
||||
params.mCasterActorId = it->second.mCasterActorId;
|
||||
params.mDisplayName = it->second.mDisplayName;
|
||||
params.mTimeStamp = it->second.mTimeStamp.toEsm();
|
||||
|
||||
state.mSpells.insert (std::make_pair(it->first, params));
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveSpells::readState(const ESM::ActiveSpells &state)
|
||||
{
|
||||
for (ESM::ActiveSpells::TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it)
|
||||
{
|
||||
// Stupid copying of almost identical structures. ESM::TimeStamp <-> MWWorld::TimeStamp
|
||||
ActiveSpellParams params;
|
||||
params.mEffects = it->second.mEffects;
|
||||
params.mCasterActorId = it->second.mCasterActorId;
|
||||
params.mDisplayName = it->second.mDisplayName;
|
||||
params.mTimeStamp = MWWorld::TimeStamp(it->second.mTimeStamp);
|
||||
|
||||
mSpells.insert (std::make_pair(it->first, params));
|
||||
mSpellsChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "magiceffects.hpp"
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/activespells.hpp>
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
@ -21,29 +22,24 @@ namespace MWMechanics
|
|||
{
|
||||
public:
|
||||
|
||||
// Parameters of an effect concerning lasting effects.
|
||||
// Note we are not using ENAMstruct since the magnitude may be modified by magic resistance, etc.
|
||||
// It could also be a negative magnitude, in case of inversing an effect, e.g. Absorb spell causes damage on target, but heals the caster.
|
||||
struct Effect
|
||||
{
|
||||
float mMagnitude;
|
||||
EffectKey mKey;
|
||||
float mDuration;
|
||||
};
|
||||
typedef ESM::ActiveEffect ActiveEffect;
|
||||
|
||||
struct ActiveSpellParams
|
||||
{
|
||||
std::vector<Effect> mEffects;
|
||||
std::vector<ActiveEffect> mEffects;
|
||||
MWWorld::TimeStamp mTimeStamp;
|
||||
std::string mDisplayName;
|
||||
|
||||
// Handle to the caster that that inflicted this spell on us
|
||||
std::string mCasterHandle;
|
||||
// The caster that inflicted this spell on us
|
||||
int mCasterActorId;
|
||||
};
|
||||
|
||||
typedef std::multimap<std::string, ActiveSpellParams > TContainer;
|
||||
typedef TContainer::const_iterator TIterator;
|
||||
|
||||
void readState (const ESM::ActiveSpells& state);
|
||||
void writeState (ESM::ActiveSpells& state) const;
|
||||
|
||||
private:
|
||||
|
||||
mutable TContainer mSpells;
|
||||
|
@ -76,10 +72,9 @@ namespace MWMechanics
|
|||
/// \param stack If false, the spell is not added if one with the same ID exists already.
|
||||
/// \param effects
|
||||
/// \param displayName Name for display in magic menu.
|
||||
/// \param casterHandle
|
||||
///
|
||||
void addSpell (const std::string& id, bool stack, std::vector<Effect> effects,
|
||||
const std::string& displayName, const std::string& casterHandle);
|
||||
void addSpell (const std::string& id, bool stack, std::vector<ActiveEffect> effects,
|
||||
const std::string& displayName, int casterActorId);
|
||||
|
||||
/// Removes the active effects from this spell/potion/.. with \a id
|
||||
void removeEffects (const std::string& id);
|
||||
|
@ -90,8 +85,11 @@ namespace MWMechanics
|
|||
/// Remove all active effects, if roll succeeds (for each effect)
|
||||
void purgeAll (float chance);
|
||||
|
||||
/// Remove all effects with CASTER_LINKED flag that were cast by \a actorHandle
|
||||
void purge (const std::string& actorHandle);
|
||||
/// Remove all effects with CASTER_LINKED flag that were cast by \a casterActorId
|
||||
void purge (int casterActorId);
|
||||
|
||||
/// Remove all spells
|
||||
void clear();
|
||||
|
||||
bool isSpellActive (std::string id) const;
|
||||
///< case insensitive
|
||||
|
|
|
@ -38,9 +38,12 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a
|
|||
{
|
||||
if (bound)
|
||||
{
|
||||
MWWorld::Ptr newPtr = *actor.getClass().getContainerStore(actor).add(item, 1, actor);
|
||||
MWWorld::ActionEquip action(newPtr);
|
||||
action.execute(actor);
|
||||
if (actor.getClass().getContainerStore(actor).count(item) == 0)
|
||||
{
|
||||
MWWorld::Ptr newPtr = *actor.getClass().getContainerStore(actor).add(item, 1, actor);
|
||||
MWWorld::ActionEquip action(newPtr);
|
||||
action.execute(actor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -116,7 +119,7 @@ namespace MWMechanics
|
|||
: mCreature(trappedCreature) {}
|
||||
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, const std::string& casterHandle,
|
||||
const std::string& sourceName, int casterActorId,
|
||||
float magnitude, float remainingTime = -1)
|
||||
{
|
||||
if (key.mId != ESM::MagicEffect::Soultrap)
|
||||
|
@ -126,7 +129,7 @@ namespace MWMechanics
|
|||
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
MWWorld::Ptr caster = world->searchPtrViaHandle(casterHandle);
|
||||
MWWorld::Ptr caster = world->searchPtrViaActorId(casterActorId);
|
||||
if (caster.isEmpty() || !caster.getClass().isActor())
|
||||
return;
|
||||
|
||||
|
@ -534,28 +537,54 @@ namespace MWMechanics
|
|||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1);
|
||||
ref.getPtr().getCellRef().mPos = ipos;
|
||||
|
||||
// TODO: Add AI to follow player and fight for him
|
||||
AiFollow package(ptr.getRefData().getHandle());
|
||||
MWWorld::Class::get (ref.getPtr()).getCreatureStats (ref.getPtr()).getAiSequence().stack(package, ptr);
|
||||
MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr());
|
||||
|
||||
// Make the summoned creature follow its master and help in fights
|
||||
AiFollow package(ptr);
|
||||
summonedCreatureStats.getAiSequence().stack(package, ref.getPtr());
|
||||
int creatureActorId = summonedCreatureStats.getActorId();
|
||||
|
||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos);
|
||||
|
||||
// TODO: VFX_SummonStart, VFX_SummonEnd
|
||||
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
|
||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos).getRefData().getHandle()));
|
||||
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first, creatureActorId));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string handle = creatureStats.mSummonedCreatures[it->first];
|
||||
// TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation
|
||||
// plays though, which is a rather lame exploit in vanilla.
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle);
|
||||
// Summon lifetime has expired. Try to delete the creature.
|
||||
int actorId = creatureStats.mSummonedCreatures[it->first];
|
||||
creatureStats.mSummonedCreatures.erase(it->first);
|
||||
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(actorId);
|
||||
if (!ptr.isEmpty())
|
||||
{
|
||||
// TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation
|
||||
// plays though, which is a rather lame exploit in vanilla.
|
||||
MWBase::Environment::get().getWorld()->deleteObject(ptr);
|
||||
creatureStats.mSummonedCreatures.erase(it->first);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We didn't find the creature. It's probably in an inactive cell.
|
||||
// Add to graveyard so we can delete it when the cell becomes active.
|
||||
creatureStats.mSummonGraveyard.push_back(actorId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<int>::iterator it = creatureStats.mSummonGraveyard.begin(); it != creatureStats.mSummonGraveyard.end(); )
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it);
|
||||
if (!ptr.isEmpty())
|
||||
{
|
||||
it = creatureStats.mSummonGraveyard.erase(it);
|
||||
MWBase::Environment::get().getWorld()->deleteObject(ptr);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr)
|
||||
|
@ -730,7 +759,7 @@ namespace MWMechanics
|
|||
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player)
|
||||
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
|
||||
{
|
||||
creatureStats.getAiSequence().stack(AiPursue(player.getClass().getId(player)), ptr);
|
||||
creatureStats.getAiSequence().stack(AiPursue(player), ptr);
|
||||
creatureStats.setAlarmed(true);
|
||||
npcStats.setCrimeId(MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId());
|
||||
}
|
||||
|
@ -759,7 +788,7 @@ namespace MWMechanics
|
|||
else if (!creatureStats.isHostile())
|
||||
{
|
||||
if (ptr.getClass().isClass(ptr, "Guard"))
|
||||
creatureStats.getAiSequence().stack(AiPursue(player.getClass().getId(player)), ptr);
|
||||
creatureStats.getAiSequence().stack(AiPursue(player), ptr);
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player);
|
||||
|
@ -781,7 +810,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
void Actors::addActor (const MWWorld::Ptr& ptr)
|
||||
void Actors::addActor (const MWWorld::Ptr& ptr, bool updateImmediately)
|
||||
{
|
||||
// erase previous death events since we are currently only tracking them while in an active cell
|
||||
MWWorld::Class::get(ptr).getCreatureStats(ptr).clearHasDied();
|
||||
|
@ -790,6 +819,8 @@ namespace MWMechanics
|
|||
|
||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||
mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim)));
|
||||
if (updateImmediately)
|
||||
mActors[ptr]->update(0);
|
||||
}
|
||||
|
||||
void Actors::removeActor (const MWWorld::Ptr& ptr)
|
||||
|
@ -912,18 +943,17 @@ namespace MWMechanics
|
|||
continue;
|
||||
}
|
||||
|
||||
// Make sure spell effects with CasterLinked flag are removed
|
||||
// TODO: would be nice not to do this all the time...
|
||||
for (PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
||||
{
|
||||
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
|
||||
spells.purge(iter->first.getRefData().getHandle());
|
||||
}
|
||||
|
||||
if (iter->second->kill())
|
||||
{
|
||||
++mDeathCount[cls.getId(iter->first)];
|
||||
|
||||
// Make sure spell effects with CasterLinked flag are removed
|
||||
for (PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
||||
{
|
||||
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
|
||||
spells.purge(stats.getActorId());
|
||||
}
|
||||
|
||||
// Apply soultrap
|
||||
if (iter->first.getTypeName() == typeid(ESM::Creature).name())
|
||||
{
|
||||
|
@ -934,6 +964,7 @@ namespace MWMechanics
|
|||
// Reset magic effects and recalculate derived effects
|
||||
// One case where we need this is to make sure bound items are removed upon death
|
||||
stats.setMagicEffects(MWMechanics::MagicEffects());
|
||||
stats.getActiveSpells().clear();
|
||||
calculateCreatureStatModifiers(iter->first, 0);
|
||||
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false);
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace MWMechanics
|
|||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
void updateMagicEffects (const MWWorld::Ptr& ptr) { adjustMagicEffects(ptr); }
|
||||
|
||||
void addActor (const MWWorld::Ptr& ptr);
|
||||
void addActor (const MWWorld::Ptr& ptr, bool updateImmediately=false);
|
||||
///< Register an actor for stats management
|
||||
///
|
||||
/// \note Dead actors are ignored.
|
||||
|
|
|
@ -45,7 +45,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor,float duration
|
|||
return true; // We have tried backing up for more than one second, we've probably cleared it
|
||||
}
|
||||
|
||||
if(!MWBase::Environment::get().getWorld()->getIsMovingDoor(mDoorPtr))
|
||||
if (!mDoorPtr.getClass().getDoorState(mDoorPtr))
|
||||
return true; //Door is no longer opening
|
||||
|
||||
ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door
|
||||
|
|
|
@ -11,9 +11,9 @@ namespace MWMechanics
|
|||
{
|
||||
/// \brief AiPackage to have an actor avoid an opening door
|
||||
/** The AI will retreat from the door until it has finished opening, walked far away from it, or one second has passed, in an attempt to avoid it
|
||||
**/
|
||||
class AiAvoidDoor : public AiPackage
|
||||
{
|
||||
**/
|
||||
class AiAvoidDoor : public AiPackage
|
||||
{
|
||||
public:
|
||||
/// Avoid door until the door is fully open
|
||||
AiAvoidDoor(const MWWorld::Ptr& doorPtr);
|
||||
|
@ -29,10 +29,10 @@ namespace MWMechanics
|
|||
|
||||
private:
|
||||
float mDuration;
|
||||
const MWWorld::Ptr& mDoorPtr;
|
||||
MWWorld::Ptr mDoorPtr;
|
||||
ESM::Position mLastPos;
|
||||
float mAdjAngle;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
float mAdjAngle;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace MWMechanics
|
|||
// NOTE: MIN_DIST_TO_DOOR_SQUARED is defined in obstacle.hpp
|
||||
|
||||
AiCombat::AiCombat(const MWWorld::Ptr& actor) :
|
||||
mTarget(actor),
|
||||
mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId()),
|
||||
mTimerAttack(0),
|
||||
mTimerReact(0),
|
||||
mTimerCombatMove(0),
|
||||
|
@ -153,7 +153,9 @@ namespace MWMechanics
|
|||
|| actor.getClass().getCreatureStats(actor).getHealth().getCurrent() <= 0)
|
||||
return true;
|
||||
|
||||
if(mTarget.getClass().getCreatureStats(mTarget).isDead())
|
||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||
|
||||
if(target.getClass().getCreatureStats(target).isDead())
|
||||
return true;
|
||||
|
||||
//Update every frame
|
||||
|
@ -325,7 +327,7 @@ namespace MWMechanics
|
|||
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
Ogre::Vector3 vActorPos(pos.pos);
|
||||
Ogre::Vector3 vTargetPos(mTarget.getRefData().getPosition().pos);
|
||||
Ogre::Vector3 vTargetPos(target.getRefData().getPosition().pos);
|
||||
Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos;
|
||||
|
||||
bool isStuck = false;
|
||||
|
@ -396,7 +398,7 @@ namespace MWMechanics
|
|||
else // remote pathfinding
|
||||
{
|
||||
bool preferShortcut = false;
|
||||
bool inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget);
|
||||
bool inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target);
|
||||
|
||||
if(mReadyToAttack) isStuck = false;
|
||||
|
||||
|
@ -432,7 +434,7 @@ namespace MWMechanics
|
|||
|
||||
mFollowTarget = false;
|
||||
|
||||
buildNewPath(actor); //may fail to build a path, check before use
|
||||
buildNewPath(actor, target); //may fail to build a path, check before use
|
||||
|
||||
//delete visited path node
|
||||
mPathFinder.checkWaypoint(pos.pos[0],pos.pos[1],pos.pos[2]);
|
||||
|
@ -476,9 +478,9 @@ namespace MWMechanics
|
|||
//less than in time of playing weapon anim from 'start' to 'hit' tags (t_swing)
|
||||
//then start attacking
|
||||
float speed1 = actorCls.getSpeed(actor);
|
||||
float speed2 = mTarget.getClass().getSpeed(mTarget);
|
||||
if(mTarget.getClass().getMovementSettings(mTarget).mPosition[0] == 0
|
||||
&& mTarget.getClass().getMovementSettings(mTarget).mPosition[1] == 0)
|
||||
float speed2 = target.getClass().getSpeed(target);
|
||||
if(target.getClass().getMovementSettings(target).mPosition[0] == 0
|
||||
&& target.getClass().getMovementSettings(target).mPosition[1] == 0)
|
||||
speed2 = 0;
|
||||
|
||||
float s1 = distToTarget - weapRange;
|
||||
|
@ -570,9 +572,9 @@ namespace MWMechanics
|
|||
return false;
|
||||
}
|
||||
|
||||
void AiCombat::buildNewPath(const MWWorld::Ptr& actor)
|
||||
void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target)
|
||||
{
|
||||
Ogre::Vector3 newPathTarget = Ogre::Vector3(mTarget.getRefData().getPosition().pos);
|
||||
Ogre::Vector3 newPathTarget = Ogre::Vector3(target.getRefData().getPosition().pos);
|
||||
|
||||
float dist;
|
||||
|
||||
|
@ -627,9 +629,12 @@ namespace MWMechanics
|
|||
return 1;
|
||||
}
|
||||
|
||||
const std::string &AiCombat::getTargetId() const
|
||||
std::string AiCombat::getTargetId() const
|
||||
{
|
||||
return mTarget.getRefData().getHandle();
|
||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||
if (target.isEmpty())
|
||||
return "";
|
||||
return target.getRefData().getHandle();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace MWMechanics
|
|||
virtual unsigned int getPriority() const;
|
||||
|
||||
///Returns target ID
|
||||
const std::string &getTargetId() const;
|
||||
std::string getTargetId() const;
|
||||
|
||||
private:
|
||||
PathFinder mPathFinder;
|
||||
|
@ -53,7 +53,7 @@ namespace MWMechanics
|
|||
|
||||
ESM::Position mLastPos;
|
||||
MWMechanics::Movement mMovement;
|
||||
MWWorld::Ptr mTarget;
|
||||
int mTargetActorId;
|
||||
|
||||
const MWWorld::CellStore* mCell;
|
||||
ObstacleCheck mObstacleCheck;
|
||||
|
@ -63,7 +63,7 @@ namespace MWMechanics
|
|||
MWWorld::CellRefList<ESM::Door>::List::iterator mDoorIter;
|
||||
MWWorld::CellRefList<ESM::Door>& mDoors;
|
||||
|
||||
void buildNewPath(const MWWorld::Ptr& actor);
|
||||
void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/timestamp.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
|
||||
|
@ -19,8 +21,8 @@
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
AiEscort::AiEscort(const MWWorld::Ptr& actor, int duration, float x, float y, float z)
|
||||
: mActorId(actor.getClass().getCreatureStats(actor).getActorId()), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
, mCellX(std::numeric_limits<int>::max())
|
||||
, mCellY(std::numeric_limits<int>::max())
|
||||
{
|
||||
|
@ -38,8 +40,8 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
AiEscort::AiEscort(const MWWorld::Ptr& actor, 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)
|
||||
, mCellX(std::numeric_limits<int>::max())
|
||||
, mCellY(std::numeric_limits<int>::max())
|
||||
{
|
||||
|
@ -75,7 +77,14 @@ namespace MWMechanics
|
|||
return true;
|
||||
}
|
||||
|
||||
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
||||
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId);
|
||||
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 followerPos = follower.getRefData().getPosition().pos;
|
||||
double differenceBetween[3];
|
||||
|
@ -89,7 +98,7 @@ namespace MWMechanics
|
|||
|
||||
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;
|
||||
mMaxDist = 470;
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@ namespace MWMechanics
|
|||
/// 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
|
||||
\implement AiEscort **/
|
||||
AiEscort(const std::string &actorId,int duration, float x, float y, float z);
|
||||
AiEscort(const MWWorld::Ptr& actor,int duration, float x, float y, float z);
|
||||
/// 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
|
||||
\implement AiEscortCell **/
|
||||
AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z);
|
||||
AiEscort(const MWWorld::Ptr& actor,const std::string &cellId,int duration, float x, float y, float z);
|
||||
|
||||
virtual AiEscort *clone() const;
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace MWMechanics
|
|||
virtual int getTypeId() const;
|
||||
|
||||
private:
|
||||
std::string mActorId;
|
||||
int mActorId;
|
||||
std::string mCellId;
|
||||
float mX;
|
||||
float mY;
|
||||
|
|
|
@ -11,23 +11,26 @@
|
|||
|
||||
#include "steering.hpp"
|
||||
|
||||
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), mActorId(actorId), mCellId(""), AiPackage()
|
||||
MWMechanics::AiFollow::AiFollow(const MWWorld::Ptr& actor,float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mCellId(""), AiPackage()
|
||||
{
|
||||
mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
}
|
||||
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), mActorId(actorId), mCellId(cellId), AiPackage()
|
||||
MWMechanics::AiFollow::AiFollow(const MWWorld::Ptr& actor,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()
|
||||
{
|
||||
mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
}
|
||||
|
||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId)
|
||||
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId(""), AiPackage()
|
||||
MWMechanics::AiFollow::AiFollow(const MWWorld::Ptr& actor)
|
||||
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mCellId(""), AiPackage()
|
||||
{
|
||||
mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
}
|
||||
|
||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mActorId, false); //The target to follow
|
||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); //The target to follow
|
||||
|
||||
if(target == MWWorld::Ptr()) return true; //Target doesn't exist
|
||||
|
||||
|
@ -75,7 +78,8 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
|||
|
||||
std::string MWMechanics::AiFollow::getFollowedActor()
|
||||
{
|
||||
return mActorId;
|
||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); //The target to follow
|
||||
return target.getCellRef().mRefID;
|
||||
}
|
||||
|
||||
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||
|
|
|
@ -10,16 +10,16 @@ namespace MWMechanics
|
|||
{
|
||||
/// \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
|
||||
**/
|
||||
class AiFollow : public AiPackage
|
||||
{
|
||||
**/
|
||||
class AiFollow : public AiPackage
|
||||
{
|
||||
public:
|
||||
/// Follow Actor for duration or until you arrive at a world position
|
||||
AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z);
|
||||
AiFollow(const MWWorld::Ptr& actor,float duration, float X, float Y, float Z);
|
||||
/// Follow Actor for duration or until you arrive at a position in a cell
|
||||
AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z);
|
||||
AiFollow(const MWWorld::Ptr& actor,const std::string &CellId,float duration, float X, float Y, float Z);
|
||||
/// Follow Actor indefinitively
|
||||
AiFollow(const std::string &ActorId);
|
||||
AiFollow(const MWWorld::Ptr& actor);
|
||||
|
||||
virtual AiFollow *clone() const;
|
||||
|
||||
|
@ -38,8 +38,8 @@ namespace MWMechanics
|
|||
float mX;
|
||||
float mY;
|
||||
float mZ;
|
||||
std::string mActorId;
|
||||
std::string mCellId;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
int mActorId; // The actor we should follow
|
||||
std::string mCellId;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
#include "../mwworld/action.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
|
||||
MWMechanics::AiPursue::AiPursue(const std::string &objectId)
|
||||
: mObjectId(objectId)
|
||||
MWMechanics::AiPursue::AiPursue(const MWWorld::Ptr& actor)
|
||||
: mActorId(actor.getClass().getCreatureStats(actor).getActorId())
|
||||
{
|
||||
}
|
||||
MWMechanics::AiPursue *MWMechanics::AiPursue::clone() const
|
||||
|
@ -23,7 +25,7 @@ bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration)
|
|||
{
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow
|
||||
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); //The target to follow
|
||||
|
||||
if(target == MWWorld::Ptr())
|
||||
return true; //Target doesn't exist
|
||||
|
@ -33,8 +35,7 @@ bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration)
|
|||
|
||||
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) { //Stop when you get close
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); //Arrest player
|
||||
target.getClass().activate(target,actor).get()->execute(actor); //Arrest player
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -16,14 +16,14 @@ namespace MWMechanics
|
|||
{
|
||||
public:
|
||||
///Constructor
|
||||
/** \param objectId Actor to pursue **/
|
||||
AiPursue(const std::string &objectId);
|
||||
/** \param actor Actor to pursue **/
|
||||
AiPursue(const MWWorld::Ptr& actor);
|
||||
virtual AiPursue *clone() const;
|
||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||
virtual int getTypeId() const;
|
||||
|
||||
private:
|
||||
std::string mObjectId;
|
||||
int mActorId; // The actor to pursue
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
};
|
||||
|
|
|
@ -175,7 +175,8 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
|
|||
else if (it->mType == ESM::AI_Escort)
|
||||
{
|
||||
ESM::AITarget data = it->mTarget;
|
||||
package = new MWMechanics::AiEscort(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
|
||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(data.mId.toString(), false);
|
||||
package = new MWMechanics::AiEscort(target, data.mDuration, data.mX, data.mY, data.mZ);
|
||||
}
|
||||
else if (it->mType == ESM::AI_Travel)
|
||||
{
|
||||
|
@ -190,7 +191,8 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
|
|||
else //if (it->mType == ESM::AI_Follow)
|
||||
{
|
||||
ESM::AITarget data = it->mTarget;
|
||||
package = new MWMechanics::AiFollow(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
|
||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(data.mId.toString(), false);
|
||||
package = new MWMechanics::AiFollow(target, data.mDuration, data.mX, data.mY, data.mZ);
|
||||
}
|
||||
mPackages.push_back(package);
|
||||
}
|
||||
|
|
|
@ -431,6 +431,11 @@ void CharacterController::playRandomDeath(float startpoint)
|
|||
mDeathState = static_cast<CharacterState>(CharState_Death1 + (selected-1));
|
||||
}
|
||||
|
||||
// For dead actors, refreshCurrentAnims is no longer called, so we need to disable the movement state manually.
|
||||
mMovementState = CharState_None;
|
||||
mAnimation->disable(mCurrentMovement);
|
||||
mCurrentMovement = "";
|
||||
|
||||
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
||||
false, 1.0f, "start", "stop", startpoint, 0);
|
||||
}
|
||||
|
@ -1367,9 +1372,9 @@ bool CharacterController::kill()
|
|||
{
|
||||
if( isDead() )
|
||||
{
|
||||
//player's death animation is over
|
||||
if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) )
|
||||
{
|
||||
//player's death animation is over
|
||||
MWBase::Environment::get().getStateManager()->askLoadRecent();
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -202,7 +202,9 @@ public:
|
|||
void skipAnim();
|
||||
bool isAnimPlaying(const std::string &groupName);
|
||||
|
||||
/// @return false if the character has already been killed before
|
||||
bool kill();
|
||||
|
||||
void resurrect();
|
||||
bool isDead() const
|
||||
{ return mDeathState != CharState_None; }
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
int CreatureStats::sActorId = 0;
|
||||
|
||||
CreatureStats::CreatureStats()
|
||||
: mLevel (0), mDead (false), mDied (false), mFriendlyHits (0),
|
||||
mTalkedTo (false), mAlarmed (false),
|
||||
|
@ -20,7 +22,7 @@ namespace MWMechanics
|
|||
mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mKnockdownOneFrame(false),
|
||||
mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false),
|
||||
mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f),
|
||||
mTradeTime(0,0), mGoldPool(0)
|
||||
mTradeTime(0,0), mGoldPool(0), mActorId(-1)
|
||||
{
|
||||
for (int i=0; i<4; ++i)
|
||||
mAiSettings[i] = 0;
|
||||
|
@ -494,13 +496,15 @@ namespace MWMechanics
|
|||
state.mBlock = mBlock;
|
||||
state.mMovementFlags = mMovementFlags;
|
||||
state.mAttackStrength = mAttackStrength;
|
||||
state.mFallHeight = mFallHeight;
|
||||
state.mFallHeight = mFallHeight; // TODO: vertical velocity (move from PhysicActor to CreatureStats?)
|
||||
state.mLastHitObject = mLastHitObject;
|
||||
state.mRecalcDynamicStats = mRecalcDynamicStats;
|
||||
state.mDrawState = mDrawState;
|
||||
state.mLevel = mLevel;
|
||||
state.mActorId = mActorId;
|
||||
|
||||
mSpells.writeState(state.mSpells);
|
||||
mActiveSpells.writeState(state.mActiveSpells);
|
||||
}
|
||||
|
||||
void CreatureStats::readState (const ESM::CreatureStats& state)
|
||||
|
@ -536,8 +540,10 @@ namespace MWMechanics
|
|||
mRecalcDynamicStats = state.mRecalcDynamicStats;
|
||||
mDrawState = DrawState_(state.mDrawState);
|
||||
mLevel = state.mLevel;
|
||||
mActorId = state.mActorId;
|
||||
|
||||
mSpells.readState(state.mSpells);
|
||||
mActiveSpells.readState(state.mActiveSpells);
|
||||
}
|
||||
|
||||
// Relates to NPC gold reset delay
|
||||
|
@ -559,4 +565,34 @@ namespace MWMechanics
|
|||
{
|
||||
return mGoldPool;
|
||||
}
|
||||
|
||||
int CreatureStats::getActorId()
|
||||
{
|
||||
if (mActorId==-1)
|
||||
mActorId = sActorId++;
|
||||
|
||||
return mActorId;
|
||||
}
|
||||
|
||||
bool CreatureStats::matchesActorId (int id) const
|
||||
{
|
||||
return mActorId!=-1 && id==mActorId;
|
||||
}
|
||||
|
||||
void CreatureStats::cleanup()
|
||||
{
|
||||
sActorId = 0;
|
||||
}
|
||||
|
||||
void CreatureStats::writeActorIdCounter (ESM::ESMWriter& esm)
|
||||
{
|
||||
esm.startRecord(ESM::REC_ACTC);
|
||||
esm.writeHNT("COUN", sActorId);
|
||||
esm.endRecord(ESM::REC_ACTC);
|
||||
}
|
||||
|
||||
void CreatureStats::readActorIdCounter (ESM::ESMReader& esm)
|
||||
{
|
||||
esm.getHNT(sActorId, "COUN");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace MWMechanics
|
|||
///
|
||||
class CreatureStats
|
||||
{
|
||||
static int sActorId;
|
||||
DrawState_ mDrawState;
|
||||
AttributeValue mAttributes[8];
|
||||
DynamicStat<float> mDynamic[3]; // health, magicka, fatigue
|
||||
|
@ -58,6 +59,7 @@ namespace MWMechanics
|
|||
MWWorld::TimeStamp mTradeTime; // Relates to NPC gold reset delay
|
||||
|
||||
int mGoldPool; // the pool of merchant gold not in inventory
|
||||
int mActorId;
|
||||
|
||||
protected:
|
||||
// These two are only set by NpcStats, but they are declared in CreatureStats to prevent using virtual methods.
|
||||
|
@ -221,21 +223,39 @@ namespace MWMechanics
|
|||
void setLastHitObject(const std::string &objectid);
|
||||
const std::string &getLastHitObject() const;
|
||||
|
||||
// Note, this is just a cache to avoid checking the whole container store every frame TODO: Put it somewhere else?
|
||||
// Note, this is just a cache to avoid checking the whole container store every frame. We don't need to store it in saves.
|
||||
// TODO: Put it somewhere else?
|
||||
std::set<int> mBoundItems;
|
||||
// Same as above
|
||||
std::map<int, std::string> mSummonedCreatures;
|
||||
|
||||
// TODO: store in savegame
|
||||
// TODO: encapsulate?
|
||||
// <ESM::MagicEffect index, actor index>
|
||||
std::map<int, int> mSummonedCreatures;
|
||||
// Contains summoned creatures with an expired lifetime that have not been deleted yet.
|
||||
std::vector<int> mSummonGraveyard;
|
||||
|
||||
void writeState (ESM::CreatureStats& state) const;
|
||||
|
||||
void readState (const ESM::CreatureStats& state);
|
||||
|
||||
static void writeActorIdCounter (ESM::ESMWriter& esm);
|
||||
static void readActorIdCounter (ESM::ESMReader& esm);
|
||||
|
||||
// Relates to NPC gold reset delay
|
||||
void setTradeTime(MWWorld::TimeStamp tradeTime);
|
||||
MWWorld::TimeStamp getTradeTime() const;
|
||||
|
||||
void setGoldPool(int pool);
|
||||
int getGoldPool() const;
|
||||
|
||||
int getActorId();
|
||||
///< Will generate an actor ID, if the actor does not have one yet.
|
||||
|
||||
bool matchesActorId (int id) const;
|
||||
///< Check if \a id matches the actor ID of *this (if the actor does not have an ID
|
||||
/// assigned this function will return false).
|
||||
|
||||
static void cleanup();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace MWMechanics
|
|||
struct EffectSourceVisitor
|
||||
{
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, const std::string& casterHandle,
|
||||
const std::string& sourceName, int casterActorId,
|
||||
float magnitude, float remainingTime = -1) = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -25,11 +25,11 @@ namespace
|
|||
bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim)
|
||||
{
|
||||
const std::string& owner = item.getCellRef().mOwner;
|
||||
bool isOwned = !owner.empty();
|
||||
bool isOwned = !owner.empty() && owner != "player";
|
||||
|
||||
const std::string& faction = item.getCellRef().mFaction;
|
||||
bool isFactionOwned = false;
|
||||
if (!faction.empty())
|
||||
if (!faction.empty() && ptr.getClass().isNpc())
|
||||
{
|
||||
const std::map<std::string, int>& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks();
|
||||
if (factions.find(Misc::StringUtils::lowerCase(faction)) == factions.end())
|
||||
|
@ -385,7 +385,7 @@ namespace MWMechanics
|
|||
// have been made for them. Make sure they're properly updated.
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
mActors.removeActor(ptr);
|
||||
mActors.addActor(ptr);
|
||||
mActors.addActor(ptr, true);
|
||||
}
|
||||
|
||||
mActors.update(duration, paused);
|
||||
|
|
|
@ -140,7 +140,7 @@ namespace MWMechanics
|
|||
float x = (willpower + 0.1 * luck) * stats.getFatigueTerm();
|
||||
|
||||
// This makes spells that are easy to cast harder to resist and vice versa
|
||||
if (spell != NULL && caster.getClass().isActor())
|
||||
if (spell != NULL && !caster.isEmpty() && caster.getClass().isActor())
|
||||
{
|
||||
float castChance = getSpellSuccessChance(spell, caster);
|
||||
if (castChance > 0)
|
||||
|
@ -189,6 +189,9 @@ namespace MWMechanics
|
|||
void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster,
|
||||
const ESM::EffectList &effects, ESM::RangeType range, bool reflected, bool exploded)
|
||||
{
|
||||
if (target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead())
|
||||
return;
|
||||
|
||||
// If none of the effects need to apply, we can early-out
|
||||
bool found = false;
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
||||
|
@ -219,10 +222,12 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
ESM::EffectList reflectedEffects;
|
||||
std::vector<ActiveSpells::Effect> appliedLastingEffects;
|
||||
std::vector<ActiveSpells::ActiveEffect> appliedLastingEffects;
|
||||
bool firstAppliedEffect = true;
|
||||
bool anyHarmfulEffect = false;
|
||||
|
||||
bool castByPlayer = (!caster.isEmpty() && caster.getRefData().getHandle() == "player");
|
||||
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.mList.begin());
|
||||
effectIt!=effects.mList.end(); ++effectIt)
|
||||
{
|
||||
|
@ -235,7 +240,7 @@ namespace MWMechanics
|
|||
|
||||
if (!MWBase::Environment::get().getWorld()->isLevitationEnabled() && effectIt->mEffectID == ESM::MagicEffect::Levitate)
|
||||
{
|
||||
if (caster.getRefData().getHandle() == "player")
|
||||
if (castByPlayer)
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sLevitateDisabled}");
|
||||
continue;
|
||||
}
|
||||
|
@ -246,13 +251,13 @@ namespace MWMechanics
|
|||
effectIt->mEffectID == ESM::MagicEffect::Mark ||
|
||||
effectIt->mEffectID == ESM::MagicEffect::Recall))
|
||||
{
|
||||
if (caster.getRefData().getHandle() == "player")
|
||||
if (castByPlayer)
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// If player is healing someone, show the target's HP bar
|
||||
if (caster.getRefData().getHandle() == "player" && target != caster
|
||||
if (castByPlayer && target != caster
|
||||
&& effectIt->mEffectID == ESM::MagicEffect::RestoreHealth
|
||||
&& target.getClass().isActor())
|
||||
MWBase::Environment::get().getWindowManager()->setEnemy(target);
|
||||
|
@ -263,7 +268,7 @@ namespace MWMechanics
|
|||
anyHarmfulEffect = true;
|
||||
|
||||
// If player is attempting to cast a harmful spell, show the target's HP bar
|
||||
if (caster.getRefData().getHandle() == "player" && target != caster)
|
||||
if (castByPlayer && target != caster)
|
||||
MWBase::Environment::get().getWindowManager()->setEnemy(target);
|
||||
|
||||
// Try absorbing if it's a spell
|
||||
|
@ -329,8 +334,9 @@ namespace MWMechanics
|
|||
bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
|
||||
if (target.getClass().isActor() && hasDuration)
|
||||
{
|
||||
ActiveSpells::Effect effect;
|
||||
effect.mKey = MWMechanics::EffectKey(*effectIt);
|
||||
ActiveSpells::ActiveEffect effect;
|
||||
effect.mEffectId = effectIt->mEffectID;
|
||||
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
|
||||
effect.mDuration = effectIt->mDuration;
|
||||
effect.mMagnitude = magnitude;
|
||||
|
||||
|
@ -338,17 +344,20 @@ namespace MWMechanics
|
|||
|
||||
// For absorb effects, also apply the effect to the caster - but with a negative
|
||||
// magnitude, since we're transfering stats from the target to the caster
|
||||
for (int i=0; i<5; ++i)
|
||||
if (!caster.isEmpty() && caster.getClass().isActor())
|
||||
{
|
||||
if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i)
|
||||
for (int i=0; i<5; ++i)
|
||||
{
|
||||
std::vector<ActiveSpells::Effect> effects;
|
||||
ActiveSpells::Effect effect_ = effect;
|
||||
effect_.mMagnitude *= -1;
|
||||
effects.push_back(effect_);
|
||||
// Also make sure to set casterHandle = target, so that the effect on the caster gets purged when the target dies
|
||||
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true,
|
||||
effects, mSourceName, target.getRefData().getHandle());
|
||||
if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i)
|
||||
{
|
||||
std::vector<ActiveSpells::ActiveEffect> effects;
|
||||
ActiveSpells::ActiveEffect effect_ = effect;
|
||||
effect_.mMagnitude *= -1;
|
||||
effects.push_back(effect_);
|
||||
// Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies
|
||||
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true,
|
||||
effects, mSourceName, target.getClass().getCreatureStats(target).getActorId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -389,6 +398,7 @@ namespace MWMechanics
|
|||
else
|
||||
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_DefaultHit");
|
||||
|
||||
// TODO: VFX are no longer active after saving/reloading the game
|
||||
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
|
||||
// Note: in case of non actor, a free effect should be fine as well
|
||||
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);
|
||||
|
@ -405,12 +415,17 @@ namespace MWMechanics
|
|||
inflict(caster, target, reflectedEffects, range, true);
|
||||
|
||||
if (!appliedLastingEffects.empty())
|
||||
{
|
||||
int casterActorId = -1;
|
||||
if (caster.getClass().isActor())
|
||||
casterActorId = caster.getClass().getCreatureStats(caster).getActorId();
|
||||
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects,
|
||||
mSourceName, caster.getRefData().getHandle());
|
||||
mSourceName, casterActorId);
|
||||
}
|
||||
|
||||
if (anyHarmfulEffect && target.getClass().isActor() && target != caster
|
||||
&& target.getClass().getCreatureStats(target).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() <= 30)
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(caster, target, MWBase::MechanicsManager::OT_Assault);
|
||||
// Notify the target actor they've been hit
|
||||
if (anyHarmfulEffect && target.getClass().isActor() && target != caster && caster.getClass().isActor())
|
||||
target.getClass().onHit(target, 0.f, true, MWWorld::Ptr(), caster, true);
|
||||
}
|
||||
|
||||
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude)
|
||||
|
@ -431,7 +446,8 @@ namespace MWMechanics
|
|||
if (target.getCellRef().mLockLevel > 0)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f);
|
||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target);
|
||||
if (!caster.isEmpty() && caster.getClass().isActor())
|
||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target);
|
||||
}
|
||||
target.getCellRef().mLockLevel = -abs(target.getCellRef().mLockLevel); //unlocks the door
|
||||
}
|
||||
|
|
|
@ -61,9 +61,12 @@ namespace MWMechanics
|
|||
/// @note Auto detects if spell, ingredient or potion
|
||||
bool cast (const std::string& id);
|
||||
|
||||
/// @note \a target can be any type of object, not just actors.
|
||||
/// @note \a caster can be any type of object, or even an empty object.
|
||||
void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
|
||||
const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false, bool exploded=false);
|
||||
|
||||
/// @note \a caster can be any type of object, or even an empty object.
|
||||
void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude);
|
||||
};
|
||||
|
||||
|
|
|
@ -211,7 +211,7 @@ namespace MWMechanics
|
|||
random = it->second.at(i);
|
||||
|
||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
|
||||
visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, "", magnitude);
|
||||
visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, -1, magnitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ namespace MWScript
|
|||
|
||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true);
|
||||
|
||||
Interpreter::Type_Float duration = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
@ -107,7 +108,7 @@ namespace MWScript
|
|||
// discard additional arguments (reset), because we have no idea what they mean.
|
||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||
|
||||
MWMechanics::AiEscort escortPackage(actorID, duration, x, y, z);
|
||||
MWMechanics::AiEscort escortPackage(actor, duration, x, y, z);
|
||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
|
||||
|
||||
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
||||
|
@ -126,6 +127,7 @@ namespace MWScript
|
|||
|
||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true);
|
||||
|
||||
std::string cellID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
@ -145,7 +147,7 @@ namespace MWScript
|
|||
// discard additional arguments (reset), because we have no idea what they mean.
|
||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||
|
||||
MWMechanics::AiEscort escortPackage(actorID, cellID, duration, x, y, z);
|
||||
MWMechanics::AiEscort escortPackage(actor, cellID, duration, x, y, z);
|
||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr);
|
||||
|
||||
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
||||
|
@ -281,6 +283,7 @@ namespace MWScript
|
|||
|
||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true);
|
||||
|
||||
Interpreter::Type_Float duration = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
@ -297,7 +300,7 @@ namespace MWScript
|
|||
// discard additional arguments (reset), because we have no idea what they mean.
|
||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||
|
||||
MWMechanics::AiFollow followPackage(actorID, duration, x, y ,z);
|
||||
MWMechanics::AiFollow followPackage(actor, duration, x, y ,z);
|
||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
|
||||
|
||||
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
||||
|
@ -316,6 +319,7 @@ namespace MWScript
|
|||
|
||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true);
|
||||
|
||||
std::string cellID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
@ -335,8 +339,8 @@ namespace MWScript
|
|||
// discard additional arguments (reset), because we have no idea what they mean.
|
||||
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||
|
||||
MWMechanics::AiFollow followPackage(actorID, cellID, duration, x, y ,z);
|
||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
|
||||
MWMechanics::AiFollow followPackage(actor, cellID, duration, x, y ,z);
|
||||
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(followPackage, ptr);
|
||||
std::cout << "AiFollow: " << actorID << ", " << x << ", " << y << ", " << z << ", " << duration
|
||||
<< std::endl;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "../mwscript/globalscripts.hpp"
|
||||
|
||||
|
@ -46,6 +47,8 @@ void MWState::StateManager::cleanup (bool force)
|
|||
mState = State_NoGame;
|
||||
mCharacterManager.clearCurrentCharacter();
|
||||
mTimePlayed = 0;
|
||||
|
||||
MWMechanics::CreatureStats::cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,6 +318,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
|
|||
case ESM::REC_CSTA:
|
||||
case ESM::REC_WTHR:
|
||||
case ESM::REC_DYNA:
|
||||
case ESM::REC_ACTC:
|
||||
|
||||
MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap);
|
||||
break;
|
||||
|
|
|
@ -22,7 +22,6 @@ namespace MWWorld
|
|||
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor);
|
||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
{
|
||||
std::cout << "teleporting someone!" << (*it).getCellRef().mRefID;
|
||||
executeImp(*it);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,14 @@
|
|||
#include <components/esm/npcstate.hpp>
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
#include <components/esm/fogstate.hpp>
|
||||
#include <components/esm/creaturelevliststate.hpp>
|
||||
#include <components/esm/doorstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "ptr.hpp"
|
||||
#include "esmstore.hpp"
|
||||
#include "class.hpp"
|
||||
|
@ -41,6 +45,22 @@ namespace
|
|||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
MWWorld::Ptr searchViaActorId (MWWorld::CellRefList<T>& actorList, int actorId,
|
||||
MWWorld::CellStore *cell)
|
||||
{
|
||||
for (typename MWWorld::CellRefList<T>::List::iterator iter (actorList.mList.begin());
|
||||
iter!=actorList.mList.end(); ++iter)
|
||||
{
|
||||
MWWorld::Ptr actor (&*iter, cell);
|
||||
|
||||
if (actor.getClass().getCreatureStats (actor).matchesActorId (actorId) && actor.getRefData().getCount() > 0)
|
||||
return actor;
|
||||
}
|
||||
|
||||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
template<typename RecordType, typename T>
|
||||
void writeReferenceCollection (ESM::ESMWriter& writer,
|
||||
const MWWorld::CellRefList<T>& collection)
|
||||
|
@ -323,6 +343,17 @@ namespace MWWorld
|
|||
return Ptr();
|
||||
}
|
||||
|
||||
Ptr CellStore::searchViaActorId (int id)
|
||||
{
|
||||
if (Ptr ptr = ::searchViaActorId (mNpcs, id, this))
|
||||
return ptr;
|
||||
|
||||
if (Ptr ptr = ::searchViaActorId (mCreatures, id, this))
|
||||
return ptr;
|
||||
|
||||
return Ptr();
|
||||
}
|
||||
|
||||
float CellStore::getWaterLevel() const
|
||||
{
|
||||
return mWaterLevel;
|
||||
|
@ -561,9 +592,9 @@ namespace MWWorld
|
|||
writeReferenceCollection<ESM::ObjectState> (writer, mClothes);
|
||||
writeReferenceCollection<ESM::ContainerState> (writer, mContainers);
|
||||
writeReferenceCollection<ESM::CreatureState> (writer, mCreatures);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mDoors);
|
||||
writeReferenceCollection<ESM::DoorState> (writer, mDoors);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mIngreds);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mCreatureLists);
|
||||
writeReferenceCollection<ESM::CreatureLevListState> (writer, mCreatureLists);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mItemLists);
|
||||
writeReferenceCollection<ESM::LightState> (writer, mLights);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mLockpicks);
|
||||
|
@ -629,7 +660,7 @@ namespace MWWorld
|
|||
|
||||
case ESM::REC_DOOR:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mDoors, contentFileMap);
|
||||
readReferenceCollection<ESM::DoorState> (reader, mDoors, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_INGR:
|
||||
|
@ -639,7 +670,7 @@ namespace MWWorld
|
|||
|
||||
case ESM::REC_LEVC:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mCreatureLists, contentFileMap);
|
||||
readReferenceCollection<ESM::CreatureLevListState> (reader, mCreatureLists, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_LEVI:
|
||||
|
|
|
@ -91,6 +91,9 @@ namespace MWWorld
|
|||
Ptr searchViaHandle (const std::string& handle);
|
||||
///< Will return an empty Ptr if cell is not loaded.
|
||||
|
||||
Ptr searchViaActorId (int id);
|
||||
///< Will return an empty Ptr if cell is not loaded.
|
||||
|
||||
float getWaterLevel() const;
|
||||
|
||||
void setWaterLevel (float level);
|
||||
|
|
|
@ -406,4 +406,14 @@ namespace MWWorld
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int Class::getDoorState (const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
throw std::runtime_error("this is not a door");
|
||||
}
|
||||
|
||||
void Class::setDoorState (const MWWorld::Ptr &ptr, int state) const
|
||||
{
|
||||
throw std::runtime_error("this is not a door");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -336,6 +336,11 @@ namespace MWWorld
|
|||
virtual int getBaseGold(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const;
|
||||
|
||||
/// 0 = nothing, 1 = opening, 2 = closing
|
||||
virtual int getDoorState (const MWWorld::Ptr &ptr) const;
|
||||
/// This does not actually cause the door to move. Use World::activateDoor instead.
|
||||
virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -599,7 +599,7 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
|
|||
const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID][i];
|
||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
|
||||
magnitude *= params.mMultiplier;
|
||||
visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), "", magnitude);
|
||||
visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), -1, magnitude);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
|
|
@ -507,4 +507,24 @@ namespace MWWorld
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Ptr Scene::searchPtrViaHandle (const std::string& handle)
|
||||
{
|
||||
for (CellStoreCollection::const_iterator iter (mActiveCells.begin());
|
||||
iter!=mActiveCells.end(); ++iter)
|
||||
if (Ptr ptr = (*iter)->searchViaHandle (handle))
|
||||
return ptr;
|
||||
|
||||
return Ptr();
|
||||
}
|
||||
|
||||
Ptr Scene::searchPtrViaActorId (int actorId)
|
||||
{
|
||||
for (CellStoreCollection::const_iterator iter (mActiveCells.begin());
|
||||
iter!=mActiveCells.end(); ++iter)
|
||||
if (Ptr ptr = (*iter)->searchViaActorId (actorId))
|
||||
return ptr;
|
||||
|
||||
return Ptr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,6 +104,10 @@ namespace MWWorld
|
|||
///< Remove an object from the scene, but not from the world model.
|
||||
|
||||
bool isCellActive(const CellStore &cell);
|
||||
|
||||
Ptr searchPtrViaHandle (const std::string& handle);
|
||||
|
||||
Ptr searchPtrViaActorId (int actorId);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -275,7 +275,8 @@ namespace MWWorld
|
|||
+mStore.countSavedGameRecords()
|
||||
+mGlobalVariables.countSavedGameRecords()
|
||||
+1 // player record
|
||||
+1; // weather record
|
||||
+1 // weather record
|
||||
+1; // actorId counter
|
||||
}
|
||||
|
||||
void World::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
|
||||
|
@ -288,6 +289,9 @@ namespace MWWorld
|
|||
mRendering->writeFog(cellstore);
|
||||
}
|
||||
|
||||
MWMechanics::CreatureStats::writeActorIdCounter(writer);
|
||||
progress.increaseProgress();
|
||||
|
||||
mCells.write (writer, progress);
|
||||
mStore.write (writer, progress);
|
||||
mGlobalVariables.write (writer, progress);
|
||||
|
@ -298,6 +302,12 @@ namespace MWWorld
|
|||
void World::readRecord (ESM::ESMReader& reader, int32_t type,
|
||||
const std::map<int, int>& contentFileMap)
|
||||
{
|
||||
if (type == ESM::REC_ACTC)
|
||||
{
|
||||
MWMechanics::CreatureStats::readActorIdCounter(reader);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mStore.readRecord (reader, type) &&
|
||||
!mGlobalVariables.readRecord (reader, type) &&
|
||||
!mPlayer->readRecord (reader, type) &&
|
||||
|
@ -547,17 +557,17 @@ namespace MWWorld
|
|||
{
|
||||
if (mPlayer->getPlayer().getRefData().getHandle()==handle)
|
||||
return mPlayer->getPlayer();
|
||||
for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin());
|
||||
iter!=mWorldScene->getActiveCells().end(); ++iter)
|
||||
{
|
||||
CellStore* cellstore = *iter;
|
||||
Ptr ptr = cellstore->searchViaHandle (handle);
|
||||
|
||||
if (!ptr.isEmpty())
|
||||
return ptr;
|
||||
}
|
||||
return mWorldScene->searchPtrViaHandle (handle);
|
||||
}
|
||||
|
||||
return MWWorld::Ptr();
|
||||
Ptr World::searchPtrViaActorId (int actorId)
|
||||
{
|
||||
// The player is not registered in any CellStore so must be checked manually
|
||||
if (actorId == getPlayerPtr().getClass().getCreatureStats(getPlayerPtr()).getActorId())
|
||||
return getPlayerPtr();
|
||||
// Now search cells
|
||||
return mWorldScene->searchPtrViaActorId (actorId);
|
||||
}
|
||||
|
||||
void World::addContainerScripts(const Ptr& reference, CellStore * cell)
|
||||
|
@ -1196,36 +1206,48 @@ namespace MWWorld
|
|||
while (it != mDoorStates.end())
|
||||
{
|
||||
if (!mWorldScene->isCellActive(*it->first.getCell()) || !it->first.getRefData().getBaseNode())
|
||||
{
|
||||
// The door is no longer in an active cell, or it was disabled.
|
||||
// Erase from mDoorStates, since we no longer need to move it.
|
||||
// Once we load the door's cell again (or re-enable the door), Door::insertObject will reinsert to mDoorStates.
|
||||
mDoorStates.erase(it++);
|
||||
}
|
||||
else
|
||||
{
|
||||
float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees();
|
||||
float diff = duration * 90;
|
||||
float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second ? 1 : -1)), 90.f);
|
||||
float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second == 1 ? 1 : -1)), 90.f);
|
||||
localRotateObject(it->first, 0, 0, targetRot);
|
||||
|
||||
bool reached = (targetRot == 90.f && it->second) || targetRot == 0.f;
|
||||
|
||||
/// \todo should use convexSweepTest here
|
||||
std::vector<std::string> collisions = mPhysics->getCollisions(it->first);
|
||||
for (std::vector<std::string>::iterator cit = collisions.begin(); cit != collisions.end(); ++cit)
|
||||
{
|
||||
MWWorld::Ptr ptr = getPtrViaHandle(*cit);
|
||||
if (MWWorld::Class::get(ptr).isActor())
|
||||
if (ptr.getClass().isActor())
|
||||
{
|
||||
// Collided with actor, ask actor to try to avoid door
|
||||
if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr() ) {
|
||||
MWMechanics::AiSequence& seq = MWWorld::Class::get(ptr).getCreatureStats(ptr).getAiSequence();
|
||||
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
||||
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once
|
||||
seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr);
|
||||
}
|
||||
|
||||
// we need to undo the rotation
|
||||
localRotateObject(it->first, 0, 0, oldRot);
|
||||
reached = false;
|
||||
//break; //Removed in case multiple actors are touching
|
||||
}
|
||||
}
|
||||
|
||||
if ((targetRot == 90.f && it->second) || targetRot == 0.f)
|
||||
if (reached)
|
||||
{
|
||||
// Mark as non-moving
|
||||
it->first.getClass().setDoorState(it->first, 0);
|
||||
mDoorStates.erase(it++);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
@ -1843,31 +1865,32 @@ namespace MWWorld
|
|||
|
||||
void World::activateDoor(const MWWorld::Ptr& door)
|
||||
{
|
||||
if (mDoorStates.find(door) != mDoorStates.end())
|
||||
{
|
||||
// if currently opening, then close, if closing, then open
|
||||
mDoorStates[door] = !mDoorStates[door];
|
||||
}
|
||||
else
|
||||
int state = door.getClass().getDoorState(door);
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
if (door.getRefData().getLocalRotation().rot[2] == 0)
|
||||
mDoorStates[door] = 1; // open
|
||||
state = 1; // if closed, then open
|
||||
else
|
||||
mDoorStates[door] = 0; // close
|
||||
state = 2; // if open, then close
|
||||
break;
|
||||
case 2:
|
||||
state = 1; // if closing, then open
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
state = 2; // if opening, then close
|
||||
break;
|
||||
}
|
||||
door.getClass().setDoorState(door, state);
|
||||
mDoorStates[door] = state;
|
||||
}
|
||||
|
||||
bool World::getOpenOrCloseDoor(const Ptr &door)
|
||||
void World::activateDoor(const Ptr &door, bool open)
|
||||
{
|
||||
if (mDoorStates.find(door) != mDoorStates.end())
|
||||
return !mDoorStates[door]; // if currently opening or closing, then do the opposite
|
||||
return door.getRefData().getLocalRotation().rot[2] == 0;
|
||||
}
|
||||
|
||||
bool World::getIsMovingDoor(const Ptr& door)
|
||||
{
|
||||
bool result = mDoorStates.find(door) != mDoorStates.end();
|
||||
return result;
|
||||
int state = open ? 1 : 2;
|
||||
door.getClass().setDoorState(door, state);
|
||||
mDoorStates[door] = state;
|
||||
}
|
||||
|
||||
bool World::getPlayerStandingOn (const MWWorld::Ptr& object)
|
||||
|
@ -2231,7 +2254,7 @@ namespace MWWorld
|
|||
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed)
|
||||
{
|
||||
ProjectileState state;
|
||||
state.mActorHandle = actor.getRefData().getHandle();
|
||||
state.mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
state.mBow = bow;
|
||||
state.mVelocity = orient.yAxis() * speed;
|
||||
|
||||
|
@ -2318,7 +2341,7 @@ namespace MWWorld
|
|||
MagicBoltState state;
|
||||
state.mSourceName = sourceName;
|
||||
state.mId = id;
|
||||
state.mActorHandle = actor.getRefData().getHandle();
|
||||
state.mActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
state.mSpeed = speed;
|
||||
state.mStack = stack;
|
||||
|
||||
|
@ -2382,7 +2405,7 @@ namespace MWWorld
|
|||
if (obstacle == ptr)
|
||||
continue;
|
||||
|
||||
MWWorld::Ptr caster = searchPtrViaHandle(it->second.mActorHandle);
|
||||
MWWorld::Ptr caster = searchPtrViaActorId(it->second.mActorId);
|
||||
|
||||
// Arrow intersects with player immediately after shooting :/
|
||||
if (obstacle == caster)
|
||||
|
@ -2468,7 +2491,7 @@ namespace MWWorld
|
|||
if (obstacle == ptr)
|
||||
continue;
|
||||
|
||||
MWWorld::Ptr caster = searchPtrViaHandle(it->second.mActorHandle);
|
||||
MWWorld::Ptr caster = searchPtrViaActorId(it->second.mActorId);
|
||||
if (caster.isEmpty())
|
||||
caster = obstacle;
|
||||
|
||||
|
@ -2491,7 +2514,7 @@ namespace MWWorld
|
|||
|
||||
if (explode)
|
||||
{
|
||||
MWWorld::Ptr caster = searchPtrViaHandle(it->second.mActorHandle);
|
||||
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);
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace MWWorld
|
|||
float mFacedDistance;
|
||||
|
||||
std::map<MWWorld::Ptr, int> mDoorStates;
|
||||
///< only holds doors that are currently moving. 0 means closing, 1 opening
|
||||
///< only holds doors that are currently moving. 1 = opening, 2 = closing
|
||||
|
||||
struct MagicBoltState
|
||||
{
|
||||
|
@ -96,7 +96,7 @@ namespace MWWorld
|
|||
std::string mId;
|
||||
|
||||
// Actor who casted this projectile
|
||||
std::string mActorHandle;
|
||||
int mActorId;
|
||||
|
||||
// Name of item to display as effect source in magic menu (in case we casted an enchantment)
|
||||
std::string mSourceName;
|
||||
|
@ -111,7 +111,7 @@ namespace MWWorld
|
|||
struct ProjectileState
|
||||
{
|
||||
// Actor who shot this projectile
|
||||
std::string mActorHandle;
|
||||
int mActorId;
|
||||
|
||||
MWWorld::Ptr mBow; // bow or crossbow the projectile was fired from
|
||||
|
||||
|
@ -287,6 +287,9 @@ namespace MWWorld
|
|||
virtual Ptr searchPtrViaHandle (const std::string& handle);
|
||||
///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found
|
||||
|
||||
virtual Ptr searchPtrViaActorId (int actorId);
|
||||
///< Search is limited to the active cells.
|
||||
|
||||
virtual void adjustPosition (const Ptr& ptr);
|
||||
///< Adjust position after load to be on ground. Must be called after model load.
|
||||
|
||||
|
@ -493,13 +496,11 @@ namespace MWWorld
|
|||
virtual void setupPlayer();
|
||||
virtual void renderPlayer();
|
||||
|
||||
/// if activated, should this door be opened or closed?
|
||||
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door);
|
||||
|
||||
/// activate (open or close) an non-teleport door
|
||||
/// open or close a non-teleport door (depending on current state)
|
||||
virtual void activateDoor(const MWWorld::Ptr& door);
|
||||
|
||||
virtual bool getIsMovingDoor(const MWWorld::Ptr& door);
|
||||
/// open or close a non-teleport door as specified
|
||||
virtual void activateDoor(const MWWorld::Ptr& door, bool open);
|
||||
|
||||
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object); ///< @return true if the player is standing on \a object
|
||||
virtual bool getActorStandingOn (const MWWorld::Ptr& object); ///< @return true if any actor is standing on \a object
|
||||
|
|
|
@ -45,7 +45,7 @@ add_component_dir (esm
|
|||
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
||||
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
|
||||
npcstats creaturestats weatherstate quickkeys fogstate spellstate
|
||||
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate
|
||||
)
|
||||
|
||||
add_component_dir (misc
|
||||
|
|
56
components/esm/activespells.cpp
Normal file
56
components/esm/activespells.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include "activespells.hpp"
|
||||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
||||
void ActiveSpells::save(ESMWriter &esm) const
|
||||
{
|
||||
for (TContainer::const_iterator it = mSpells.begin(); it != mSpells.end(); ++it)
|
||||
{
|
||||
esm.writeHNString ("ID__", it->first);
|
||||
|
||||
const ActiveSpellParams& params = it->second;
|
||||
|
||||
esm.writeHNT ("CAST", params.mCasterActorId);
|
||||
esm.writeHNString ("DISP", params.mDisplayName);
|
||||
esm.writeHNT ("TIME", params.mTimeStamp);
|
||||
|
||||
for (std::vector<ActiveEffect>::const_iterator effectIt = params.mEffects.begin(); effectIt != params.mEffects.end(); ++effectIt)
|
||||
{
|
||||
esm.writeHNT ("MGEF", effectIt->mEffectId);
|
||||
if (effectIt->mArg != -1)
|
||||
esm.writeHNT ("ARG_", effectIt->mArg);
|
||||
esm.writeHNT ("MAGN", effectIt->mMagnitude);
|
||||
esm.writeHNT ("DURA", effectIt->mDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveSpells::load(ESMReader &esm)
|
||||
{
|
||||
while (esm.isNextSub("ID__"))
|
||||
{
|
||||
std::string spellId = esm.getHString();
|
||||
|
||||
ActiveSpellParams params;
|
||||
esm.getHNT (params.mCasterActorId, "CAST");
|
||||
params.mDisplayName = esm.getHNString ("DISP");
|
||||
esm.getHNT (params.mTimeStamp, "TIME");
|
||||
|
||||
while (esm.isNextSub("MGEF"))
|
||||
{
|
||||
ActiveEffect effect;
|
||||
esm.getHT(effect.mEffectId);
|
||||
effect.mArg = -1;
|
||||
esm.getHNOT(effect.mArg, "ARG_");
|
||||
esm.getHNT (effect.mMagnitude, "MAGN");
|
||||
esm.getHNT (effect.mDuration, "DURA");
|
||||
params.mEffects.push_back(effect);
|
||||
}
|
||||
mSpells.insert(std::make_pair(spellId, params));
|
||||
}
|
||||
}
|
||||
}
|
45
components/esm/activespells.hpp
Normal file
45
components/esm/activespells.hpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef OPENMW_ESM_ACTIVESPELLS_H
|
||||
#define OPENMW_ESM_ACTIVESPELLS_H
|
||||
|
||||
#include "effectlist.hpp"
|
||||
#include "defs.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
// Parameters of an effect concerning lasting effects.
|
||||
// Note we are not using ENAMstruct since the magnitude may be modified by magic resistance, etc.
|
||||
// It could also be a negative magnitude, in case of inversing an effect, e.g. Absorb spell causes damage on target, but heals the caster.
|
||||
struct ActiveEffect
|
||||
{
|
||||
int mEffectId;
|
||||
float mMagnitude;
|
||||
int mArg; // skill or attribute
|
||||
float mDuration;
|
||||
};
|
||||
|
||||
// format 0, saved games only
|
||||
struct ActiveSpells
|
||||
{
|
||||
struct ActiveSpellParams
|
||||
{
|
||||
std::vector<ActiveEffect> mEffects;
|
||||
ESM::TimeStamp mTimeStamp;
|
||||
std::string mDisplayName;
|
||||
int mCasterActorId;
|
||||
};
|
||||
|
||||
typedef std::multimap<std::string, ActiveSpellParams > TContainer;
|
||||
TContainer mSpells;
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
25
components/esm/creaturelevliststate.cpp
Normal file
25
components/esm/creaturelevliststate.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "creaturelevliststate.hpp"
|
||||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
||||
void CreatureLevListState::load(ESMReader &esm)
|
||||
{
|
||||
ObjectState::load(esm);
|
||||
|
||||
mSpawnActorId = -1;
|
||||
esm.getHNOT (mSpawnActorId, "SPAW");
|
||||
}
|
||||
|
||||
void CreatureLevListState::save(ESMWriter &esm, bool inInventory) const
|
||||
{
|
||||
ObjectState::save(esm, inInventory);
|
||||
|
||||
if (mSpawnActorId != -1)
|
||||
esm.writeHNT ("SPAW", mSpawnActorId);
|
||||
}
|
||||
|
||||
}
|
19
components/esm/creaturelevliststate.hpp
Normal file
19
components/esm/creaturelevliststate.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef OPENMW_ESM_CREATURELEVLISTSTATE_H
|
||||
#define OPENMW_ESM_CREATURELEVLISTSTATE_H
|
||||
|
||||
#include "objectstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
// format 0, saved games only
|
||||
|
||||
struct CreatureLevListState : public ObjectState
|
||||
{
|
||||
int mSpawnActorId;
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include "creaturestats.hpp"
|
||||
|
||||
void ESM::CreatureStats::load (ESMReader &esm)
|
||||
|
@ -72,7 +71,11 @@ void ESM::CreatureStats::load (ESMReader &esm)
|
|||
mLevel = 1;
|
||||
esm.getHNOT (mLevel, "LEVL");
|
||||
|
||||
mActorId = -1;
|
||||
esm.getHNOT (mActorId, "ACID");
|
||||
|
||||
mSpells.load(esm);
|
||||
mActiveSpells.load(esm);
|
||||
}
|
||||
|
||||
void ESM::CreatureStats::save (ESMWriter &esm) const
|
||||
|
@ -146,5 +149,9 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
|
|||
if (mLevel != 1)
|
||||
esm.writeHNT ("LEVL", mLevel);
|
||||
|
||||
if (mActorId != -1)
|
||||
esm.writeHNT ("ACID", mActorId);
|
||||
|
||||
mSpells.save(esm);
|
||||
mActiveSpells.save(esm);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "defs.hpp"
|
||||
|
||||
#include "spellstate.hpp"
|
||||
#include "activespells.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
@ -24,6 +25,7 @@ namespace ESM
|
|||
|
||||
ESM::TimeStamp mTradeTime;
|
||||
int mGoldPool;
|
||||
int mActorId;
|
||||
|
||||
bool mDead;
|
||||
bool mDied;
|
||||
|
@ -48,6 +50,7 @@ namespace ESM
|
|||
int mLevel;
|
||||
|
||||
SpellState mSpells;
|
||||
ActiveSpells mActiveSpells;
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
|
|
|
@ -108,6 +108,7 @@ enum RecNameInts
|
|||
REC_KEYS = FourCC<'K','E','Y','S'>::value,
|
||||
REC_DYNA = FourCC<'D','Y','N','A'>::value,
|
||||
REC_ASPL = FourCC<'A','S','P','L'>::value,
|
||||
REC_ACTC = FourCC<'A','C','T','C'>::value,
|
||||
|
||||
// format 1
|
||||
REC_FILT = 0x544C4946
|
||||
|
|
25
components/esm/doorstate.cpp
Normal file
25
components/esm/doorstate.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "doorstate.hpp"
|
||||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
||||
void DoorState::load(ESMReader &esm)
|
||||
{
|
||||
ObjectState::load(esm);
|
||||
|
||||
mDoorState = 0;
|
||||
esm.getHNOT (mDoorState, "ANIM");
|
||||
}
|
||||
|
||||
void DoorState::save(ESMWriter &esm, bool inInventory) const
|
||||
{
|
||||
ObjectState::save(esm, inInventory);
|
||||
|
||||
if (mDoorState != 0)
|
||||
esm.writeHNT ("ANIM", mDoorState);
|
||||
}
|
||||
|
||||
}
|
19
components/esm/doorstate.hpp
Normal file
19
components/esm/doorstate.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef OPENMW_ESM_DOORSTATE_H
|
||||
#define OPENMW_ESM_DOORSTATE_H
|
||||
|
||||
#include "objectstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
// format 0, saved games only
|
||||
|
||||
struct DoorState : public ObjectState
|
||||
{
|
||||
int mDoorState;
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -74,6 +74,18 @@ class ESMWriter
|
|||
endRecord(name);
|
||||
}
|
||||
|
||||
private:
|
||||
// Prevent using writeHNT with strings. This already happened by accident and results in
|
||||
// state being discarded without any error on writing or reading it. :(
|
||||
// writeHNString and friends must be used instead.
|
||||
void writeHNT(const std::string &name, std::string data)
|
||||
{
|
||||
}
|
||||
void writeT(const std::string& data)
|
||||
{
|
||||
}
|
||||
public:
|
||||
|
||||
template<typename T>
|
||||
void writeHNT(const std::string& name, const T& data, int size)
|
||||
{
|
||||
|
|
|
@ -140,7 +140,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const
|
|||
|
||||
for (std::vector<std::string>::const_iterator iter (mUsedIds.begin()); iter!=mUsedIds.end();
|
||||
++iter)
|
||||
esm.writeHNT ("USED", *iter);
|
||||
esm.writeHNString ("USED", *iter);
|
||||
|
||||
if (mTimeToStartDrowning)
|
||||
esm.writeHNT ("DRTI", mTimeToStartDrowning);
|
||||
|
|
|
@ -150,7 +150,7 @@ device =
|
|||
master volume = 1.0
|
||||
sfx volume = 1.0
|
||||
music volume = 0.4
|
||||
footsteps volume = 0.6
|
||||
footsteps volume = 0.15
|
||||
voice volume = 1.0
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace Physic
|
|||
PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale)
|
||||
: mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0)
|
||||
, mBody(0), mRaycastingBody(0), mOnGround(false), mCollisionMode(true), mBoxRotation(0,0,0,0)
|
||||
, mCollisionBody(true)
|
||||
, mForce(0.0f)
|
||||
{
|
||||
mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation);
|
||||
|
@ -49,8 +50,9 @@ namespace Physic
|
|||
void PhysicActor::enableCollisionBody(bool collision)
|
||||
{
|
||||
assert(mBody);
|
||||
if(collision && !mCollisionMode) enableCollisionBody();
|
||||
if(!collision && mCollisionMode) disableCollisionBody();
|
||||
if(collision && !mCollisionBody) enableCollisionBody();
|
||||
if(!collision && mCollisionBody) disableCollisionBody();
|
||||
mCollisionBody = collision;
|
||||
}
|
||||
|
||||
void PhysicActor::setPosition(const Ogre::Vector3 &pos)
|
||||
|
@ -108,7 +110,7 @@ namespace Physic
|
|||
//Create the newly scaled rigid body
|
||||
mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot);
|
||||
mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot, 0, 0, true);
|
||||
mEngine->addRigidBody(mBody, false, mRaycastingBody,true); //Add rigid body to dynamics world, but do not add to object map
|
||||
mEngine->addRigidBody(mCollisionBody ? mBody : 0, false, mRaycastingBody,true); //Add rigid body to dynamics world, but do not add to object map
|
||||
}
|
||||
|
||||
Ogre::Vector3 PhysicActor::getHalfExtents() const
|
||||
|
|
|
@ -175,6 +175,7 @@ namespace Physic
|
|||
Ogre::Vector3 mForce;
|
||||
bool mOnGround;
|
||||
bool mCollisionMode;
|
||||
bool mCollisionBody;
|
||||
|
||||
std::string mMesh;
|
||||
std::string mName;
|
||||
|
|
Loading…
Reference in a new issue