diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 29381eb42..8b4946308 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -241,7 +241,7 @@ namespace MWBase virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; - virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0; + virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index c8e09d433..f3f36542a 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -169,7 +169,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mValue; + if (ptr.getCellRef().mCharge == -1) + return ref->mBase->mData.mValue; + else + return ref->mBase->mData.mValue * (ptr.getCellRef().mCharge / getItemMaxHealth(ptr)); } void Armor::registerSelf() @@ -281,6 +284,7 @@ namespace MWClass newItem.mEnchant=enchId; const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); ref->mBase = record; + ref->mRef.mRefID = record->mId; } std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index a692b30d8..b22cbc31f 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -171,6 +171,7 @@ namespace MWClass newItem.mEnchant=enchId; const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); ref->mBase = record; + ref->mRef.mRefID = record->mId; } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 0a23821a9..8941f3627 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -227,6 +227,7 @@ namespace MWClass newItem.mEnchant=enchId; const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); ref->mBase = record; + ref->mRef.mRefID = record->mId; } std::pair Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 20f95ab0e..983480782 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -98,6 +98,8 @@ namespace MWClass data->mContainerStore.fill(ref->mBase->mInventory, getId(ptr), MWBase::Environment::get().getWorld()->getStore()); + data->mContainerStore.add("gold_001", ref->mBase->mData.mGold, ptr); + // store ptr.getRefData().setCustomData (data.release()); } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index f629cc15d..06d9d5d23 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -156,6 +156,9 @@ namespace MWClass MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player); int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); + static const float fWortChanceValue = + MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->getFloat(); + MWGui::Widgets::SpellEffectList list; for (int i=0; i<4; ++i) { @@ -166,10 +169,10 @@ namespace MWClass params.mAttribute = ref->mBase->mData.mAttributes[i]; params.mSkill = ref->mBase->mData.mSkills[i]; - params.mKnown = ( (i == 0 && alchemySkill >= 15) - || (i == 1 && alchemySkill >= 30) - || (i == 2 && alchemySkill >= 45) - || (i == 3 && alchemySkill >= 60)); + params.mKnown = ( (i == 0 && alchemySkill >= fWortChanceValue) + || (i == 1 && alchemySkill >= fWortChanceValue*2) + || (i == 2 && alchemySkill >= fWortChanceValue*3) + || (i == 3 && alchemySkill >= fWortChanceValue*4)); list.push_back(params); } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index aff36ba81..73b47d6af 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -86,7 +86,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mValue; + if (ptr.getCellRef().mCharge == -1) + return ref->mBase->mData.mValue; + else + return ref->mBase->mData.mValue * (ptr.getCellRef().mCharge / getItemMaxHealth(ptr)); } void Lockpick::registerSelf() diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e9182d094..6970e8646 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -184,8 +184,11 @@ namespace MWClass } // creature stats + int gold=0; if(ref->mBase->mNpdt52.mGold != -10) { + gold = ref->mBase->mNpdt52.mGold; + for (int i=0; i<27; ++i) data->mNpcStats.getSkill (i).setBase (ref->mBase->mNpdt52.mSkills[i]); @@ -207,6 +210,8 @@ namespace MWClass } else { + gold = ref->mBase->mNpdt12.mGold; + for (int i=0; i<3; ++i) data->mNpcStats.setDynamic (i, 10); @@ -236,6 +241,8 @@ namespace MWClass // store ptr.getRefData().setCustomData (data.release()); + getContainerStore(ptr).add("gold_001", gold, ptr); + getInventoryStore(ptr).autoEquip(ptr); } } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 2f9e63d13..883473eb3 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -137,13 +137,14 @@ namespace MWClass MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player); int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); int i=0; + static const float fWortChanceValue = + MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->getFloat(); for (MWGui::Widgets::SpellEffectList::iterator it = info.effects.begin(); it != info.effects.end(); ++it) { - /// \todo this code is duplicated from mwclass/ingredient, put it in a helper function - it->mKnown = ( (i == 0 && alchemySkill >= 15) - || (i == 1 && alchemySkill >= 30) - || (i == 2 && alchemySkill >= 45) - || (i == 3 && alchemySkill >= 60)); + it->mKnown = ( (i == 0 && alchemySkill >= fWortChanceValue) + || (i == 1 && alchemySkill >= fWortChanceValue*2) + || (i == 2 && alchemySkill >= fWortChanceValue*3) + || (i == 3 && alchemySkill >= fWortChanceValue*4)); ++i; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 5cff140a6..845c2a0d0 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -85,7 +85,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mValue; + if (ptr.getCellRef().mCharge == -1) + return ref->mBase->mData.mValue; + else + return ref->mBase->mData.mValue * (ptr.getCellRef().mCharge / getItemMaxHealth(ptr)); } void Probe::registerSelf() diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 38c15ac92..dbfa9f0f6 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -76,7 +76,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mValue; + if (ptr.getCellRef().mCharge == -1) + return ref->mBase->mData.mValue; + else + return ref->mBase->mData.mValue * (ptr.getCellRef().mCharge / getItemMaxHealth(ptr)); } void Repair::registerSelf() diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index eaed597fc..b1bf2b0b7 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -154,7 +154,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mValue; + if (ptr.getCellRef().mCharge == -1) + return ref->mBase->mData.mValue; + else + return ref->mBase->mData.mValue * (ptr.getCellRef().mCharge / getItemMaxHealth(ptr)); } void Weapon::registerSelf() @@ -370,16 +373,17 @@ namespace MWClass void Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); - ESM::Weapon newItem = *ref->mBase; - newItem.mId=""; - newItem.mName=newName; - newItem.mData.mEnchant=enchCharge; - newItem.mEnchant=enchId; - const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - ref->mBase = record; + ESM::Weapon newItem = *ref->mBase; + newItem.mId=""; + newItem.mName=newName; + newItem.mData.mEnchant=enchCharge; + newItem.mEnchant=enchId; + const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); + ref->mBase = record; + ref->mRef.mRefID = record->mId; } std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index c9a780691..71995f97f 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -12,6 +12,8 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwdialogue/dialoguemanagerimp.hpp" @@ -67,23 +69,24 @@ namespace MWGui void PersuasionDialog::onPersuade(MyGUI::Widget *sender) { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWBase::MechanicsManager::PersuasionType type; if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; else if (sender == mBribe10Button) { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); + player.getClass().getContainerStore(player).remove("gold_001", 10, player); type = MWBase::MechanicsManager::PT_Bribe10; } else if (sender == mBribe100Button) { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); + player.getClass().getContainerStore(player).remove("gold_001", 100, player); type = MWBase::MechanicsManager::PT_Bribe100; } else /*if (sender == mBribe1000Button)*/ { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); + player.getClass().getContainerStore(player).remove("gold_001", 1000, player); type = MWBase::MechanicsManager::PT_Bribe1000; } diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 530594dda..4da166820 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -13,7 +13,6 @@ #include "../mwworld/containerstore.hpp" #include "inventorywindow.hpp" -#include "tradewindow.hpp" namespace MWGui { @@ -119,7 +118,9 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); int price = boost::lexical_cast(sender->getUserString("Price")); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + player.getClass().getContainerStore(player).remove("gold_001", price, player); startRepair(mActor); } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index a7fcfdd02..bbd28b2de 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -10,11 +10,11 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwmechanics/creaturestats.hpp" #include "inventorywindow.hpp" -#include "tradewindow.hpp" namespace MWGui { @@ -123,7 +123,7 @@ namespace MWGui MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); spells.add (mSpellsWidgetMap.find(_sender)->second); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); + player.getClass().getContainerStore(player).remove("gold_001", price, player); startSpellBuying(mPtr); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index e0b808b28..b9324fea1 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -8,13 +8,13 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwmechanics/spellcasting.hpp" #include "tooltips.hpp" #include "class.hpp" #include "inventorywindow.hpp" -#include "tradewindow.hpp" namespace { @@ -342,13 +342,14 @@ namespace MWGui mSpell.mName = mNameEdit->getCaption(); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-boost::lexical_cast(mPriceLabel->getCaption())); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + player.getClass().getContainerStore(player).remove("gold_001", boost::lexical_cast(mPriceLabel->getCaption()), player); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); const ESM::Spell* spell = MWBase::Environment::get().getWorld()->createRecord(mSpell); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); spells.add (spell->mId); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 65e3917ed..636b8ae9b 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -203,19 +203,17 @@ namespace MWGui sellToNpc(item.mBase, count, true); } - void TradeWindow::addOrRemoveGold(int amount) + void TradeWindow::addOrRemoveGold(int amount, const MWWorld::Ptr& actor) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); + MWWorld::ContainerStore& store = MWWorld::Class::get(actor).getContainerStore(actor); if (amount > 0) { - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001", amount); - playerStore.add(ref.getPtr(), player); + store.add("gold_001", amount, actor); } else { - playerStore.remove("gold_001", - amount, player); + store.remove("gold_001", - amount, actor); } } @@ -270,6 +268,8 @@ namespace MWGui return; } + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(mCurrentBalance > mCurrentMerchantOffer) { //if npc is a creature: reject (no haggle) @@ -292,7 +292,6 @@ namespace MWGui + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); const MWMechanics::NpcStats &sellerStats = MWWorld::Class::get(mPtr).getNpcStats(mPtr); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); const MWMechanics::NpcStats &playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); float a1 = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); @@ -332,9 +331,12 @@ namespace MWGui mTradeModel->transferItems(); playerItemModel->transferItems(); - // add or remove gold from the player. + // transfer the gold if (mCurrentBalance != 0) - addOrRemoveGold(mCurrentBalance); + { + addOrRemoveGold(mCurrentBalance, playerPtr); + addOrRemoveGold(-mCurrentBalance, mPtr); + } std::string sound = "Item Gold Up"; MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); @@ -435,22 +437,13 @@ namespace MWGui int TradeWindow::getMerchantGold() { - int merchantGold; - - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + int merchantGold = 0; + MWWorld::ContainerStore store = mPtr.getClass().getContainerStore(mPtr); + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mNpdt52.mGold == -10) - merchantGold = ref->mBase->mNpdt12.mGold; - else - merchantGold = ref->mBase->mNpdt52.mGold; + if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) + merchantGold += it->getRefData().getCount(); } - else // ESM::Creature - { - MWWorld::LiveCellRef* ref = mPtr.get(); - merchantGold = ref->mBase->mData.mGold; - } - return merchantGold; } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 4e905915a..7c11bd539 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -28,7 +28,7 @@ namespace MWGui void startTrade(const MWWorld::Ptr& actor); - void addOrRemoveGold(int gold); + void addOrRemoveGold(int gold, const MWWorld::Ptr& actor); void onFrame(float frameDuration); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 7ddac38f5..04eddcb17 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -11,11 +11,11 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwmechanics/npcstats.hpp" #include "inventorywindow.hpp" -#include "tradewindow.hpp" #include "tooltips.hpp" namespace MWGui @@ -142,7 +142,7 @@ namespace MWGui pcStats.increaseSkill (skillId, *class_, true); // remove gold - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); + player.getClass().getContainerStore(player).remove("gold_001", price, player); // go back to game mode MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 93ac8299d..dd5da4522 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -11,9 +11,9 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/containerstore.hpp" #include "inventorywindow.hpp" -#include "tradewindow.hpp" namespace MWGui { @@ -121,13 +121,15 @@ namespace MWGui int price; iss >> price; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if (MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()getTradeWindow ()->addOrRemoveGold (-price); + + player.getClass().getContainerStore(player).remove("gold_001", price, player); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); ESM::Position pos = *_sender->getUserData(); std::string cellname = _sender->getUserString("Destination"); int x,y; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index b9a56e30c..5aa846118 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -12,6 +12,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/manualref.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -27,6 +29,25 @@ #include "aicombat.hpp" +namespace +{ + +void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& actor) +{ + if (bound) + { + MWWorld::Ptr newPtr = *actor.getClass().getContainerStore(actor).add(item, 1, actor); + MWWorld::ActionEquip action(newPtr); + action.execute(actor); + } + else + { + actor.getClass().getContainerStore(actor).remove(item, 1, actor); + } +} + +} + namespace MWMechanics { void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) @@ -247,6 +268,118 @@ namespace MWMechanics } creatureStats.setHealth(health); + + // TODO: dirty flag for magic effects to avoid some unnecessary work below? + + // Update bound effects + static std::map boundItemsMap; + if (boundItemsMap.empty()) + { + boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "battle_axe"; + boundItemsMap[ESM::MagicEffect::BoundBoots] = "boots"; + boundItemsMap[ESM::MagicEffect::BoundCuirass] = "cuirass"; + boundItemsMap[ESM::MagicEffect::BoundDagger] = "dagger"; + boundItemsMap[ESM::MagicEffect::BoundGloves] = "gauntlet"; // Note: needs both _left and _right variants, see below + boundItemsMap[ESM::MagicEffect::BoundHelm] = "helm"; + boundItemsMap[ESM::MagicEffect::BoundLongbow] = "longbow"; + boundItemsMap[ESM::MagicEffect::BoundLongsword] = "longsword"; + boundItemsMap[ESM::MagicEffect::BoundMace] = "mace"; + boundItemsMap[ESM::MagicEffect::BoundShield] = "shield"; + boundItemsMap[ESM::MagicEffect::BoundSpear] = "spear"; + } + + for (std::map::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) + { + bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); + int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude; + if (found != (magnitude > 0)) + { + std::string item = "bound_" + it->second; + if (it->first == ESM::MagicEffect::BoundGloves) + { + adjustBoundItem(item + "_left", magnitude > 0, ptr); + adjustBoundItem(item + "_right", magnitude > 0, ptr); + } + else + adjustBoundItem(item, magnitude > 0, ptr); + + if (magnitude > 0) + creatureStats.mBoundItems.insert(it->first); + else + creatureStats.mBoundItems.erase(it->first); + } + } + + // Update summon effects + static std::map summonMap; + if (summonMap.empty()) + { + summonMap[ESM::MagicEffect::SummonAncestralGhost] = "ancestor_ghost_summon"; + summonMap[ESM::MagicEffect::SummonBear] = "BM_bear_black_summon"; + summonMap[ESM::MagicEffect::SummonBonelord] = "bonelord_summon"; + summonMap[ESM::MagicEffect::SummonBonewalker] = "bonewalker_summon"; + summonMap[ESM::MagicEffect::SummonBonewolf] = "BM_wolf_bone_summon"; + summonMap[ESM::MagicEffect::SummonCenturionSphere] = "centurion_sphere_summon"; + summonMap[ESM::MagicEffect::SummonClannfear] = "clannfear_summon"; + summonMap[ESM::MagicEffect::SummonDaedroth] = "daedroth_summon"; + summonMap[ESM::MagicEffect::SummonDremora] = "dremora_summon"; + summonMap[ESM::MagicEffect::SummonFabricant] = "fabricant_summon"; + summonMap[ESM::MagicEffect::SummonFlameAtronach] = "atronach_flame_summon"; + summonMap[ESM::MagicEffect::SummonFrostAtronach] = "atronach_frost_summon"; + summonMap[ESM::MagicEffect::SummonGoldenSaint] = "golden saint_summon"; + summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "bonewalker_greater_summ"; + summonMap[ESM::MagicEffect::SummonHunger] = "hunger_summon"; + summonMap[ESM::MagicEffect::SummonScamp] = "scamp_summon"; + summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "skeleton_summon"; + summonMap[ESM::MagicEffect::SummonStormAtronach] = "atronach_storm_summon"; + summonMap[ESM::MagicEffect::SummonWingedTwilight] = "winged twilight_summon"; + summonMap[ESM::MagicEffect::SummonWolf] = "BM_wolf_grey_summon"; + } + + for (std::map::iterator it = summonMap.begin(); it != summonMap.end(); ++it) + { + bool found = creatureStats.mSummonedCreatures.find(it->first) != creatureStats.mSummonedCreatures.end(); + int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude; + if (found != (magnitude > 0)) + { + if (magnitude > 0) + { + ESM::Position ipos = ptr.getRefData().getPosition(); + Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); + Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); + const float distance = 50; + pos = pos + distance*rot.yAxis(); + ipos.pos[0] = pos.x; + ipos.pos[1] = pos.y; + ipos.pos[2] = pos.z; + ipos.rot[0] = 0; + ipos.rot[1] = 0; + ipos.rot[2] = 0; + + MWWorld::CellStore* store = ptr.getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->second, 1); + ref.getPtr().getCellRef().mPos = ipos; + + // TODO: Add AI to follow player and fight for him + + creatureStats.mSummonedCreatures.insert(std::make_pair(it->first, + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle())); + + } + 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); + if (!ptr.isEmpty()) + { + MWBase::Environment::get().getWorld()->deleteObject(ptr); + creatureStats.mSummonedCreatures.erase(it->first); + } + } + } + } } void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 82580ce0e..f994c28b8 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -287,8 +287,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) record = MWBase::Environment::get().getWorld()->createRecord (newRecord); } - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - MWWorld::Class::get (mAlchemist).getContainerStore (mAlchemist).add (ref.getPtr(), mAlchemist); + mAlchemist.getClass().getContainerStore (mAlchemist).add (record->mId, 1, mAlchemist); } void MWMechanics::Alchemy::increaseSkill() diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 126b0685f..f28f50fc6 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -171,6 +171,11 @@ 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? + std::set mBoundItems; + // Same as above + std::map mSummonedCreatures; }; } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index ba53a1a72..7e11acdb0 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -62,10 +62,7 @@ namespace MWMechanics //Exception for Azura Star, new one will be added after enchanting if(boost::iequals(mSoulGemPtr.get()->mBase->mId, "Misc_SoulGem_Azura")) - { - MWWorld::ManualRef azura (MWBase::Environment::get().getWorld()->getStore(), "Misc_SoulGem_Azura"); - store.add(azura.getPtr(), player); - } + store.add("Misc_SoulGem_Azura", 1, player); if(mSelfEnchanting) { @@ -92,8 +89,8 @@ namespace MWMechanics MWWorld::Class::get(newItemPtr).applyEnchantment(newItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName); // Add the new item to player inventory and remove the old one - store.add(newItemPtr, player); store.remove(mOldItemPtr, 1, player); + store.add(newItemPtr, player); if(!mSelfEnchanting) payForEnchantment(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8acc9866a..ff13841a2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -419,7 +419,7 @@ namespace MWMechanics MWWorld::LiveCellRef* player = playerPtr.get(); const MWMechanics::NpcStats &playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); - if (Misc::StringUtils::lowerCase(npc->mBase->mRace) == Misc::StringUtils::lowerCase(player->mBase->mRace)) + if (Misc::StringUtils::ciEqual(npc->mBase->mRace, player->mBase->mRace)) x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispRaceMod")->getFloat(); x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispPersonalityMult")->getFloat() @@ -435,7 +435,9 @@ namespace MWMechanics for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.begin(); it != MWBase::Environment::get().getWorld()->getStore().get().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.end(); ++it) { - if(Misc::StringUtils::lowerCase(it->mFaction) == Misc::StringUtils::lowerCase(npcFaction)) reaction = it->mReaction; + if(Misc::StringUtils::lowerCase(it->mFaction) == Misc::StringUtils::lowerCase(npcFaction) + && playerStats.getExpelled().find(Misc::StringUtils::lowerCase(it->mFaction)) == playerStats.getExpelled().end()) + reaction = it->mReaction; } rank = playerStats.getFactionRanks().find(Misc::StringUtils::lowerCase(npcFaction))->second; } @@ -446,7 +448,8 @@ namespace MWMechanics { if(playerStats.getFactionRanks().find(Misc::StringUtils::lowerCase(it->mFaction)) != playerStats.getFactionRanks().end() ) { - if(it->mReactionmReaction; + if(it->mReaction < reaction) + reaction = it->mReaction; } } rank = 0; diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index d124eca48..53f4c23c9 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -17,7 +17,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/actionequip.hpp" @@ -53,24 +52,14 @@ namespace MWScript if (count == 0) return; - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item, count); - - // Configure item's script variables - std::string script = MWWorld::Class::get(ref.getPtr()).getScript(ref.getPtr()); - if (script != "") - { - const ESM::Script *esmscript = MWBase::Environment::get().getWorld()->getStore().get().find (script); - ref.getPtr().getRefData().setLocals(*esmscript); - } - - MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr(), ptr); + MWWorld::Ptr itemPtr = *ptr.getClass().getContainerStore (ptr).add (item, count, ptr); // Spawn a messagebox (only for items added to player's inventory and if player is talking to someone) if (ptr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer() ) { // The two GMST entries below expand to strings informing the player of what, and how many of it has been added to their inventory std::string msgBox; - std::string itemName = MWWorld::Class::get(ref.getPtr()).getName(ref.getPtr()); + std::string itemName = itemPtr.getClass().getName(itemPtr); if (count == 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 35f7a4044..8e2a8af8c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -19,7 +19,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" #include "../mwworld/containerstore.hpp" #include "../mwmechanics/npcstats.hpp" @@ -348,12 +347,8 @@ namespace MWScript const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); store.get().find(creature); // This line throws an exception if it can't find the creature - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), gem, 1); - - ref.getPtr().getCellRef().mSoul = creature; - - MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr(), ptr); - + MWWorld::Ptr item = *ptr.getClass().getContainerStore(ptr).add(gem, 1, ptr); + item.getCellRef().mSoul = creature; } }; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index be2e0b5a3..d1d16ee01 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -118,6 +118,12 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) || cls2.getItemMaxHealth(ptr2) == ptr2.getCellRef().mCharge); } +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string &id, int count, const Ptr &actorPtr) +{ + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count); + return add(ref.getPtr(), actorPtr); +} + MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr, const Ptr& actorPtr) { MWWorld::ContainerStoreIterator it = addImp(itemPtr); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index c430b4bfc..df7168dfa 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -74,6 +74,9 @@ namespace MWWorld /// /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. + ContainerStoreIterator add(const std::string& id, int count, const Ptr& actorPtr); + ///< Utility to construct a ManualRef and call add(ptr, actorPtr) + int remove(const std::string& itemId, int count, const Ptr& actor); ///< Remove \a count item(s) designated by \a itemId from this container. /// diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 33cc03f9f..0ad06cf26 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1084,9 +1084,9 @@ namespace MWWorld adjust); } - void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) + MWWorld::Ptr World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) { - copyObjectToCell(ptr,Cell,pos); + return copyObjectToCell(ptr,Cell,pos); } void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const @@ -1967,23 +1967,13 @@ namespace MWWorld if(werewolf) { - ManualRef ref(getStore(), "WerewolfRobe"); + InventoryStore &inv = actor.getClass().getInventoryStore(actor); - // Configure item's script variables - std::string script = Class::get(ref.getPtr()).getScript(ref.getPtr()); - if(script != "") - { - const ESM::Script *esmscript = getStore().get().find(script); - ref.getPtr().getRefData().setLocals(*esmscript); - } - - // Not sure this is right - InventoryStore &inv = Class::get(actor).getInventoryStore(actor); - inv.equip(InventoryStore::Slot_Robe, inv.add(ref.getPtr(), actor), actor); + inv.equip(InventoryStore::Slot_Robe, inv.ContainerStore::add("WerewolfRobe", 1, actor), actor); } else { - Class::get(actor).getContainerStore(actor).remove("WerewolfRobe", 1, actor); + actor.getClass().getContainerStore(actor).remove("WerewolfRobe", 1, actor); } if(actor.getRefData().getHandle() == "player") diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7ccea2502..1022a74fe 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -302,7 +302,7 @@ namespace MWWorld virtual void localRotateObject (const Ptr& ptr, float x, float y, float z); - virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos); + virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)