diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0fe62ea4f9..a43119c614 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 ) @@ -81,6 +83,9 @@ set(GAMEWORLD mwworld/globals.cpp mwworld/class.cpp mwworld/actionteleport.cpp + mwworld/actiontalk.cpp + mwworld/actiontake.cpp + mwworld/containerutil.cpp ) set(GAMEWORLD_HEADER mwworld/refdata.hpp @@ -92,6 +97,11 @@ set(GAMEWORLD_HEADER mwworld/action.hpp 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}) @@ -140,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/engine.cpp b/apps/openmw/engine.cpp index 8734ffaada..b67bcd0ac7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -38,13 +38,18 @@ void OMW::Engine::executeLocalScripts() mEnvironment.mWorld->getLocalScripts().begin()); iter!=mEnvironment.mWorld->getLocalScripts().end(); ++iter) { - MWScript::InterpreterContext interpreterContext (mEnvironment, - &iter->second.getRefData().getLocals(), MWWorld::Ptr (iter->second)); - mScriptManager->run (iter->first, interpreterContext); + if (!mIgnoreLocalPtr.isEmpty() && mIgnoreLocalPtr!=iter->second) + { + MWScript::InterpreterContext interpreterContext (mEnvironment, + &iter->second.getRefData().getLocals(), MWWorld::Ptr (iter->second)); + mScriptManager->run (iter->first, interpreterContext); - if (mEnvironment.mWorld->hasCellChanged()) - break; + if (mEnvironment.mWorld->hasCellChanged()) + break; + } } + + mIgnoreLocalPtr = MWWorld::Ptr(); } bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt) @@ -74,22 +79,20 @@ bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt) if (focusFrameCounter++ == focusUpdateFrame) { - std::pair handle = mEnvironment.mWorld->getMWScene()->getFacedHandle(); + std::string handle = mEnvironment.mWorld->getFacedHandle(); std::string name; - if (!handle.first.empty()) + if (!handle.empty()) { - // TODO compare handle.second with max activation range (from a GMST) - - MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle.first); + MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); if (!ptr.isEmpty()) name = MWWorld::Class::get (ptr).getName (ptr); } if (!name.empty()) - std::cout << "Object: " << name << ", distance: " << handle.second << std::endl; + std::cout << "Object: " << name << std::endl; focusFrameCounter = 0; } @@ -255,7 +258,7 @@ void OMW::Engine::go() // Sets up the input system MWInput::MWInputManager input(mOgre, mEnvironment.mWorld->getPlayerPos(), - *mEnvironment.mWindowManager, mDebug); + *mEnvironment.mWindowManager, mDebug, *this); focusFrameCounter = 0; @@ -268,3 +271,38 @@ void OMW::Engine::go() std::cout << "Quitting peacefully.\n"; } + +void OMW::Engine::activate() +{ + std::string handle = mEnvironment.mWorld->getFacedHandle(); + + if (handle.empty()) + return; + + MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); + + if (ptr.isEmpty()) + return; + + MWScript::InterpreterContext interpreterContext (mEnvironment, + &ptr.getRefData().getLocals(), ptr); + + boost::shared_ptr action = + MWWorld::Class::get (ptr).activate (ptr, mEnvironment.mWorld->getPlayerPos().getPlayer(), + mEnvironment); + + interpreterContext.activate (ptr, action); + + std::string script = MWWorld::Class::get (ptr).getScript (ptr); + + if (!script.empty()) + { + mIgnoreLocalPtr = ptr; + mScriptManager->run (script, interpreterContext); + } + + if (!interpreterContext.hasActivationBeenHandled()) + { + interpreterContext.executeActivation(); + } +} diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 412c4fa736..bc612d13c0 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -11,6 +11,7 @@ #include #include "mwworld/environment.hpp" +#include "mwworld/ptr.hpp" namespace Compiler { @@ -68,6 +69,8 @@ namespace OMW int focusFrameCounter; static const int focusUpdateFrame = 10; + MWWorld::Ptr mIgnoreLocalPtr; + // not implemented Engine (const Engine&); Engine& operator= (const Engine&); @@ -111,12 +114,15 @@ namespace OMW /// Enable verbose script output void enableVerboseScripts(); - + /// Start as a new game. void setNewGame(); /// Initialise and enter main loop. void go(); + + /// Activate the focussed object. + void activate(); }; } diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index ff2d559f46..3cdc1f8508 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -17,6 +17,14 @@ namespace MWClass return ref->base->name; } + std::string Activator::getScript (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->script; + } + void Activator::registerSelf() { boost::shared_ptr instance (new Activator); diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 5639117b72..66821a7c5d 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -13,6 +13,9 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; + ///< Return name of the script attached to ptr + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 1a936e76ba..4b94d78d10 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,27 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Apparatus::registerSelf() { boost::shared_ptr instance (new Apparatus); diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 96c838e8d9..4a514c94de 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 1a339c7034..f4236b5f6c 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,20 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Armor::registerSelf() { boost::shared_ptr instance (new Armor); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 4a6cd2f75d..217a74a763 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -13,12 +13,23 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index d162698571..3bea7d5b9c 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,29 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Book::registerSelf() { boost::shared_ptr instance (new Book); diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index b9a03f2e76..3f15e2278e 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index a728394d94..c0e43bc3e9 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,27 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Clothing::registerSelf() { boost::shared_ptr instance (new Clothing); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 1b8dcf16dc..ea358be685 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index a6df294e7d..0cc5163085 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -17,6 +17,30 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Container::registerSelf() { boost::shared_ptr instance (new Container); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 0b907b2b79..baeac23c7d 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -13,6 +13,13 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/containerutil.hpp b/apps/openmw/mwclass/containerutil.hpp new file mode 100644 index 0000000000..5f89983acb --- /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 198c0e72fd..8525e9142c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -6,6 +6,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontalk.hpp" namespace MWClass { @@ -44,6 +45,36 @@ namespace MWClass return *ptr.getRefData().getCreatureStats(); } + boost::shared_ptr Creature::activate (const MWWorld::Ptr& ptr, + 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 + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->script; + } + void Creature::registerSelf() { boost::shared_ptr instance (new Creature); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 5056501c5c..e964a7708f 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -16,6 +16,17 @@ namespace MWClass virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; ///< Return creature stats + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 24710fa4cc..2c4bd35629 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -53,6 +53,14 @@ namespace MWClass } } + std::string Door::getScript (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->script; + } + void Door::registerSelf() { boost::shared_ptr instance (new Door); diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 28d0486331..fa3b6d6573 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -17,6 +17,9 @@ namespace MWClass const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation + virtual std::string getScript (const MWWorld::Ptr& ptr) const; + ///< Return name of the script attached to ptr + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 6ae80c4408..9162384af7 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,27 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Ingredient::registerSelf() { boost::shared_ptr instance (new Ingredient); diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index eed520cb15..d742fae8bd 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index bf983259b7..7cb363bf81 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,33 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Light::registerSelf() { boost::shared_ptr instance (new Light); diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 8fa53aeaf9..6d08d557ca 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index ee861c30b3..ab19694802 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,27 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Lockpick::registerSelf() { boost::shared_ptr instance (new Lockpick); diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index daff07f85f..e15d9daee3 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index eabb7ba7ae..f29a0be1f7 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,27 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Misc::registerSelf() { boost::shared_ptr instance (new Misc); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index d2f685d406..01542baedd 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index dbb7f2a934..829b17e7e9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -6,6 +6,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwworld/ptr.hpp" +#include "../mwworld/actiontalk.hpp" namespace MWClass { @@ -44,6 +45,36 @@ namespace MWClass return *ptr.getRefData().getCreatureStats(); } + boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, + 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 + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->script; + } + void Npc::registerSelf() { boost::shared_ptr instance (new Npc); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 76c56de40e..a2dd6f4703 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -16,6 +16,17 @@ namespace MWClass virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; ///< Return creature stats + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, + 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 75f2f6ccb2..0799b20310 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,27 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Potion::registerSelf() { boost::shared_ptr instance (new Potion); diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 350aba1569..208c26c560 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 65fbf47cbf..08ec391a85 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,27 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Probe::registerSelf() { boost::shared_ptr instance (new Probe); diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 1a60f220a5..c17d53dabb 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 722baebde3..9ed7f0e77a 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,27 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Repair::registerSelf() { boost::shared_ptr instance (new Repair); diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index e7a9928ede..52d045ebed 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -13,6 +13,17 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 5ca80bcb7b..c292c32dd1 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,20 @@ 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 = + ptr.get(); + + return ref->base->script; + } + void Weapon::registerSelf() { boost::shared_ptr instance (new Weapon); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 98e5930f87..6bc96381cf 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -13,12 +13,23 @@ 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 + static void registerSelf(); }; } diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index f851b43b2e..f730150b0b 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -17,6 +17,8 @@ #include #include "../mwrender/playerpos.hpp" +#include "../engine.hpp" + #include #include #include @@ -58,6 +60,7 @@ namespace MWInput OEngine::GUI::EventInjectorPtr guiEvents; MWRender::PlayerPos &player; MWGui::WindowManager &windows; + OMW::Engine& mEngine; // Count screenshots. int shotCount; @@ -137,7 +140,7 @@ namespace MWInput void activate() { - + mEngine.activate(); } // Exit program now button (which is disabled in GUI mode) @@ -151,13 +154,15 @@ namespace MWInput InputImpl(OEngine::Render::OgreRenderer &_ogre, MWRender::PlayerPos &_player, MWGui::WindowManager &_windows, - bool debug) + bool debug, + OMW::Engine& engine) : ogre(_ogre), exit(ogre.getWindow()), input(ogre.getWindow(), !debug), poller(input), player(_player), windows(_windows), + mEngine (engine), shotCount(0) { using namespace OEngine::Input; @@ -275,9 +280,10 @@ namespace MWInput MWInputManager::MWInputManager(OEngine::Render::OgreRenderer &ogre, MWRender::PlayerPos &player, MWGui::WindowManager &windows, - bool debug) + bool debug, + OMW::Engine& engine) { - impl = new InputImpl(ogre,player,windows,debug); + impl = new InputImpl(ogre,player,windows,debug, engine); } MWInputManager::~MWInputManager() diff --git a/apps/openmw/mwinput/inputmanager.hpp b/apps/openmw/mwinput/inputmanager.hpp index 094b848eef..554089588d 100644 --- a/apps/openmw/mwinput/inputmanager.hpp +++ b/apps/openmw/mwinput/inputmanager.hpp @@ -19,6 +19,11 @@ namespace MWGui class WindowManager; } +namespace OMW +{ + class Engine; +} + namespace MWInput { // Forward declaration of the real implementation. @@ -37,7 +42,8 @@ namespace MWInput MWInputManager(OEngine::Render::OgreRenderer &_ogre, MWRender::PlayerPos &_player, MWGui::WindowManager &_windows, - bool debug); + bool debug, + OMW::Engine& engine); ~MWInputManager(); }; } diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index a42b534446..d6422b0847 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -49,7 +49,7 @@ namespace MWMechanics value = min + (mModified - mBase); diff = value - mModified; } - else if (mBase>max-diff) + else if (mBase+diff>max) { value = max + (mModified - mBase); diff = value - mModified; diff --git a/apps/openmw/mwrender/cell.hpp b/apps/openmw/mwrender/cell.hpp index d6dd944caf..8fa3f9f0f0 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 50047c1d9f..121f173835 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 c67bc8878b..d559a12160 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 0ef5ec85c0..3d375f7f23 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 0000000000..1121d8eff4 --- /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 0000000000..f99a71b4dc --- /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 9394679604..70e5fe8c2b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -76,4 +76,11 @@ op 0x2000069-0x200006b: ModDynamic (health, magicka, fatigue) op 0x200006c-0x200006e: ModDynamic (health, magicka, fatigue), explicit reference op 0x200006f-0x2000071: GetDynamic (health, magicka, fatigue) op 0x2000072-0x2000074: GetDynamic (health, magicka, fatigue), explicit reference -opcodes 0x2000075-0x3ffffff unused +op 0x2000075: Activate +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 3abaac58cb..1b3d3df14e 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/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index f2dc57dd0e..404aa69a68 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -27,9 +27,9 @@ namespace MWScript { if (mReference.isEmpty()) throw std::runtime_error ("no implicit reference"); - + return mReference; - } + } } const MWWorld::Ptr InterpreterContext::getReference ( @@ -43,21 +43,22 @@ namespace MWScript { if (mReference.isEmpty()) throw std::runtime_error ("no implicit reference"); - + return mReference; - } + } } - + InterpreterContext::InterpreterContext (MWWorld::Environment& environment, MWScript::Locals *locals, MWWorld::Ptr reference) - : mEnvironment (environment), mLocals (locals), mReference (reference) + : mEnvironment (environment), mLocals (locals), mReference (reference), + mActivationHandled (false) {} int InterpreterContext::getLocalShort (int index) const { if (!mLocals) throw std::runtime_error ("local variables not available in this context"); - + return mLocals->mShorts.at (index); } @@ -65,7 +66,7 @@ namespace MWScript { if (!mLocals) throw std::runtime_error ("local variables not available in this context"); - + return mLocals->mLongs.at (index); } @@ -73,7 +74,7 @@ namespace MWScript { if (!mLocals) throw std::runtime_error ("local variables not available in this context"); - + return mLocals->mFloats.at (index); } @@ -90,45 +91,45 @@ namespace MWScript if (!mLocals) throw std::runtime_error ("local variables not available in this context"); - mLocals->mLongs.at (index) = value; + mLocals->mLongs.at (index) = value; } void InterpreterContext::setLocalFloat (int index, float value) { if (!mLocals) throw std::runtime_error ("local variables not available in this context"); - - mLocals->mFloats.at (index) = value; + + mLocals->mFloats.at (index) = value; } - + void InterpreterContext::messageBox (const std::string& message, const std::vector& buttons) { std::cout << "message box: " << message << std::endl; - - if (!buttons.empty()) + + if (!buttons.empty()) std::cerr << "error: message box buttons not supported" << std::endl; } - + bool InterpreterContext::menuMode() { return mEnvironment.mWindowManager->isGuiMode(); } - + int InterpreterContext::getGlobalShort (const std::string& name) const { - return mEnvironment.mWorld->getGlobalVariable (name).mShort; + return mEnvironment.mWorld->getGlobalVariable (name).mShort; } int InterpreterContext::getGlobalLong (const std::string& name) const { // a global long is internally a float. - return mEnvironment.mWorld->getGlobalVariable (name).mLong; + return mEnvironment.mWorld->getGlobalVariable (name).mLong; } float InterpreterContext::getGlobalFloat (const std::string& name) const { - return mEnvironment.mWorld->getGlobalVariable (name).mFloat; + return mEnvironment.mWorld->getGlobalVariable (name).mFloat; } void InterpreterContext::setGlobalShort (const std::string& name, int value) @@ -166,83 +167,117 @@ namespace MWScript else mEnvironment.mWorld->getGlobalVariable (name).mFloat = value; } - + bool InterpreterContext::isScriptRunning (const std::string& name) const { return mEnvironment.mGlobalScripts->isRunning (name); } - + void InterpreterContext::startScript (const std::string& name) { mEnvironment.mGlobalScripts->addScript (name); } - + void InterpreterContext::stopScript (const std::string& name) { mEnvironment.mGlobalScripts->removeScript (name); } - + float InterpreterContext::getDistance (const std::string& name, const std::string& id) const { // TODO handle exterior cells (when ref and ref2 are located in different cells) const MWWorld::Ptr ref2 = getReference (id, false); - + const MWWorld::Ptr ref = mEnvironment.mWorld->getPtr (name, true); - + double diff[3]; - - for (int i=0; i<3; ++i) + + for (int i=0; i<3; ++i) diff[i] = ref.getCellRef().pos.pos[i] - ref2.getCellRef().pos.pos[i]; - + return std::sqrt (diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]); } - - bool InterpreterContext::hasBeenActivated() const + + bool InterpreterContext::hasBeenActivated (const MWWorld::Ptr& ptr) { + if (!mActivated.isEmpty() && mActivated==ptr) + { + mActivationHandled = true; + return true; + } + return false; } - + + bool InterpreterContext::hasActivationBeenHandled() const + { + return mActivationHandled; + } + + void InterpreterContext::activate (const MWWorld::Ptr& ptr, + boost::shared_ptr action) + { + mActivated = ptr; + mActivationHandled = false; + mAction = action; + } + + void InterpreterContext::executeActivation() + { + if (!mAction.get()) + throw std::runtime_error ("activation failed, because no action to perform"); + + mAction->execute (mEnvironment); + mActivationHandled = true; + } + + void InterpreterContext::clearActivation() + { + mActivated = MWWorld::Ptr(); + mActivationHandled = false; + mAction.reset(); + } + float InterpreterContext::getSecondsPassed() const { return mEnvironment.mFrameDuration; } - + bool InterpreterContext::isDisabled (const std::string& id) const { const MWWorld::Ptr ref = getReference (id, false); return !ref.getRefData().isEnabled(); } - + void InterpreterContext::enable (const std::string& id) { MWWorld::Ptr ref = getReference (id, false); mEnvironment.mWorld->enable (ref); } - + void InterpreterContext::disable (const std::string& id) { - MWWorld::Ptr ref = getReference (id, false); + MWWorld::Ptr ref = getReference (id, false); mEnvironment.mWorld->disable (ref); } - + MWGui::WindowManager& InterpreterContext::getWindowManager() { return *mEnvironment.mWindowManager; } - + MWWorld::World& InterpreterContext::getWorld() { return *mEnvironment.mWorld; } - + MWSound::SoundManager& InterpreterContext::getSoundManager() { return *mEnvironment.mSoundManager; } - + MWWorld::Ptr InterpreterContext::getReference() { return getReference ("", true); } } - diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index ee35964b80..e63c4838c3 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -1,11 +1,14 @@ #ifndef GAME_SCRIPT_INTERPRETERCONTEXT_H #define GAME_SCRIPT_INTERPRETERCONTEXT_H +#include + #include #include "../mwworld/ptr.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" +#include "../mwworld/action.hpp" namespace MWSound { @@ -17,80 +20,95 @@ namespace MWScript struct Locals; class InterpreterContext : public Interpreter::Context - { + { MWWorld::Environment& mEnvironment; Locals *mLocals; MWWorld::Ptr mReference; - - + + MWWorld::Ptr mActivated; + bool mActivationHandled; + boost::shared_ptr mAction; + MWWorld::Ptr getReference (const std::string& id, bool activeOnly); const MWWorld::Ptr getReference (const std::string& id, bool activeOnly) const; public: - - InterpreterContext (MWWorld::Environment& environment, + + InterpreterContext (MWWorld::Environment& environment, MWScript::Locals *locals, MWWorld::Ptr reference); ///< The ownership of \a locals is not transferred. 0-pointer allowed. - + virtual int getLocalShort (int index) const; virtual int getLocalLong (int index) const; virtual float getLocalFloat (int index) const; - virtual void setLocalShort (int index, int value); + virtual void setLocalShort (int index, int value); virtual void setLocalLong (int index, int value); virtual void setLocalFloat (int index, float value); - + virtual void messageBox (const std::string& message, - const std::vector& buttons); + const std::vector& buttons); virtual bool menuMode(); - + virtual int getGlobalShort (const std::string& name) const; virtual int getGlobalLong (const std::string& name) const; virtual float getGlobalFloat (const std::string& name) const; - virtual void setGlobalShort (const std::string& name, int value); + virtual void setGlobalShort (const std::string& name, int value); - virtual void setGlobalLong (const std::string& name, int value); + virtual void setGlobalLong (const std::string& name, int value); virtual void setGlobalFloat (const std::string& name, float value); - + virtual bool isScriptRunning (const std::string& name) const; - + virtual void startScript (const std::string& name); - + virtual void stopScript (const std::string& name); - + virtual float getDistance (const std::string& name, const std::string& id = "") const; - - virtual bool hasBeenActivated() const; - + + bool hasBeenActivated (const MWWorld::Ptr& ptr); + ///< \attention Calling this function for the right reference will mark the action as + /// been handled. + + bool hasActivationBeenHandled() const; + + void activate (const MWWorld::Ptr& ptr, boost::shared_ptr action); + ///< Store reference acted upon and action. The actual execution of the action does not + /// take place here. + + void executeActivation(); + ///< Execute the action defined by the last activate call. + + void clearActivation(); + ///< Discard the action defined by the last activate call. + virtual float getSecondsPassed() const; - + virtual bool isDisabled (const std::string& id = "") const; - + virtual void enable (const std::string& id = ""); - + virtual void disable (const std::string& id = ""); - + MWWorld::World& getWorld(); - + MWSound::SoundManager& getSoundManager(); MWGui::WindowManager& getWindowManager(); - + MWWorld::Ptr getReference(); ///< Reference, that the script is running from (can be empty) }; } #endif - - diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 3d865d56fa..1ecfd0c57b 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -16,37 +16,59 @@ namespace MWScript class OpXBox : public Interpreter::Opcode0 { public: - + virtual void execute (Interpreter::Runtime& runtime) { runtime.push (0); - } + } }; - + class OpOnActivate : public Interpreter::Opcode0 { public: - + virtual void execute (Interpreter::Runtime& runtime) { - runtime.push (static_cast ( - runtime.getContext()).hasBeenActivated()); - } + InterpreterContext& context = + static_cast (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + runtime.push (context.hasBeenActivated (ptr)); + } }; - + + class OpActivate : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + context.executeActivation(); + } + }; + const int opcodeXBox = 0x200000c; - const int opcodeOnActivate = 0x200000d; - + const int opcodeOnActivate = 0x200000d; + const int opcodeActivate = 0x2000075; + void registerExtensions (Compiler::Extensions& extensions) { extensions.registerFunction ("xbox", 'l', "", opcodeXBox); extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate); + extensions.registerInstruction ("activate", "", opcodeActivate); } - + void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (opcodeXBox, new OpXBox); interpreter.installSegment5 (opcodeOnActivate, new OpOnActivate); - } - } + interpreter.installSegment5 (opcodeActivate, new OpActivate); + } + } } diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp new file mode 100644 index 0000000000..b318f07963 --- /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 0000000000..509ebc6bbf --- /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/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp new file mode 100644 index 0000000000..2b4aba735c --- /dev/null +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -0,0 +1,16 @@ + +#include "actiontalk.hpp" + +#include "environment.hpp" + +#include "../mwgui/window_manager.hpp" + +namespace MWWorld +{ + ActionTalk::ActionTalk (const Ptr& actor) : mActor (actor) {} + + void ActionTalk::execute (Environment& environment) + { + environment.mWindowManager->setMode (MWGui::GM_Dialogue); + } +} diff --git a/apps/openmw/mwworld/actiontalk.hpp b/apps/openmw/mwworld/actiontalk.hpp new file mode 100644 index 0000000000..034d6131c2 --- /dev/null +++ b/apps/openmw/mwworld/actiontalk.hpp @@ -0,0 +1,21 @@ +#ifndef GAME_MWWORLD_ACTIONTALK_H +#define GAME_MWWORLD_ACTIONTALK_H + +#include "ptr.hpp" +#include "action.hpp" + +namespace MWWorld +{ + class ActionTalk : public Action + { + Ptr mActor; + + public: + + ActionTalk (const Ptr& actor); + + virtual void execute (Environment& environment); + }; +} + +#endif diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 9cca8035eb..85e5140eaf 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -41,6 +41,21 @@ 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 ""; + } + const Class& Class::get (const std::string& key) { std::map >::const_iterator iter = sClasses.find (key); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 9535786e27..28d96d69f2 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,19 @@ 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). + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp new file mode 100644 index 0000000000..c05bfe1561 --- /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 0000000000..7c7e5e5e87 --- /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 0000000000..21e770404b --- /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 0000000000..4b7edfa430 --- /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 919f4f8a02..b041a06cb0 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 73a9d6ad30..c8230f5a8c 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)) { @@ -384,9 +384,9 @@ namespace MWWorld void World::disable (Ptr reference) { - if (!reference.getRefData().isEnabled()) + if (reference.getRefData().isEnabled()) { - reference.getRefData().enable(); + reference.getRefData().disable(); if (MWRender::CellRender *render = searchRender (reference.getCell())) { @@ -544,7 +544,7 @@ namespace MWWorld insertInteriorScripts (*cell); // adjust player - mPlayerPos->setPos (position.pos[0], position.pos[1], position.pos[2]); + mPlayerPos->setPos (position.pos[0], position.pos[1], position.pos[2], true); mPlayerPos->setCell (cell); // TODO orientation @@ -600,4 +600,36 @@ namespace MWWorld { mCellChanged = false; } + + std::string World::getFacedHandle() + { + std::pair result = mScene.getFacedHandle(); + + if (result.first.empty() || + result.second>getStore().gameSettings.find ("iMaxActivateDist")->i) + return ""; + + 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 354c3603c3..2a7b8009a1 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -83,8 +83,6 @@ namespace MWWorld ~World(); - MWRender::MWScene* getMWScene() { return &mScene; } - MWRender::PlayerPos& getPlayerPos(); ESMS::ESMStore& getStore(); @@ -133,6 +131,11 @@ namespace MWWorld ///< works only for interior cells currently. void markCellAsUnchanged(); + + std::string getFacedHandle(); + ///< Return handle of the object the player is looking at + + void deleteObject (Ptr ptr); }; }