1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-03 21:45:34 +00:00

Refactor NpcAnimation: get rid of delayed update (no longer required), make sure that the Animation is set up *before* the inventory store is accessed anywhere (which now triggers auto equip and animation update). Allows better tracking of magic VFX for permanent enchantments in InventoryStore.

This commit is contained in:
scrawl 2013-11-14 14:41:10 +01:00
parent 956d8adb99
commit 992a8e9c36
19 changed files with 86 additions and 123 deletions

View file

@ -410,13 +410,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mVerboseScripts, *mScriptContext)); mVerboseScripts, *mScriptContext));
// Create game mechanics system // Create game mechanics system
mEnvironment.setMechanicsManager (new MWMechanics::MechanicsManager); MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager;
mEnvironment.setMechanicsManager (mechanics);
// Create dialog system // Create dialog system
mEnvironment.setJournal (new MWDialogue::Journal); mEnvironment.setJournal (new MWDialogue::Journal);
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage));
mEnvironment.getWorld()->renderPlayer(); mEnvironment.getWorld()->renderPlayer();
mechanics->buildPlayer();
window->updatePlayer();
if (!mNewGame) if (!mNewGame)
{ {

View file

@ -254,7 +254,7 @@ namespace MWClass
void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{ {
renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr)); renderingInterface.getActors().insertNPC(ptr);
} }
void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const

View file

@ -47,8 +47,6 @@ namespace MWGui
, mIngredients (4) , mIngredients (4)
, mSortModel(NULL) , mSortModel(NULL)
{ {
mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
getWidget(mCreateButton, "CreateButton"); getWidget(mCreateButton, "CreateButton");
getWidget(mCancelButton, "CancelButton"); getWidget(mCancelButton, "CancelButton");
getWidget(mIngredients[0], "Ingredient1"); getWidget(mIngredients[0], "Ingredient1");
@ -145,6 +143,8 @@ namespace MWGui
void AlchemyWindow::open() void AlchemyWindow::open()
{ {
mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
mSortModel = new SortFilterItemModel(model); mSortModel = new SortFilterItemModel(model);
mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients); mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients);

View file

@ -63,8 +63,6 @@ namespace MWGui
mItemView->eventItemClicked += MyGUI::newDelegate(this, &InventoryWindow::onItemSelected); mItemView->eventItemClicked += MyGUI::newDelegate(this, &InventoryWindow::onItemSelected);
mItemView->eventBackgroundClicked += MyGUI::newDelegate(this, &InventoryWindow::onBackgroundSelected); mItemView->eventBackgroundClicked += MyGUI::newDelegate(this, &InventoryWindow::onBackgroundSelected);
updatePlayer();
mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterWeapon->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); mFilterWeapon->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
@ -75,8 +73,6 @@ namespace MWGui
setCoord(mPositionInventory.left, mPositionInventory.top, mPositionInventory.width, mPositionInventory.height); setCoord(mPositionInventory.left, mPositionInventory.top, mPositionInventory.width, mPositionInventory.height);
onWindowResize(static_cast<MyGUI::Window*>(mMainWidget)); onWindowResize(static_cast<MyGUI::Window*>(mMainWidget));
mPreview.setup();
} }
void InventoryWindow::updatePlayer() void InventoryWindow::updatePlayer()

View file

@ -45,7 +45,6 @@ void ItemView::setModel(ItemModel *model)
{ {
delete mModel; delete mModel;
mModel = model; mModel = model;
update();
} }
void ItemView::initialiseOverride() void ItemView::initialiseOverride()

View file

@ -51,8 +51,6 @@ namespace MWGui
setCoord(498, 300, 302, 300); setCoord(498, 300, 302, 300);
updateSpells();
mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SpellWindow::onWindowResize); mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SpellWindow::onWindowResize);
} }

View file

@ -246,9 +246,6 @@ namespace MWGui
mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat<float>())); mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat<float>()));
} }
unsetSelectedSpell();
unsetSelectedWeapon();
// Set up visibility // Set up visibility
updateVisible(); updateVisible();
@ -1333,6 +1330,9 @@ namespace MWGui
void WindowManager::updatePlayer() void WindowManager::updatePlayer()
{ {
unsetSelectedSpell();
unsetSelectedWeapon();
mInventoryWindow->updatePlayer(); mInventoryWindow->updatePlayer();
} }

View file

