Issue #777: Create InventoryStore for creatures with weapons/shields

actorid
scrawl 11 years ago
parent 69ca03c308
commit 589fbbd871

@ -289,7 +289,7 @@ namespace MWClass
std::pair<int, std::string> Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{
MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc);
MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc);
if (ptr.getCellRef().mCharge == 0)
return std::make_pair(0, "#{sInventoryMessage1}");
@ -300,20 +300,23 @@ namespace MWClass
if (slots_.first.empty())
return std::make_pair(0, "");
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
if (npc.getClass().isNpc())
{
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts;
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{
if((*itr).mPart == ESM::PRT_Head)
return std::make_pair(0, "#{sNotifyMessage13}");
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
return std::make_pair(0, "#{sNotifyMessage14}");
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts;
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_Head)
return std::make_pair(0, "#{sNotifyMessage13}");
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
return std::make_pair(0, "#{sNotifyMessage14}");
}
}
}

@ -238,20 +238,23 @@ namespace MWClass
if (slots_.first.empty())
return std::make_pair(0, "");
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
if (npc.getClass().isNpc())
{
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts;
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{
if((*itr).mPart == ESM::PRT_Head)
return std::make_pair(0, "#{sNotifyMessage13}");
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
return std::make_pair(0, "#{sNotifyMessage15}");
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts;
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_Head)
return std::make_pair(0, "#{sNotifyMessage13}");
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
return std::make_pair(0, "#{sNotifyMessage15}");
}
}
}

@ -26,6 +26,8 @@
#include "../mwgui/tooltips.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwmechanics/npcstats.hpp"
namespace
@ -33,15 +35,20 @@ namespace
struct CustomData : public MWWorld::CustomData
{
MWMechanics::CreatureStats mCreatureStats;
MWWorld::ContainerStore mContainerStore;
MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures
MWMechanics::Movement mMovement;
virtual MWWorld::CustomData *clone() const;
CustomData() : mContainerStore(0) {}
virtual ~CustomData() { delete mContainerStore; }
};
MWWorld::CustomData *CustomData::clone() const
{
return new CustomData (*this);
CustomData* cloned = new CustomData (*this);
cloned->mContainerStore = mContainerStore->clone();
return cloned;
}
}
@ -106,15 +113,23 @@ namespace MWClass
data->mCreatureStats.getSpells().add (*iter);
// inventory
data->mContainerStore.fill(ref->mBase->mInventory, getId(ptr), "",
if (ref->mBase->mFlags & ESM::Creature::Weapon)
data->mContainerStore = new MWWorld::InventoryStore();
else
data->mContainerStore = new MWWorld::ContainerStore();
// store
ptr.getRefData().setCustomData (data.release());
getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "",
MWBase::Environment::get().getWorld()->getStore());
// TODO: this is not quite correct, in vanilla the merchant's gold pool is not available in his inventory.
// (except for gold you gave him)
data->mContainerStore.add(MWWorld::ContainerStore::sGoldId, ref->mBase->mData.mGold, ptr);
getContainerStore(ptr).add(MWWorld::ContainerStore::sGoldId, ref->mBase->mData.mGold, ptr);
// store
ptr.getRefData().setCustomData (data.release());
if (ref->mBase->mFlags & ESM::Creature::Weapon)
getInventoryStore(ptr).autoEquip(ptr);
}
}
@ -325,18 +340,33 @@ namespace MWClass
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
}
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr)
const
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr) const
{
ensureCustomData (ptr);
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
return *dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
}
MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
if (ref->mBase->mFlags & ESM::Creature::Weapon)
return dynamic_cast<MWWorld::InventoryStore&>(getContainerStore(ptr));
else
throw std::runtime_error("this creature has no inventory store");
}
bool Creature::hasInventoryStore(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
return (ref->mBase->mFlags & ESM::Creature::Weapon);
}
std::string Creature::getScript (const MWWorld::Ptr& ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
return ref->mBase->mScript;
}

@ -68,6 +68,11 @@ namespace MWClass
const MWWorld::Ptr& ptr) const;
///< Return container store
virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const;
///< Return inventory store
virtual bool hasInventoryStore (const MWWorld::Ptr &ptr) const;
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr

