diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f4b231807..a43119c61 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -51,6 +51,7 @@ set(GAMESCRIPT mwscript/soundextensions.cpp mwscript/skyextensions.cpp mwscript/statsextensions.cpp + mwscript/containerextensions.cpp mwscript/extensions.cpp mwscript/globalscripts.cpp ) @@ -65,6 +66,7 @@ set(GAMESCRIPT_HEADER mwscript/soundextensions.hpp mwscript/skyextensions.hpp mwscript/statsextensions.hpp + mwscript/containerextensions.hpp mwscript/extensions.hpp mwscript/globalscripts.hpp ) @@ -82,6 +84,8 @@ set(GAMEWORLD mwworld/class.cpp mwworld/actionteleport.cpp mwworld/actiontalk.cpp + mwworld/actiontake.cpp + mwworld/containerutil.cpp ) set(GAMEWORLD_HEADER mwworld/refdata.hpp @@ -94,6 +98,10 @@ set(GAMEWORLD_HEADER mwworld/nullaction.hpp mwworld/actionteleport.hpp mwworld/actiontalk.hpp + mwworld/actiontake.hpp + mwworld/containerstore.hpp + mwworld/manualref.hpp + mwworld/containerutil.hpp ) source_group(apps\\openmw\\mwworld FILES ${GAMEWORLD} ${GAMEWORLD_HEADER}) @@ -142,6 +150,7 @@ set(GAMECLASS_HEADER mwclass/probe.hpp mwclass/repair.hpp mwclass/static.hpp + mwclass/containerutil.hpp ) source_group(apps\\openmw\\mwclass FILES ${GAMECLASS} ${GAMECLASS_HEADER}) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 066eacd3f..4b94d78d1 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,19 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Apparatus::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Apparatus::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.appas); + } + std::string Apparatus::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 7b3ccff6a..4a514c94d 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 786868c81..f4236b5f6 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,13 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Armor::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + bool Armor::hasItemHealth (const MWWorld::Ptr& ptr) const { return true; @@ -30,6 +40,12 @@ namespace MWClass return ref->base->data.health; } + void Armor::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.armors); + } + std::string Armor::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index ebae75a9f..217a74a76 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -13,12 +13,20 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 9c0a48409..3bea7d5b9 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,21 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Book::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + // TODO implement reading + + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Book::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.books); + } + std::string Book::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index d45f569b5..3f15e2278 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 2c0d76fb3..c0e43bc3e 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,19 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Clothing::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Clothing::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.clothes); + } + std::string Clothing::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 09b66b92d..ea358be68 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index dd0fc729c..0cc516308 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -17,6 +17,22 @@ namespace MWClass return ref->base->name; } + MWWorld::ContainerStore& Container::getContainerStore (const MWWorld::Ptr& ptr) + const + { + if (!ptr.getRefData().getContainerStore().get()) + { + boost::shared_ptr > store ( + new MWWorld::ContainerStore); + + // TODO add initial content + + ptr.getRefData().getContainerStore() = store; + } + + return *ptr.getRefData().getContainerStore(); + } + std::string Container::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 959e6a634..baeac23c7 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -13,6 +13,10 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual MWWorld::ContainerStore& getContainerStore ( + const MWWorld::Ptr& ptr) const; + ///< Return container store + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/containerutil.hpp b/apps/openmw/mwclass/containerutil.hpp new file mode 100644 index 000000000..5f89983ac --- /dev/null +++ b/apps/openmw/mwclass/containerutil.hpp @@ -0,0 +1,31 @@ +#ifndef GAME_MWCLASS_CONTAINERUTIL_H +#define GAME_MWCLASS_CONTAINERUTIL_H + +#include + +#include "../mwworld/ptr.hpp" +#include "../mwworld/containerstore.hpp" + +namespace MWClass +{ + template + void insertIntoContainerStore (const MWWorld::Ptr& ptr, + ESMS::CellRefList& containerStore) + { + if (!ptr.isEmpty()) + { + // TODO check stacking + + ESMS::LiveCellRef cellRef; + + cellRef.base = ptr.get()->base; + cellRef.ref = ptr.getCellRef(); + cellRef.mData = ptr.getRefData(); + + containerStore.list.push_back (cellRef); + + } + } +} + +#endif diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 32575d7db..8525e9142 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -49,6 +49,22 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); + } + + MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr) + const + { + if (!ptr.getRefData().getContainerStore().get()) + { + boost::shared_ptr > store ( + new MWWorld::ContainerStore); + + // TODO add initial content + + ptr.getRefData().getContainerStore() = store; + } + + return *ptr.getRefData().getContainerStore(); } std::string Creature::getScript (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 71fb4dbec..e964a7708 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -20,6 +20,10 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual MWWorld::ContainerStore& getContainerStore ( + const MWWorld::Ptr& ptr) const; + ///< Return container store + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 81d19b2fa..9162384af 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,19 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Ingredient::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Ingredient::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.ingreds); + } + std::string Ingredient::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index c2edd9484..d742fae8b 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 98e0b01b4..7cb363bf8 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -6,6 +6,10 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" +#include "../mwworld/nullaction.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -20,6 +24,25 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Light::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + if (!(ref->base->data.flags & ESM::Light::Carry)) + return boost::shared_ptr (new MWWorld::NullAction); + + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Light::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.lights); + } + std::string Light::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 08c3ddf7c..6d08d557c 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index ce57e0c99..ab1969480 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,19 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Lockpick::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Lockpick::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.lockpicks); + } + std::string Lockpick::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index e009e9fdd..e15d9daee 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index dda21aaa7..f29a0be1f 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,19 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Misc::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Misc::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.miscItems); + } + std::string Misc::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 526235aa0..01542baed 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 56d601edc..829b17e7e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -49,6 +49,22 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); + } + + MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr) + const + { + if (!ptr.getRefData().getContainerStore().get()) + { + boost::shared_ptr > store ( + new MWWorld::ContainerStore); + + // TODO add initial content + + ptr.getRefData().getContainerStore() = store; + } + + return *ptr.getRefData().getContainerStore(); } std::string Npc::getScript (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index eb18cb2bd..a2dd6f470 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -20,6 +20,10 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual MWWorld::ContainerStore& getContainerStore ( + const MWWorld::Ptr& ptr) const; + ///< Return container store + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index f8e9ee0a0..0799b2031 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,19 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Potion::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Potion::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.potions); + } + std::string Potion::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index c851d1b4e..208c26c56 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 3c22e4c7f..08ec391a8 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,19 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Probe::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Probe::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.probes); + } + std::string Probe::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 84e93d1ce..c17d53dab 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index f22b8607a..9ed7f0e77 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,19 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Repair::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + + void Repair::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.repairs); + } + std::string Repair::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 803e21d51..52d045ebe 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -13,6 +13,14 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a7fce960c..c292c32dd 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -6,6 +6,9 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontake.hpp" + +#include "containerutil.hpp" namespace MWClass { @@ -17,6 +20,13 @@ namespace MWClass return ref->base->name; } + boost::shared_ptr Weapon::activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + { + return boost::shared_ptr ( + new MWWorld::ActionTake (ptr)); + } + bool Weapon::hasItemHealth (const MWWorld::Ptr& ptr) const { return true; @@ -30,6 +40,12 @@ namespace MWClass return ref->base->data.health; } + void Weapon::insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const + { + insertIntoContainerStore (ptr, containerStore.weapons); + } + std::string Weapon::getScript (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 01b6f8e13..6bc96381c 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -13,12 +13,20 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + ///< Generate action for activation + virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health + virtual void insertIntoContainer (const MWWorld::Ptr& ptr, + MWWorld::ContainerStore& containerStore) const; + ///< Insert into a containe + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwrender/cell.hpp b/apps/openmw/mwrender/cell.hpp index d6dd944ca..8fa3f9f0f 100644 --- a/apps/openmw/mwrender/cell.hpp +++ b/apps/openmw/mwrender/cell.hpp @@ -3,31 +3,33 @@ #include -namespace MWRender +namespace MWRender { class CellRender { - public: - + public: + virtual ~CellRender() {}; - + /// Make the cell visible. Load the cell if necessary. virtual void show() = 0; - + /// Remove the cell from rendering, but don't remove it from /// memory. - virtual void hide() = 0; - + virtual void hide() = 0; + /// Destroy all rendering objects connected with this cell. virtual void destroy() = 0; - + /// Make the reference with the given handle visible. virtual void enable (const std::string& handle) = 0; - + /// Make the reference with the given handle invisible. virtual void disable (const std::string& handle) = 0; + + /// Remove the reference with the given handle permanently from the scene. + virtual void deleteObject (const std::string& handle) = 0; }; } #endif - diff --git a/apps/openmw/mwrender/cellimp.cpp b/apps/openmw/mwrender/cellimp.cpp index 50047c1d9..121f17383 100644 --- a/apps/openmw/mwrender/cellimp.cpp +++ b/apps/openmw/mwrender/cellimp.cpp @@ -48,24 +48,25 @@ void insertObj(CellRenderImp& cellRender, ESMS::LiveCellRefmodel; - + cellRender.insertBegin(liveRef.ref); cellRender.insertMesh(headModel); //TODO: define consts for each bodypart e.g. chest, foot, wrist... and put the parts in the right place cellRender.insertMesh("meshes\\" + store.bodyParts.find(bodyRaceID + "chest")->model); - + liveRef.mData.setHandle (cellRender.insertEnd (liveRef.mData.isEnabled())); } - + template void insertCellRefList (CellRenderImp& cellRender, const ESMS::ESMStore& store, T& cellRefList) { - for(typename T::List::iterator it = cellRefList.list.begin(); - it != cellRefList.list.end(); it++) - { - insertObj (cellRender, *it, store); - } + for(typename T::List::iterator it = cellRefList.list.begin(); + it != cellRefList.list.end(); it++) + { + if (it->mData.getCount()) + insertObj (cellRender, *it, store); + } } void CellRenderImp::insertCell(ESMS::CellStore &cell, const ESMS::ESMStore& store) @@ -92,5 +93,3 @@ void CellRenderImp::insertCell(ESMS::CellStore &cell, const ES insertCellRefList (*this, store, cell.statics); insertCellRefList (*this, store, cell.weapons); } - - diff --git a/apps/openmw/mwrender/interior.cpp b/apps/openmw/mwrender/interior.cpp index c67bc8878..d559a1216 100644 --- a/apps/openmw/mwrender/interior.cpp +++ b/apps/openmw/mwrender/interior.cpp @@ -237,6 +237,16 @@ void InteriorCellRender::disable (const std::string& handle) scene.getMgr()->getSceneNode (handle)->setVisible (false); } +void InteriorCellRender::deleteObject (const std::string& handle) +{ + if (!handle.empty()) + { + Ogre::SceneNode *node = scene.getMgr()->getSceneNode (handle); + node->removeAndDestroyAllChildren(); + scene.getMgr()->destroySceneNode (node); + } +} + // Magic function from the internets. Might need this later. /* void Scene::DestroyAllAttachedMovableObjects( SceneNode* i_pSceneNode ) diff --git a/apps/openmw/mwrender/interior.hpp b/apps/openmw/mwrender/interior.hpp index 0ef5ec85c..3d375f7f2 100644 --- a/apps/openmw/mwrender/interior.hpp +++ b/apps/openmw/mwrender/interior.hpp @@ -99,11 +99,13 @@ namespace MWRender /// Make the reference with the given handle visible. virtual void enable (const std::string& handle); - + /// Make the reference with the given handle invisible. - virtual void disable (const std::string& handle); + virtual void disable (const std::string& handle); + + /// Remove the reference with the given handle permanently from the scene. + virtual void deleteObject (const std::string& handle); }; } #endif - diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp new file mode 100644 index 000000000..1121d8eff --- /dev/null +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -0,0 +1,273 @@ + +#include "containerextensions.hpp" + +#include + +#include + +#include +#include +#include + +#include "../mwworld/manualref.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/containerutil.hpp" + +#include "interpretercontext.hpp" + +namespace MWScript +{ + namespace Container + { + class OpAddItem : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer count = runtime[0].mInteger; + runtime.pop(); + + if (count<0) + throw std::runtime_error ("second argument for AddItem must be non-negative"); + + MWWorld::Ptr ptr = context.getReference(); + + MWWorld::ManualRef ref (context.getWorld().getStore(), item); + + ref.getPtr().getRefData().setCount (count); + + MWWorld::Class::get (ref.getPtr()).insertIntoContainer (ref.getPtr(), + MWWorld::Class::get (ptr).getContainerStore (ptr)); + } + }; + + class OpAddItemExplicit : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer count = runtime[0].mInteger; + runtime.pop(); + + if (count<0) + throw std::runtime_error ("second argument for AddItem must be non-negative"); + + MWWorld::Ptr ptr = context.getWorld().getPtr (id, false); + + MWWorld::ManualRef ref (context.getWorld().getStore(), item); + + ref.getPtr().getRefData().setCount (count); + + MWWorld::Class::get (ref.getPtr()).insertIntoContainer (ref.getPtr(), + MWWorld::Class::get (ptr).getContainerStore (ptr)); + } + }; + + class OpGetItemCount : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Ptr ptr = context.getReference(); + + std::vector list; + + MWWorld::listItemsInContainer (item, + MWWorld::Class::get (ptr).getContainerStore (ptr), + context.getWorld().getStore(), list); + + Interpreter::Type_Integer sum = 0; + + for (std::vector::iterator iter (list.begin()); iter!=list.end(); + ++iter) + { + sum += iter->getRefData().getCount(); + } + + runtime.push (sum); + } + }; + + class OpGetItemCountExplicit : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Ptr ptr = context.getWorld().getPtr (id, false); + + std::vector list; + + MWWorld::listItemsInContainer (item, + MWWorld::Class::get (ptr).getContainerStore (ptr), + context.getWorld().getStore(), list); + + Interpreter::Type_Integer sum = 0; + + for (std::vector::iterator iter (list.begin()); iter!=list.end(); + ++iter) + { + sum += iter->getRefData().getCount(); + } + + runtime.push (sum); + } + }; + + class OpRemoveItem : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer count = runtime[0].mInteger; + runtime.pop(); + + if (count<0) + throw std::runtime_error ("second argument for RemoveItem must be non-negative"); + + MWWorld::Ptr ptr = context.getReference(); + + std::vector list; + + MWWorld::listItemsInContainer (item, + MWWorld::Class::get (ptr).getContainerStore (ptr), + context.getWorld().getStore(), list); + + for (std::vector::iterator iter (list.begin()); + iter!=list.end() && count; + ++iter) + { + if (iter->getRefData().getCount()<=count) + { + count -= iter->getRefData().getCount(); + iter->getRefData().setCount (0); + } + else + { + iter->getRefData().setCount (iter->getRefData().getCount()-count); + count = 0; + } + } + + // To be fully compatible with original Morrowind, we would need to check if + // count is >= 0 here and throw an exception. But let's be tollerant instead. + } + }; + + class OpRemoveItemExplicit : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer count = runtime[0].mInteger; + runtime.pop(); + + if (count<0) + throw std::runtime_error ("second argument for RemoveItem must be non-negative"); + + MWWorld::Ptr ptr = context.getWorld().getPtr (id, false); + + std::vector list; + + MWWorld::listItemsInContainer (item, + MWWorld::Class::get (ptr).getContainerStore (ptr), + context.getWorld().getStore(), list); + + for (std::vector::iterator iter (list.begin()); + iter!=list.end() && count; + ++iter) + { + if (iter->getRefData().getCount()<=count) + { + count -= iter->getRefData().getCount(); + iter->getRefData().setCount (0); + } + else + { + iter->getRefData().setCount (iter->getRefData().getCount()-count); + count = 0; + } + } + + // To be fully compatible with original Morrowind, we would need to check if + // count is >= 0 here and throw an exception. But let's be tollerant instead. + } + }; + + const int opcodeAddItem = 0x2000076; + const int opcodeAddItemExplicit = 0x2000077; + const int opcodeGetItemCount = 0x2000078; + const int opcodeGetItemCountExplicit = 0x2000079; + const int opcodeRemoveItem = 0x200007a; + const int opcodeRemoveItemExplicit = 0x200007b; + + void registerExtensions (Compiler::Extensions& extensions) + { + extensions.registerInstruction ("additem", "cl", opcodeAddItem, opcodeAddItemExplicit); + extensions.registerFunction ("getitemcount", 'l', "c", opcodeGetItemCount, + opcodeGetItemCountExplicit); + extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem, + opcodeRemoveItemExplicit); + } + + void installOpcodes (Interpreter::Interpreter& interpreter) + { + interpreter.installSegment5 (opcodeAddItem, new OpAddItem); + interpreter.installSegment5 (opcodeAddItemExplicit, new OpAddItemExplicit); + interpreter.installSegment5 (opcodeGetItemCount, new OpGetItemCount); + interpreter.installSegment5 (opcodeGetItemCountExplicit, new OpGetItemCountExplicit); + interpreter.installSegment5 (opcodeRemoveItem, new OpRemoveItem); + interpreter.installSegment5 (opcodeRemoveItemExplicit, new OpRemoveItemExplicit); + } + } +} diff --git a/apps/openmw/mwscript/containerextensions.hpp b/apps/openmw/mwscript/containerextensions.hpp new file mode 100644 index 000000000..f99a71b4d --- /dev/null +++ b/apps/openmw/mwscript/containerextensions.hpp @@ -0,0 +1,25 @@ +#ifndef GAME_SCRIPT_CONTAINEREXTENSIONS_H +#define GAME_SCRIPT_CONTAINEREXTENSIONS_H + +namespace Compiler +{ + class Extensions; +} + +namespace Interpreter +{ + class Interpreter; +} + +namespace MWScript +{ + /// \brief stats-related script functionality (creatures and NPCs) + namespace Container + { + void registerExtensions (Compiler::Extensions& extensions); + + void installOpcodes (Interpreter::Interpreter& interpreter); + } +} + +#endif diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 5807f26d4..70e5fe8c2 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -77,4 +77,10 @@ op 0x200006c-0x200006e: ModDynamic (health, magicka, fatigue), explicit referenc op 0x200006f-0x2000071: GetDynamic (health, magicka, fatigue) op 0x2000072-0x2000074: GetDynamic (health, magicka, fatigue), explicit reference op 0x2000075: Activate -opcodes 0x2000076-0x3ffffff unused +op 0x2000076: AddItem +op 0x2000077: AddItem, explicit reference +op 0x2000078: GetItemCount +op 0x2000079: GetItemCount, explicit reference +op 0x200007a: RemoveItem +op 0x200007b: RemoveItem, explicit reference +opcodes 0x200007c-0x3ffffff unused diff --git a/apps/openmw/mwscript/extensions.cpp b/apps/openmw/mwscript/extensions.cpp index 3abaac58c..1b3d3df14 100644 --- a/apps/openmw/mwscript/extensions.cpp +++ b/apps/openmw/mwscript/extensions.cpp @@ -10,6 +10,7 @@ #include "guiextensions.hpp" #include "skyextensions.hpp" #include "statsextensions.hpp" +#include "containerextensions.hpp" namespace MWScript { @@ -21,8 +22,9 @@ namespace MWScript Sound::registerExtensions (extensions); Sky::registerExtensions (extensions); Stats::registerExtensions (extensions); + Container::registerExtensions (extensions); } - + void installOpcodes (Interpreter::Interpreter& interpreter) { Interpreter::installOpcodes (interpreter); @@ -32,6 +34,6 @@ namespace MWScript Sound::installOpcodes (interpreter); Sky::installOpcodes (interpreter); Stats::installOpcodes (interpreter); - } + Container::installOpcodes (interpreter); + } } - diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp new file mode 100644 index 000000000..b318f0796 --- /dev/null +++ b/apps/openmw/mwworld/actiontake.cpp @@ -0,0 +1,23 @@ + +#include "actiontake.hpp" + +#include "class.hpp" +#include "environment.hpp" +#include "world.hpp" + +namespace MWWorld +{ + ActionTake::ActionTake (const MWWorld::Ptr& object) : mObject (object) {} + + void ActionTake::execute (Environment& environment) + { + // insert into player's inventory + MWWorld::Ptr player = environment.mWorld->getPtr ("player", true); + + MWWorld::Class::get (mObject).insertIntoContainer (mObject, + MWWorld::Class::get (player).getContainerStore (player)); + + // remove from world + environment.mWorld->deleteObject (mObject); + } +} diff --git a/apps/openmw/mwworld/actiontake.hpp b/apps/openmw/mwworld/actiontake.hpp new file mode 100644 index 000000000..509ebc6bb --- /dev/null +++ b/apps/openmw/mwworld/actiontake.hpp @@ -0,0 +1,21 @@ +#ifndef GAME_MWWORLD_ACTIONTAKE_H +#define GAME_MWWORLD_ACTIONTAKE_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionTake : public Action + { + MWWorld::Ptr mObject; + + public: + + ActionTake (const MWWorld::Ptr& object); + + virtual void execute (Environment& environment); + }; +} + +#endif diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 267ff7294..85e5140ea 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -41,6 +41,16 @@ namespace MWWorld return boost::shared_ptr (new NullAction); } + ContainerStore& Class::getContainerStore (const Ptr& ptr) const + { + throw std::runtime_error ("class does not have a container store"); + } + + void Class::insertIntoContainer (const Ptr& ptr, ContainerStore& containerStore) const + { + throw std::runtime_error ("class does not support inserting into a container"); + } + std::string Class::getScript (const Ptr& ptr) const { return ""; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 3f5722ce2..28d96d69f 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -7,6 +7,8 @@ #include #include "action.hpp" +#include "containerstore.hpp" +#include "refdata.hpp" namespace MWMechanics { @@ -58,6 +60,15 @@ namespace MWWorld ///< Generate action for using via inventory menu (default implementation: return a /// null action). + virtual ContainerStore& getContainerStore (const Ptr& ptr) const; + ///< Return container store or throw an exception, if class does not have a + /// container store (default implementation: throw an exceoption) + + virtual void insertIntoContainer (const Ptr& ptr, ContainerStore& containerStore) + const; + ///< Insert into a container or throw an exception, if class does not support inserting into + /// a container. + virtual std::string getScript (const Ptr& ptr) const; ///< Return name of the script attached to ptr (default implementation: return an empty /// string). diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp new file mode 100644 index 000000000..c05bfe156 --- /dev/null +++ b/apps/openmw/mwworld/containerstore.hpp @@ -0,0 +1,26 @@ +#ifndef GAME_MWWORLD_CONTAINERSTORE_H +#define GAME_MWWORLD_CONTAINERSTORE_H + +#include + +namespace MWWorld +{ + template + struct ContainerStore + { + ESMS::CellRefList potions; + ESMS::CellRefList appas; + ESMS::CellRefList armors; + ESMS::CellRefList books; + ESMS::CellRefList clothes; + ESMS::CellRefList ingreds; + ESMS::CellRefList lights; + ESMS::CellRefList lockpicks; + ESMS::CellRefList miscItems; + ESMS::CellRefList probes; + ESMS::CellRefList repairs; + ESMS::CellRefList weapons; + }; +} + +#endif diff --git a/apps/openmw/mwworld/containerutil.cpp b/apps/openmw/mwworld/containerutil.cpp new file mode 100644 index 000000000..7c7e5e5e8 --- /dev/null +++ b/apps/openmw/mwworld/containerutil.cpp @@ -0,0 +1,43 @@ + +#include "containerutil.hpp" + +namespace +{ + template + void listItemsInContainerImp (const std::string& id, + ESMS::CellRefList& containerStore, + const ESMS::RecListT& store, std::vector& list) + { + if (const T *record = store.search (id)) + { + for (typename ESMS::CellRefList::List::iterator iter + (containerStore.list.begin()); + iter!=containerStore.list.end(); ++iter) + { + if (iter->base==record) + list.push_back (MWWorld::Ptr (&*iter, 0)); + } + } + } +} + +namespace MWWorld +{ + void listItemsInContainer (const std::string& id, + ContainerStore& containerStore, + const ESMS::ESMStore& store, std::vector& list) + { + listItemsInContainerImp (id, containerStore.potions, store.potions, list); + listItemsInContainerImp (id, containerStore.appas, store.appas, list); + listItemsInContainerImp (id, containerStore.armors, store.armors, list); + listItemsInContainerImp (id, containerStore.books, store.books, list); + listItemsInContainerImp (id, containerStore.clothes, store.clothes, list); + listItemsInContainerImp (id, containerStore.ingreds, store.ingreds, list); + listItemsInContainerImp (id, containerStore.lights, store.lights, list); + listItemsInContainerImp (id, containerStore.lockpicks, store.lockpicks, list); + listItemsInContainerImp (id, containerStore.miscItems, store.miscItems, list); + listItemsInContainerImp (id, containerStore.probes, store.probes, list); + listItemsInContainerImp (id, containerStore.repairs, store.repairs, list); + listItemsInContainerImp (id, containerStore.weapons, store.weapons, list); + } +} diff --git a/apps/openmw/mwworld/containerutil.hpp b/apps/openmw/mwworld/containerutil.hpp new file mode 100644 index 000000000..21e770404 --- /dev/null +++ b/apps/openmw/mwworld/containerutil.hpp @@ -0,0 +1,20 @@ +#ifndef GAME_MWWORLD_CONTAINERUTIL_H +#define GAME_MWWORLD_CONTAINERUTIL_H + +#include +#include + +#include + +#include "containerstore.hpp" +#include "ptr.hpp" +#include "refdata.hpp" + +namespace MWWorld +{ + void listItemsInContainer (const std::string& id, ContainerStore& containerStore, + const ESMS::ESMStore& store, std::vector& list); + ///< append all references with the given id to list. +} + +#endif diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp new file mode 100644 index 000000000..4b7edfa43 --- /dev/null +++ b/apps/openmw/mwworld/manualref.hpp @@ -0,0 +1,86 @@ +#ifndef GAME_MWWORLD_MANUALREF_H +#define GAME_MWWORLD_MANUALREF_H + +#include + +#include +#include + +#include "ptr.hpp" + +namespace MWWorld +{ + /// \brief Manually constructed live cell ref + class ManualRef + { + boost::any mRef; + Ptr mPtr; + + ManualRef (const ManualRef&); + ManualRef& operator= (const ManualRef&); + + template + bool create (const ESMS::RecListT& list, const std::string& name) + { + if (const T *instance = list.search (name)) + { + ESMS::LiveCellRef ref; + ref.base = instance; + + mRef = ref; + mPtr = Ptr (&boost::any_cast&> (mRef), 0); + + return true; + } + + return false; + } + + public: + + ManualRef (const ESMS::ESMStore& store, const std::string& name) + { + // create + if (!create (store.activators, name) && + !create (store.potions, name) && + !create (store.appas, name) && + !create (store.armors, name) && + !create (store.books, name) && + !create (store.clothes, name) && + !create (store.containers, name) && + !create (store.creatures, name) && + !create (store.doors, name) && + !create (store.ingreds, name) && + !create (store.creatureLists, name) && + !create (store.itemLists, name) && + !create (store.lights, name) && + !create (store.lockpicks, name) && + !create (store.miscItems, name) && + !create (store.npcs, name) && + !create (store.probes, name) && + !create (store.repairs, name) && + !create (store.statics, name) && + !create (store.weapons, name)) + throw std::logic_error ("failed to create manual cell ref for " + name); + + // initialise + ESM::CellRef& cellRef = mPtr.getCellRef(); + cellRef.refnum = -1; + cellRef.scale = 1; + cellRef.factIndex = 0; + cellRef.charge = 0; + cellRef.intv = 0; + cellRef.nam9 = 0; + cellRef.teleport = false; + cellRef.lockLevel = 0; + cellRef.unam = 0; + } + + const Ptr& getPtr() const + { + return mPtr; + } + }; +} + +#endif diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 919f4f8a0..b041a06cb 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -7,6 +7,8 @@ #include "../mwscript/locals.hpp" +#include "containerstore.hpp" + namespace ESM { class Script; @@ -22,28 +24,36 @@ namespace MWWorld class RefData { std::string mHandle; - + MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, // we can make this a pointer later. bool mHasLocals; bool mEnabled; - + int mCount; // 0: deleted + // we are using shared pointer here to avoid having to create custom copy-constructor, // assignment operator and destructor. As a consequence though copying a RefData object // manually will probably give unexcepted results. This is not a problem since RefData // are never copied outside of container operations. boost::shared_ptr mCreatureStats; - + + boost::shared_ptr > mContainerStore; + public: - - RefData() : mHasLocals (false), mEnabled (true) {} - + + RefData() : mHasLocals (false), mEnabled (true), mCount (1) {} + std::string getHandle() { return mHandle; } - + + int getCount() const + { + return mCount; + } + void setLocals (const ESM::Script& script) { if (!mHasLocals) @@ -52,37 +62,47 @@ namespace MWWorld mHasLocals = true; } } - + void setHandle (const std::string& handle) { mHandle = handle; } - + + void setCount (int count) + { + mCount = count; + } + MWScript::Locals& getLocals() { return mLocals; } - + bool isEnabled() const { return mEnabled; } - + void enable() { mEnabled = true; } - + void disable() { mEnabled = true; } - + boost::shared_ptr& getCreatureStats() { - return mCreatureStats; + return mCreatureStats; } - }; + + boost::shared_ptr >& getContainerStore() + { + return mContainerStore; + } + }; } #endif diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 296d1d0f2..c8230f5a8 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -25,7 +25,7 @@ namespace cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) { - if (!iter->base->script.empty()) + if (!iter->base->script.empty() && iter->mData.getCount()) { if (const ESM::Script *script = store.scripts.find (iter->base->script)) { @@ -611,4 +611,25 @@ namespace MWWorld return result.first; } + + void World::deleteObject (Ptr ptr) + { + if (ptr.getRefData().getCount()>0) + { + ptr.getRefData().setCount (0); + + if (MWRender::CellRender *render = searchRender (ptr.getCell())) + { + render->deleteObject (ptr.getRefData().getHandle()); + ptr.getRefData().setHandle (""); + + if (mActiveCells.find (ptr.getCell())!=mActiveCells.end() && + (ptr.getType()==typeid (ESMS::LiveCellRef) || + ptr.getType()==typeid (ESMS::LiveCellRef))) + { + mEnvironment.mMechanicsManager->removeActor (ptr); + } + } + } + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index d20161698..2a7b8009a 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -134,6 +134,8 @@ namespace MWWorld std::string getFacedHandle(); ///< Return handle of the object the player is looking at + + void deleteObject (Ptr ptr); }; }