@ -167,7 +167,7 @@ namespace MWMechanics
: mUpdatePlayer (true), mClassSelected (false), : mUpdatePlayer (true), mClassSelected (false),
mRaceSelected (false) mRaceSelected (false)
{ {
buildPlayer(); //buildPlayer no longer here, needs to be done explicitely after all subsystems are up and running
} }
void MechanicsManager::add(const MWWorld::Ptr& ptr) void MechanicsManager::add(const MWWorld::Ptr& ptr)

View file

@ -33,12 +33,12 @@ namespace MWMechanics
Objects mObjects; Objects mObjects;
Actors mActors; Actors mActors;
public:
void buildPlayer(); void buildPlayer();
///< build player according to stored class/race/birthsign information. Will ///< build player according to stored class/race/birthsign information. Will
/// default to the values of the ESM::NPC object, if no explicit information is given. /// default to the values of the ESM::NPC object, if no explicit information is given.
public:
MechanicsManager(); MechanicsManager();
virtual void add (const MWWorld::Ptr& ptr); virtual void add (const MWWorld::Ptr& ptr);

View file

@ -68,13 +68,16 @@ void Actors::insertBegin(const MWWorld::Ptr &ptr)
ptr.getRefData().setBaseNode(insert); ptr.getRefData().setBaseNode(insert);
} }
void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv) void Actors::insertNPC(const MWWorld::Ptr& ptr)
{ {
insertBegin(ptr); insertBegin(ptr);
NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), inv, RV_Actors); NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors);
delete mAllActors[ptr]; delete mAllActors[ptr];
mAllActors[ptr] = anim; mAllActors[ptr] = anim;
mRendering->addWaterRippleEmitter (ptr); mRendering->addWaterRippleEmitter (ptr);
// Create CustomData, will do autoEquip and trigger animation parts update
ptr.getClass().getInventoryStore(ptr);
} }
void Actors::insertCreature (const MWWorld::Ptr& ptr) void Actors::insertCreature (const MWWorld::Ptr& ptr)
{ {

View file

@ -39,7 +39,7 @@ namespace MWRender
void setRootNode(Ogre::SceneNode* root); void setRootNode(Ogre::SceneNode* root);
void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); void insertNPC(const MWWorld::Ptr& ptr);
void insertCreature (const MWWorld::Ptr& ptr); void insertCreature (const MWWorld::Ptr& ptr);
void insertActivator (const MWWorld::Ptr& ptr); void insertActivator (const MWWorld::Ptr& ptr);
bool deleteObject (const MWWorld::Ptr& ptr); bool deleteObject (const MWWorld::Ptr& ptr);

View file

@ -70,8 +70,9 @@ namespace MWRender
mNode = renderRoot->createChildSceneNode(); mNode = renderRoot->createChildSceneNode();
mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), mAnimation = new NpcAnimation(mCharacter, mNode,
0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal));
mAnimation->updateParts();
Ogre::Vector3 scale = mNode->getScale(); Ogre::Vector3 scale = mNode->getScale();
mCamera->setPosition(mPosition * scale); mCamera->setPosition(mPosition * scale);
@ -112,10 +113,9 @@ namespace MWRender
{ {
assert(mAnimation); assert(mAnimation);
delete mAnimation; delete mAnimation;
mAnimation = 0; mAnimation = new NpcAnimation(mCharacter, mNode,
mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter),
0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal));
mAnimation->updateParts();
float scale=1.f; float scale=1.f;
MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale);
@ -193,7 +193,7 @@ namespace MWRender
else if(mAnimation->getInfo("torch")) else if(mAnimation->getInfo("torch"))
mAnimation->disable("torch"); mAnimation->disable("torch");
mAnimation->updateParts(true); mAnimation->updateParts();
mAnimation->runAnimation(0.0f); mAnimation->runAnimation(0.0f);
mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024))); mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024)));

View file