@ -71,6 +71,8 @@ namespace MWClass
virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const;
///< Return inventory store
virtual bool hasInventoryStore(const MWWorld::Ptr &ptr) const { return true; }
virtual void hit(const MWWorld::Ptr& ptr, int type) const;
virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const;

@ -420,7 +420,7 @@ namespace MWDialogue
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue);
// Apply disposition change to NPC's base disposition
if (mActor.getTypeName() == typeid(ESM::NPC).name())
if (mActor.getClass().isNpc())
{
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(mActor).getNpcStats(mActor);
npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange);

@ -12,7 +12,7 @@ namespace MWGui
void CompanionItemModel::copyItem (const ItemStack& item, size_t count)
{
if (mActor.getTypeName() == typeid(ESM::NPC).name())
if (mActor.getClass().isNpc())
{
MWMechanics::NpcStats& stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
stats.modifyProfit(MWWorld::Class::get(item.mBase).getValue(item.mBase) * count);
@ -23,7 +23,7 @@ namespace MWGui
void CompanionItemModel::removeItem (const ItemStack& item, size_t count)
{
if (mActor.getTypeName() == typeid(ESM::NPC).name())
if (mActor.getClass().isNpc())
{
MWMechanics::NpcStats& stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
stats.modifyProfit(-MWWorld::Class::get(item.mBase).getValue(item.mBase) * count);

@ -74,9 +74,9 @@ void InventoryItemModel::update()
ItemStack newItem (item, this, item.getRefData().getCount());
if (mActor.getTypeName() == typeid(ESM::NPC).name())
if (mActor.getClass().hasInventoryStore(mActor))
{
MWWorld::InventoryStore& store = MWWorld::Class::get(mActor).getInventoryStore(mActor);
MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor);
for (int slot=0; slot<MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator equipped = store.getSlot(slot);

@ -162,7 +162,7 @@ namespace MWGui
}
// don't show equipped items
if(mMerchant.getTypeName() == typeid(ESM::NPC).name())
if(mMerchant.getClass().hasInventoryStore(mMerchant))
{
bool isEquipped = false;
MWWorld::InventoryStore& store = MWWorld::Class::get(mMerchant).getInventoryStore(mMerchant);

@ -14,7 +14,6 @@
#include "../mwworld/containerstore.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "inventorywindow.hpp"
#include "itemview.hpp"
@ -293,8 +292,8 @@ namespace MWGui
float clampedDisposition = std::max<int>(0,std::min<int>(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)
+ MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100));
const MWMechanics::NpcStats &sellerStats = mPtr.getClass().getNpcStats(mPtr);
const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player);
const MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr);
const MWMechanics::CreatureStats &playerStats = player.getClass().getCreatureStats(player);
float a1 = std::min(player.getClass().getSkill(player, ESM::Skill::Mercantile), 100);
float b1 = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);

@ -47,8 +47,7 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a
bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
{
// TODO: remove this check once creatures support inventory store
if (ptr.getTypeName() == typeid(ESM::NPC).name())
if (ptr.getClass().hasInventoryStore(ptr))
{
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
MWWorld::ContainerStoreIterator item =

@ -196,8 +196,8 @@ namespace MWMechanics
creatureStats.setDynamic (i, stat);
}
// auto-equip again. we need this for when the race is changed to a beast race
MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr);
// auto-equip again. we need this for when the race is changed to a beast race and shoes are no longer equippable
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr);
for (int i=0; i<MWWorld::InventoryStore::Slots; ++i)
invStore.unequipAll(ptr);
invStore.autoEquip(ptr);

@ -75,9 +75,6 @@ void Actors::insertNPC(const MWWorld::Ptr& ptr)
delete mAllActors[ptr];
mAllActors[ptr] = anim;
mRendering->addWaterRippleEmitter (ptr);
// Create CustomData, will do autoEquip and trigger animation parts update
ptr.getClass().getInventoryStore(ptr);
}
void Actors::insertCreature (const MWWorld::Ptr& ptr)
{

@ -142,7 +142,7 @@ namespace MWRender
{
mAnimation->updateParts();
MWWorld::InventoryStore &inv = MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter);
MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter);
MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
std::string groupname;
if(iter == inv.end())