@ -64,25 +64,11 @@ NpcAnimation::~NpcAnimation()
} }
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, ViewMode viewMode) NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags, ViewMode viewMode)
: Animation(ptr, node), : Animation(ptr, node),
mStateID(-1), mStateID(-1),
mTimeToChange(0),
mVisibilityFlags(visibilityFlags), mVisibilityFlags(visibilityFlags),
mRobe(inv.end()),
mHelmet(inv.end()),
mShirt(inv.end()),
mCuirass(inv.end()),
mGreaves(inv.end()),
mPauldronL(inv.end()),
mPauldronR(inv.end()),
mBoots(inv.end()),
mPants(inv.end()),
mGloveL(inv.end()),
mGloveR(inv.end()),
mSkirtIter(inv.end()),
mWeapon(inv.end()),
mShield(inv.end()),
mViewMode(viewMode), mViewMode(viewMode),
mShowWeapons(false), mShowWeapons(false),
mFirstPersonOffset(0.f, 0.f, 0.f) mFirstPersonOffset(0.f, 0.f, 0.f)
@ -94,8 +80,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
mPartslots[i] = -1; //each slot is empty mPartslots[i] = -1; //each slot is empty
mPartPriorities[i] = 0; mPartPriorities[i] = 0;
} }
updateNpcBase();
} }
void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
@ -173,56 +157,50 @@ void NpcAnimation::updateNpcBase()
for(size_t i = 0;i < ESM::PRT_Count;i++) for(size_t i = 0;i < ESM::PRT_Count;i++)
removeIndividualPart((ESM::PartReferenceType)i); removeIndividualPart((ESM::PartReferenceType)i);
updateParts(true); updateParts();
} }
void NpcAnimation::updateParts(bool forceupdate) void NpcAnimation::updateParts()
{ {
if (!mSkelBase)
{
// First update?
updateNpcBase();
return;
}
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
static const struct { static const struct {
MWWorld::ContainerStoreIterator NpcAnimation::*mPart;
int mSlot; int mSlot;
int mBasePriority; int mBasePriority;
} slotlist[] = { } slotlist[] = {
// FIXME: Priority is based on the number of reserved slots. There should be a better way. // FIXME: Priority is based on the number of reserved slots. There should be a better way.
{ &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe, 12 }, { MWWorld::InventoryStore::Slot_Robe, 12 },
{ &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt, 3 }, { MWWorld::InventoryStore::Slot_Skirt, 3 },
{ &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet, 0 }, { MWWorld::InventoryStore::Slot_Helmet, 0 },
{ &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass, 0 }, { MWWorld::InventoryStore::Slot_Cuirass, 0 },
{ &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves, 0 }, { MWWorld::InventoryStore::Slot_Greaves, 0 },
{ &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron, 0 }, { MWWorld::InventoryStore::Slot_LeftPauldron, 0 },
{ &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron, 0 }, { MWWorld::InventoryStore::Slot_RightPauldron, 0 },
{ &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots, 0 }, { MWWorld::InventoryStore::Slot_Boots, 0 },
{ &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet, 0 }, { MWWorld::InventoryStore::Slot_LeftGauntlet, 0 },
{ &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, 0 }, { MWWorld::InventoryStore::Slot_RightGauntlet, 0 },
{ &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, 0 }, { MWWorld::InventoryStore::Slot_Shirt, 0 },
{ &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants, 0 }, { MWWorld::InventoryStore::Slot_Pants, 0 },
{ &NpcAnimation::mShield, MWWorld::InventoryStore::Slot_CarriedLeft, 0 }, { MWWorld::InventoryStore::Slot_CarriedLeft, 0 },
{ &NpcAnimation::mWeapon, MWWorld::InventoryStore::Slot_CarriedRight, 0 } { MWWorld::InventoryStore::Slot_CarriedRight, 0 }
}; };
static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]);
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
for(size_t i = 0;!forceupdate && i < slotlistsize;i++)
{
MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].mSlot);
if(this->*slotlist[i].mPart != iter)
{
forceupdate = true;
break;
}
}
if(!forceupdate)
return;
for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++)
{ {
MWWorld::ContainerStoreIterator store = inv.getSlot(slotlist[i].mSlot); MWWorld::ContainerStoreIterator store = inv.getSlot(slotlist[i].mSlot);
this->*slotlist[i].mPart = store;
removePartGroup(slotlist[i].mSlot); removePartGroup(slotlist[i].mSlot);
if(this->*slotlist[i].mPart == inv.end()) if(store == inv.end())
continue; continue;
if(slotlist[i].mSlot == MWWorld::InventoryStore::Slot_Helmet) if(slotlist[i].mSlot == MWWorld::InventoryStore::Slot_Helmet)
@ -439,13 +417,6 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in
Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
{ {
if(mTimeToChange <= 0.0f)
{
mTimeToChange = 0.2f;
updateParts();
}
mTimeToChange -= timepassed;
Ogre::Vector3 ret = Animation::runAnimation(timepassed); Ogre::Vector3 ret = Animation::runAnimation(timepassed);
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
@ -599,11 +570,10 @@ void NpcAnimation::showWeapons(bool showWeapon)
if(showWeapon) if(showWeapon)
{ {
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if(mWeapon != inv.end()) // special case for weapons if(weapon != inv.end()) // special case for weapons
{ {
MWWorld::Ptr weapon = *mWeapon; std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
std::string mesh = MWWorld::Class::get(weapon).getModel(weapon);
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh); addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh);
} }
} }

View file

@ -43,22 +43,6 @@ private:
ViewMode mViewMode; ViewMode mViewMode;
bool mShowWeapons; bool mShowWeapons;
float mTimeToChange;
MWWorld::ContainerStoreIterator mRobe;
MWWorld::ContainerStoreIterator mHelmet;
MWWorld::ContainerStoreIterator mShirt;
MWWorld::ContainerStoreIterator mCuirass;
MWWorld::ContainerStoreIterator mGreaves;
MWWorld::ContainerStoreIterator mPauldronL;
MWWorld::ContainerStoreIterator mPauldronR;
MWWorld::ContainerStoreIterator mBoots;
MWWorld::ContainerStoreIterator mPants;
MWWorld::ContainerStoreIterator mGloveL;
MWWorld::ContainerStoreIterator mGloveR;
MWWorld::ContainerStoreIterator mSkirtIter;
MWWorld::ContainerStoreIterator mWeapon;
MWWorld::ContainerStoreIterator mShield;
int mVisibilityFlags; int mVisibilityFlags;
int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty
@ -78,8 +62,7 @@ private:
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts); void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts);
public: public:
NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int visibilityFlags,
MWWorld::InventoryStore& inv, int visibilityFlags,
ViewMode viewMode=VM_Normal); ViewMode viewMode=VM_Normal);
virtual ~NpcAnimation(); virtual ~NpcAnimation();
@ -89,7 +72,7 @@ public:
void setViewMode(ViewMode viewMode); void setViewMode(ViewMode viewMode);
void updateParts(bool forceupdate = false); void updateParts();
/// \brief Applies a translation to the arms and hands. /// \brief Applies a translation to the arms and hands.
/// This may be called multiple times before the animation /// This may be called multiple times before the animation

View file

@ -336,6 +336,7 @@ void RenderingManager::updateAnimParts(const MWWorld::Ptr& ptr)
else if(MWWorld::Class::get(ptr).isActor()) else if(MWWorld::Class::get(ptr).isActor())
anim = dynamic_cast<NpcAnimation*>(mActors.getAnimation(ptr)); anim = dynamic_cast<NpcAnimation*>(mActors.getAnimation(ptr));
assert(anim);
if(anim) if(anim)
anim->updateParts(); anim->updateParts();
} }
@ -926,18 +927,17 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr)
{ {
if(!mPlayerAnimation) if(!mPlayerAnimation)
{ {
mPlayerAnimation = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), mPlayerAnimation = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors);
MWWorld::Class::get(ptr).getInventoryStore(ptr),
RV_Actors);
} }
else else
{ {
// Reconstruct the NpcAnimation in-place // Reconstruct the NpcAnimation in-place
mPlayerAnimation->~NpcAnimation(); mPlayerAnimation->~NpcAnimation();
new(mPlayerAnimation) NpcAnimation(ptr, ptr.getRefData().getBaseNode(), new(mPlayerAnimation) NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors);
MWWorld::Class::get(ptr).getInventoryStore(ptr),
RV_Actors);
} }
// Ensure CustomData -> autoEquip -> animation update
ptr.getClass().getInventoryStore(ptr);
mCamera->setAnimation(mPlayerAnimation); mCamera->setAnimation(mPlayerAnimation);
mWater->removeEmitter(ptr); mWater->removeEmitter(ptr);
mWater->addEmitter(ptr); mWater->addEmitter(ptr);

View file