@ -892,8 +892,6 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr)
mPlayerAnimation->~NpcAnimation();
new(mPlayerAnimation) NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors);
}
// Ensure CustomData -> autoEquip -> animation update
ptr.getClass().getInventoryStore(ptr);
mCamera->setAnimation(mPlayerAnimation);
mWater->removeEmitter(ptr);

@ -159,7 +159,7 @@ namespace MWScript
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr);
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore (ptr);
MWWorld::ContainerStoreIterator it = invStore.begin();
for (; it != invStore.end(); ++it)
{

@ -19,9 +19,9 @@ namespace MWWorld
void ActionEquip::executeImp (const Ptr& actor)
{
MWWorld::Ptr object = getTarget();
MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor);
MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor);
std::pair <int, std::string> result = MWWorld::Class::get (object).canBeEquipped (object, actor);
std::pair <int, std::string> result = object.getClass().canBeEquipped (object, actor);
// display error message if the player tried to equip something
if (!result.second.empty() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr())

@ -122,6 +122,11 @@ namespace MWWorld
throw std::runtime_error ("class does not have an inventory store");
}
bool Class::hasInventoryStore(const Ptr &ptr) const
{
return false;
}
void Class::lock (const Ptr& ptr, int lockLevel) const
{
throw std::runtime_error ("class does not support locking");

@ -150,6 +150,9 @@ namespace MWWorld
///< Return inventory store or throw an exception, if class does not have a
/// inventory store (default implementation: throw an exceoption)
virtual bool hasInventoryStore (const Ptr& ptr) const;
///< Does this object have an inventory store, i.e. equipment slots? (default implementation: false)
virtual void lock (const Ptr& ptr, int lockLevel) const;
///< Lock object (default implementation: throw an exception)

@ -62,6 +62,8 @@ namespace MWWorld
virtual ~ContainerStore();
virtual ContainerStore* clone() { return new ContainerStore(*this); }
ContainerStoreIterator begin (int mask = Type_All);
ContainerStoreIterator end();

@ -81,7 +81,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr,
// Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves
if ((actorPtr.getRefData().getHandle() != "player")
&& !(MWWorld::Class::get(actorPtr).getNpcStats(actorPtr).isWerewolf())
&& !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())
&& !actorPtr.getClass().getCreatureStats(actorPtr).isDead())
{
std::string type = itemPtr.getTypeName();
@ -457,7 +457,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor
// If an armor/clothing item is removed, try to find a replacement,
// but not for the player nor werewolves.
if ((actor.getRefData().getHandle() != "player")
&& !(MWWorld::Class::get(actor).getNpcStats(actor).isWerewolf()))
&& !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()))
{
std::string type = item.getTypeName();
if (((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name()))

@ -113,6 +113,8 @@ namespace MWWorld
InventoryStore& operator= (const InventoryStore& store);
virtual InventoryStore* clone() { return new InventoryStore(*this); }
virtual ContainerStoreIterator add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner=false);
///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed)
/// Auto-equip items if specific conditions are fulfilled (see the implementation).

@ -2097,7 +2097,6 @@ namespace MWWorld
void World::castSpell(const Ptr &actor)
{
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
InventoryStore& inv = actor.getClass().getInventoryStore(actor);
MWWorld::Ptr target = getFacedObject();
@ -2111,9 +2110,11 @@ namespace MWWorld
cast.cast(spell);
}
else if (inv.getSelectedEnchantItem() != inv.end())
else if (actor.getClass().hasInventoryStore(actor))
{
cast.cast(*inv.getSelectedEnchantItem());
MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
if (inv.getSelectedEnchantItem() != inv.end())
cast.cast(*inv.getSelectedEnchantItem());
}
}
@ -2282,7 +2283,7 @@ namespace MWWorld
void World::breakInvisibility(const Ptr &actor)
{
actor.getClass().getCreatureStats(actor).getActiveSpells().purgeEffect(ESM::MagicEffect::Invisibility);
if (actor.getClass().isNpc())
if (actor.getClass().hasInventoryStore(actor))
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Invisibility);
}

Loading…
Cancel
Save