@ -45,6 +45,7 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_)
MWWorld::InventoryStore::InventoryStore() MWWorld::InventoryStore::InventoryStore()
: mSelectedEnchantItem(end()) : mSelectedEnchantItem(end())
, mUpdatesEnabled (true) , mUpdatesEnabled (true)
, mFirstAutoEquip(true)
{ {
initSlots (mSlots); initSlots (mSlots);
} }
@ -54,6 +55,7 @@ MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
, mSelectedEnchantItem(end()) , mSelectedEnchantItem(end())
{ {
mMagicEffects = store.mMagicEffects; mMagicEffects = store.mMagicEffects;
mFirstAutoEquip = store.mFirstAutoEquip;
mSelectedEnchantItem = store.mSelectedEnchantItem; mSelectedEnchantItem = store.mSelectedEnchantItem;
mPermanentMagicEffectMagnitudes = store.mPermanentMagicEffectMagnitudes; mPermanentMagicEffectMagnitudes = store.mPermanentMagicEffectMagnitudes;
copySlots (store); copySlots (store);
@ -62,6 +64,7 @@ MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStore& store) MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStore& store)
{ {
mMagicEffects = store.mMagicEffects; mMagicEffects = store.mMagicEffects;
mFirstAutoEquip = store.mFirstAutoEquip;
mPermanentMagicEffectMagnitudes = store.mPermanentMagicEffectMagnitudes; mPermanentMagicEffectMagnitudes = store.mPermanentMagicEffectMagnitudes;
ContainerStore::operator= (store); ContainerStore::operator= (store);
mSlots.clear(); mSlots.clear();
@ -256,6 +259,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc)
updateMagicEffects(npc); updateMagicEffects(npc);
flagAsModified(); flagAsModified();
} }
mFirstAutoEquip = false;
} }
const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects() const const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects() const
@ -308,8 +312,10 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
// so it doesn't really matter if both items will get the same magnitude. *Extreme* edge case. // so it doesn't really matter if both items will get the same magnitude. *Extreme* edge case.
mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID] = random; mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID] = random;
// TODO: What do we do if no animation yet? // During first auto equip, we don't play any sounds.
if (MWBase::Environment::get().getWorld()->getAnimation(actor)) // Basically we don't want sounds when the actor is first loaded,
// the items should appear as if they'd always been equipped.
if (!mFirstAutoEquip)
{ {
// Only the sound of the first effect plays // Only the sound of the first effect plays
if (effectIt == enchantment.mEffects.mList.begin()) if (effectIt == enchantment.mEffects.mList.begin())
@ -324,13 +330,15 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
else else
sndMgr->playSound3D(actor, schools[magicEffect->mData.mSchool]+" hit", 1.0f, 1.0f); sndMgr->playSound3D(actor, schools[magicEffect->mData.mSchool]+" hit", 1.0f, 1.0f);
} }
}
if (!magicEffect->mHit.empty()) if (!magicEffect->mHit.empty())
{ {
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit); const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx; bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
// Similar as above, we don't want particles during first autoequip either, unless they're continuous.
if (!mFirstAutoEquip || loop)
MWBase::Environment::get().getWorld()->getAnimation(actor)->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); MWBase::Environment::get().getWorld()->getAnimation(actor)->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
}
} }
} }

View file

@ -49,6 +49,8 @@ namespace MWWorld
// This is disabled during autoequip to avoid excessive updates // This is disabled during autoequip to avoid excessive updates
bool mUpdatesEnabled; bool mUpdatesEnabled;
bool mFirstAutoEquip;
// Vanilla allows permanent effects with a random magnitude, so it needs to be stored here. // Vanilla allows permanent effects with a random magnitude, so it needs to be stored here.
// We also need this to only play sounds and particle effects when the item is equipped, rather than on every update. // We also need this to only play sounds and particle effects when the item is equipped, rather than on every update.
typedef std::map<std::string, std::vector<float> > TEffectMagnitudes; typedef std::map<std::string, std::vector<float> > TEffectMagnitudes;

View file

@ -118,8 +118,6 @@ namespace MWWorld
void Scene::loadCell (Ptr::CellStore *cell, Loading::Listener* loadingListener) void Scene::loadCell (Ptr::CellStore *cell, Loading::Listener* loadingListener)
{ {
// register local scripts
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);
std::pair<CellStoreCollection::iterator, bool> result = mActiveCells.insert(cell); std::pair<CellStoreCollection::iterator, bool> result = mActiveCells.insert(cell);
if(result.second) if(result.second)
@ -157,6 +155,10 @@ namespace MWWorld
mRendering.requestMap(cell); mRendering.requestMap(cell);
mRendering.configureAmbient(*cell); mRendering.configureAmbient(*cell);
} }
// register local scripts
// ??? Should this go into the above if block ???
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);
} }
void Scene::playerCellChange(MWWorld::CellStore *cell, const ESM::Position& pos, bool adjustPlayerPos) void Scene::playerCellChange(MWWorld::CellStore *cell, const ESM::Position& pos, bool adjustPlayerPos)

View file

@ -2239,7 +2239,6 @@ namespace MWWorld
void World::updateAnimParts(const Ptr& actor) void World::updateAnimParts(const Ptr& actor)
{ {
if (actor.mCell && actor.mCell == mWorldScene->getCurrentCell()) mRendering->updateAnimParts(actor);
mRendering->updateAnimParts(actor);
} }
} }