diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 047cea760..4eb7aac70 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -51,7 +51,7 @@ add_openmw_dir (mwworld refdata worldimp physicssystem scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors cells localscripts customdata weather inventorystore ptr actionopen actionread - actionequip timestamp actionalchemy cellstore actionapply + actionequip timestamp actionalchemy cellstore actionapply actioneat ) add_openmw_dir (mwclass diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 82bd3b69b..db6edf397 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -162,6 +162,10 @@ void OMW::Engine::loadBSA() dataDirectory = iter->string(); std::cout << "Data dir " << dataDirectory << std::endl; Bsa::addDir(dataDirectory, mFSStrict); + + // Workaround: Mygui does not find textures in non-BSA subfolders, _unless_ they are explicitely added like this + // For splash screens, this is OK to do, but eventually we will need an investigation why this is necessary + Bsa::addDir(dataDirectory + "/Splash", mFSStrict); } } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index bd8b7eb18..58fe180e9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -218,6 +218,7 @@ namespace MWBase virtual void executeInConsole (const std::string& path) = 0; virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total) = 0; + virtual void loadingDone() = 0; }; } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index f0354de76..bdeb0e82b 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -11,6 +11,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/actioneat.hpp" #include "../mwgui/tooltips.hpp" @@ -19,6 +20,14 @@ namespace MWClass { + std::string Ingredient::getId (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->base->mId; + } + void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { const std::string model = getModel(ptr); @@ -84,6 +93,16 @@ namespace MWClass return ref->base->data.value; } + + boost::shared_ptr Ingredient::use (const MWWorld::Ptr& ptr) const + { + boost::shared_ptr action (new MWWorld::ActionEat (ptr)); + + action->setSound ("Swallow"); + + return action; + } + void Ingredient::registerSelf() { boost::shared_ptr instance (new Ingredient); diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 1365c4a71..0afd202fb 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -12,6 +12,9 @@ namespace MWClass public: + virtual std::string getId (const MWWorld::Ptr& ptr) const; + ///< Return ID of \a ptr + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering @@ -37,6 +40,10 @@ namespace MWClass virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 8aab9da56..063f39d2a 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -365,7 +365,7 @@ namespace MWClass /// \todo consider instant effects - return stats.getActiveSpells().addSpell (id); + return stats.getActiveSpells().addSpell (id, actor); } void Npc::skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index d93cc50c3..e41f2eec9 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -11,6 +11,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { @@ -20,6 +22,8 @@ namespace MWGui , WindowBase("openmw_loading_screen.layout", parWindowManager) , mLoadingOn(false) , mLastRenderTime(0.f) + , mLastWallpaperChangeTime(0.f) + , mFirstLoad(true) { getWidget(mLoadingText, "LoadingText"); getWidget(mProgressBar, "ProgressBar"); @@ -77,11 +81,7 @@ namespace MWGui mTotalRefsLoading = total; } - if (mTotalCellsLoading == 0) - { - loadingOff(); - return; - } + assert (mTotalCellsLoading != 0); float refProgress; if (mTotalRefsLoading <= 1) @@ -98,11 +98,6 @@ namespace MWGui float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading); assert(progress <= 1 && progress >= 0); - if (progress >= 1) - { - loadingOff(); - return; - } mLoadingText->setCaption(stage + "... "); mProgressBar->setProgressPosition (static_cast(progress * 1000)); @@ -113,6 +108,11 @@ namespace MWGui { mLastRenderTime = mTimer.getMilliseconds (); + if (mFirstLoad && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 3000*1) + { + mLastWallpaperChangeTime = mTimer.getMilliseconds (); + changeWallpaper(); + } // Turn off rendering except the GUI mSceneMgr->clearSpecialCaseRenderQueues(); @@ -139,8 +139,11 @@ namespace MWGui } else { - mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName()); - mRectangle->setVisible(true); + if (!mFirstLoad) + { + mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName()); + mRectangle->setVisible(true); + } for (unsigned int i = 0; igetNumCompositors(); ++i) { @@ -158,19 +161,37 @@ namespace MWGui { Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), true); } - mRectangle->setVisible(false); } + mRectangle->setVisible(false); + // resume 3d rendering mSceneMgr->clearSpecialCaseRenderQueues(); mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); } } + void LoadingScreen::loadingDone() + { + loadingOff(); + } + void LoadingScreen::loadingOn() { setVisible(true); mLoadingOn = true; + + if (mFirstLoad) + { + changeWallpaper(); + + mWindowManager.pushGuiMode(GM_LoadingWallpaper); + } + else + { + mBackgroundImage->setImageTexture(""); + mWindowManager.pushGuiMode(GM_Loading); + } } @@ -178,5 +199,28 @@ namespace MWGui { setVisible(false); mLoadingOn = false; + mFirstLoad = false; + + mWindowManager.removeGuiMode(GM_Loading); + mWindowManager.removeGuiMode(GM_LoadingWallpaper); + } + + void LoadingScreen::changeWallpaper () + { + /// \todo use a directory listing here + std::vector splash; + splash.push_back ("Splash_Bonelord.tga"); + splash.push_back ("Splash_ClannDaddy.tga"); + splash.push_back ("Splash_Clannfear.tga"); + splash.push_back ("Splash_Daedroth.tga"); + splash.push_back ("Splash_Hunger.tga"); + splash.push_back ("Splash_KwamaWarrior.tga"); + splash.push_back ("Splash_Netch.tga"); + splash.push_back ("Splash_NixHound.tga"); + splash.push_back ("Splash_Siltstriker.tga"); + splash.push_back ("Splash_Skeleton.tga"); + splash.push_back ("Splash_SphereCenturion.tga"); + + mBackgroundImage->setImageTexture (splash[rand() % splash.size()]); } } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index abd59db49..a012793ca 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -15,13 +15,17 @@ namespace MWGui virtual ~LoadingScreen(); void setLoadingProgress (const std::string& stage, int depth, int current, int total); + void loadingDone(); void onResChange(int w, int h); private: + bool mFirstLoad; + Ogre::SceneManager* mSceneMgr; Ogre::RenderWindow* mWindow; + unsigned long mLastWallpaperChangeTime; unsigned long mLastRenderTime; Ogre::Timer mTimer; @@ -43,6 +47,8 @@ namespace MWGui void loadingOn(); void loadingOff(); + + void changeWallpaper(); }; } diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 4417f7b9c..7e1adcf8b 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -35,6 +35,9 @@ namespace MWGui // interactive MessageBox GM_InterMessageBox, + GM_Loading, + GM_LoadingWallpaper, + GM_QuickKeysMenu }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b29980b21..99f476574 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -248,6 +248,8 @@ void WindowManager::updateVisible() mSpellWindow->setVisible(false); mQuickKeysMenu->setVisible(false); + mHud->setVisible(true); + // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); @@ -340,6 +342,13 @@ void WindowManager::updateVisible() case GM_Journal: mJournal->setVisible(true); break; + case GM_LoadingWallpaper: + mHud->setVisible(false); + MyGUI::PointerManager::getInstance().setVisible(false); + break; + case GM_Loading: + MyGUI::PointerManager::getInstance().setVisible(false); + break; default: // Unsupported mode, switch back to game break; @@ -909,3 +918,8 @@ void WindowManager::setLoadingProgress (const std::string& stage, int depth, int { mLoadingScreen->setLoadingProgress (stage, depth, current, total); } + +void WindowManager::loadingDone () +{ + mLoadingScreen->loadingDone (); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 5327bb868..e16b03e43 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -197,6 +197,7 @@ namespace MWGui virtual void executeInConsole (const std::string& path); virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total); + virtual void loadingDone(); private: OEngine::GUI::MyGUIManager *mGuiManager; diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 94b98d3be..67e5bad3d 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -5,12 +5,20 @@ #include #include +#include +#include +#include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/class.hpp" + +#include "creaturestats.hpp" +#include "npcstats.hpp" + namespace MWMechanics { void ActiveSpells::update() const @@ -41,47 +49,102 @@ namespace MWMechanics } if (rebuild) - { - mEffects = MagicEffects(); + rebuildEffects(); + } - for (TIterator iter (begin()); iter!=end(); ++iter) - { - const ESM::EffectList& effects = getEffectList (iter->first); + void ActiveSpells::rebuildEffects() const + { + MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp(); + + mEffects = MagicEffects(); + + for (TIterator iter (begin()); iter!=end(); ++iter) + { + std::pair effects = getEffectList (iter->first); - const MWWorld::TimeStamp& start = iter->second.first; - float magnitude = iter->second.second; + const MWWorld::TimeStamp& start = iter->second.first; + float magnitude = iter->second.second; - for (std::vector::const_iterator iter (effects.list.begin()); - iter!=effects.list.end(); ++iter) + for (std::vector::const_iterator iter (effects.first.list.begin()); + iter!=effects.first.list.end(); ++iter) + { + if (iter->duration) { - if (iter->duration) + int duration = iter->duration; + + if (effects.second) + duration *= magnitude; + + MWWorld::TimeStamp end = start; + end += static_cast (duration)* + MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); + + if (end>now) { - MWWorld::TimeStamp end = start; - end += static_cast (iter->duration)* - MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); - - if (end>now) + EffectParam param; + + if (effects.second) { - EffectParam param; - param.mMagnitude = static_cast ( - (iter->magnMax-iter->magnMin+1)*magnitude + iter->magnMin); - mEffects.add (*iter, param); + const ESM::MagicEffect *magicEffect = + MWBase::Environment::get().getWorld()->getStore().magicEffects.find ( + iter->effectID); + + if (iter->duration==0) + { + param.mMagnitude = + static_cast (magnitude / (0.1 * magicEffect->data.baseCost)); + } + else + { + param.mMagnitude = + static_cast (0.05*magnitude / (0.1 * magicEffect->data.baseCost)); + } } + else + param.mMagnitude = static_cast ( + (iter->magnMax-iter->magnMin)*magnitude + iter->magnMin); + + mEffects.add (*iter, param); } } } - } + } } - const ESM::EffectList& ActiveSpells::getEffectList (const std::string& id) const + std::pair ActiveSpells::getEffectList (const std::string& id) const { if (const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.search (id)) - return spell->effects; + return std::make_pair (spell->effects, false); if (const ESM::Potion *potion = MWBase::Environment::get().getWorld()->getStore().potions.search (id)) - return potion->effects; + return std::make_pair (potion->effects, false); + + if (const ESM::Ingredient *ingredient = + MWBase::Environment::get().getWorld()->getStore().ingreds.search (id)) + { + const ESM::MagicEffect *magicEffect = + MWBase::Environment::get().getWorld()->getStore().magicEffects.find ( + ingredient->data.effectID[0]); + + ESM::ENAMstruct effect; + effect.effectID = ingredient->data.effectID[0]; + effect.skill = ingredient->data.skills[0]; + effect.attribute = ingredient->data.attributes[0]; + effect.range = 0; + effect.area = 0; + effect.duration = magicEffect->data.flags & ESM::MagicEffect::NoDuration ? 0 : 1; + effect.magnMin = 1; + effect.magnMax = 1; + + std::pair result; + + result.first.list.push_back (effect); + result.second = true; + + return result; + } throw std::runtime_error ("ID " + id + " can not produce lasting effects"); } @@ -90,14 +153,14 @@ namespace MWMechanics : mSpellsChanged (false), mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp()) {} - bool ActiveSpells::addSpell (const std::string& id) + bool ActiveSpells::addSpell (const std::string& id, const MWWorld::Ptr& actor) { - const ESM::EffectList& effects = getEffectList (id); + std::pair effects = getEffectList (id); bool found = false; - for (std::vector::const_iterator iter (effects.list.begin()); - iter!=effects.list.end(); ++iter) + for (std::vector::const_iterator iter (effects.first.list.begin()); + iter!=effects.first.list.end(); ++iter) { if (iter->duration) { @@ -113,6 +176,22 @@ namespace MWMechanics float random = static_cast (std::rand()) / RAND_MAX; + if (effects.second) + { + // ingredient -> special treatment required. + const CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); + const NpcStats& npcStats = MWWorld::Class::get (actor).getNpcStats (actor); + + float x = + (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + + 0.2 * creatureStats.getAttribute (1).getModified() + + 0.1 * creatureStats.getAttribute (7).getModified()) + * creatureStats.getFatigueTerm(); + random *= 100; + random = random / std::min (x, 100.0f); + random *= 0.25 * x; + } + if (iter==mSpells.end()) mSpells.insert (std::make_pair (id, std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random))); @@ -155,17 +234,20 @@ namespace MWMechanics double ActiveSpells::timeToExpire (const TIterator& iterator) const { - const ESM::EffectList& effects = getEffectList (iterator->first); + std::pair effects = getEffectList (iterator->first); int duration = 0; - for (std::vector::const_iterator iter (effects.list.begin()); - iter!=effects.list.end(); ++iter) + for (std::vector::const_iterator iter (effects.first.list.begin()); + iter!=effects.first.list.end(); ++iter) { if (iter->duration>duration) duration = iter->duration; } + if (effects.second) + duration *= iterator->second.second; + double scaledDuration = duration * MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 2226cea84..e7a239854 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -15,6 +15,11 @@ namespace ESM struct EffectList; } +namespace MWWorld +{ + class Ptr; +} + namespace MWMechanics { /// \brief Lasting spell effects @@ -36,14 +41,16 @@ namespace MWMechanics mutable MWWorld::TimeStamp mLastUpdate; void update() const; + + void rebuildEffects() const; - const ESM::EffectList& getEffectList (const std::string& id) const; + std::pair getEffectList (const std::string& id) const; public: ActiveSpells(); - bool addSpell (const std::string& id); + bool addSpell (const std::string& id, const MWWorld::Ptr& actor); ///< Overwrites an existing spell with the same ID. If the spell does not have any /// non-instant effects, it is ignored. /// diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 09603bff2..91a9225fe 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -1,58 +1,206 @@ #include "creaturestats.hpp" +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + namespace MWMechanics -{ - CreatureStats::CreatureStats() - {} +{ + const AiSequence& CreatureStats::getAiSequence() const + { + return mAiSequence; + } - // Can't use all benefits of members initialization because of - // lack of copy constructors - CreatureStats::CreatureStats(const CreatureStats &orig) - : mLevel(orig.mLevel), mHello(orig.mHello), mFight(orig.mFight), - mFlee(orig.mFlee), mAlarm(orig.mAlarm) - { - for (int i = 0; i < 8; ++i) { - mAttributes[i] = orig.mAttributes[i]; + AiSequence& CreatureStats::getAiSequence() + { + return mAiSequence; + } + + float CreatureStats::getFatigueTerm() const + { + int max = getFatigue().getModified(); + int current = getFatigue().getCurrent(); + + float normalised = max==0 ? 1 : std::max (0.0f, static_cast (current)/max); + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + return store.gameSettings.find ("fFatigueBase")->getFloat() + - store.gameSettings.find ("fFatigueMult")->getFloat() * (1-normalised); + } + + const Stat &CreatureStats::getAttribute(int index) const + { + if (index < 0 || index > 7) { + throw std::runtime_error("attribute index is out of range"); } - for (int i = 0; i < 3; ++i) { - mDynamic[i] = orig.mDynamic[i]; + return mAttributes[index]; + } + + const DynamicStat &CreatureStats::getHealth() const + { + return mDynamic[0]; + } + + const DynamicStat &CreatureStats::getMagicka() const + { + return mDynamic[1]; + } + + const DynamicStat &CreatureStats::getFatigue() const + { + return mDynamic[2]; + } + + const Spells &CreatureStats::getSpells() const + { + return mSpells; + } + + const ActiveSpells &CreatureStats::getActiveSpells() const + { + return mActiveSpells; + } + + const MagicEffects &CreatureStats::getMagicEffects() const + { + return mMagicEffects; + } + + int CreatureStats::getLevel() const + { + return mLevel; + } + + int CreatureStats::getHello() const + { + return mHello; + } + + int CreatureStats::getFight() const + { + return mFight; + } + + int CreatureStats::getFlee() const + { + return mFlee; + } + + int CreatureStats::getAlarm() const + { + return mAlarm; + } + + Stat &CreatureStats::getAttribute(int index) + { + if (index < 0 || index > 7) { + throw std::runtime_error("attribute index is out of range"); } - mSpells = orig.mSpells; - mActiveSpells = orig.mActiveSpells; - mMagicEffects = orig.mMagicEffects; + return mAttributes[index]; } - CreatureStats::~CreatureStats() - {} + DynamicStat &CreatureStats::getHealth() + { + return mDynamic[0]; + } + + DynamicStat &CreatureStats::getMagicka() + { + return mDynamic[1]; + } + + DynamicStat &CreatureStats::getFatigue() + { + return mDynamic[2]; + } - const CreatureStats & - CreatureStats::operator=(const CreatureStats &orig) + DynamicStat &CreatureStats::getDynamic(int index) { - for (int i = 0; i < 8; ++i) { - mAttributes[i] = orig.mAttributes[i]; + if (index < 0 || index > 2) { + throw std::runtime_error("dynamic stat index is out of range"); } - for (int i = 0; i < 3; ++i) { - mDynamic[i] = orig.mDynamic[i]; + return mDynamic[index]; + } + + Spells &CreatureStats::getSpells() + { + return mSpells; + } + + void CreatureStats::setSpells(const Spells &spells) + { + mSpells = spells; + } + + ActiveSpells &CreatureStats::getActiveSpells() + { + return mActiveSpells; + } + + MagicEffects &CreatureStats::getMagicEffects() + { + return mMagicEffects; + } + + void CreatureStats::setAttribute(int index, const Stat &value) + { + if (index < 0 || index > 7) { + throw std::runtime_error("attribute index is out of range"); } - mLevel = orig.mLevel; - mSpells = orig.mSpells; - mActiveSpells = orig.mActiveSpells; - mMagicEffects = orig.mMagicEffects; - mHello = orig.mHello; - mFight = orig.mFight; - mFlee = orig.mFlee; - mAlarm = orig.mAlarm; + mAttributes[index] = value; + } - return *this; + void CreatureStats::setHealth(const DynamicStat &value) + { + mDynamic[0] = value; } - - const AiSequence& CreatureStats::getAiSequence() const + + void CreatureStats::setMagicka(const DynamicStat &value) { - return mAiSequence; + mDynamic[1] = value; } - - AiSequence& CreatureStats::getAiSequence() + + void CreatureStats::setFatigue(const DynamicStat &value) { - return mAiSequence; + mDynamic[2] = value; + } + + void CreatureStats::setLevel(int level) + { + mLevel = level; + } + + void CreatureStats::setActiveSpells(const ActiveSpells &active) + { + mActiveSpells = active; + } + + void CreatureStats::setMagicEffects(const MagicEffects &effects) + { + mMagicEffects = effects; } + + void CreatureStats::setHello(int value) + { + mHello = value; + } + + void CreatureStats::setFight(int value) + { + mFight = value; + } + + void CreatureStats::setFlee(int value) + { + mFlee = value; + } + + void CreatureStats::setAlarm(int value) + { + mAlarm = value; + } } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index d19972e7b..a6fb6779a 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -31,11 +31,6 @@ namespace MWMechanics AiSequence mAiSequence; public: - CreatureStats(); - CreatureStats(const CreatureStats &); - virtual ~CreatureStats(); - - const CreatureStats & operator=(const CreatureStats &); const Stat & getAttribute(int index) const; @@ -106,185 +101,10 @@ namespace MWMechanics const AiSequence& getAiSequence() const; AiSequence& getAiSequence(); - }; - - // Inline const getters - - inline const Stat & - CreatureStats::getAttribute(int index) const { - if (index < 0 || index > 7) { - throw std::runtime_error("attribute index is out of range"); - } - return mAttributes[index]; - } - - inline const DynamicStat & - CreatureStats::getHealth() const { - return mDynamic[0]; - } - - inline const DynamicStat & - CreatureStats::getMagicka() const { - return mDynamic[1]; - } - - inline const DynamicStat & - CreatureStats::getFatigue() const { - return mDynamic[2]; - } - - inline const Spells & - CreatureStats::getSpells() const { - return mSpells; - } - - inline const ActiveSpells & - CreatureStats::getActiveSpells() const { - return mActiveSpells; - } - - inline const MagicEffects & - CreatureStats::getMagicEffects() const { - return mMagicEffects; - } - - inline int - CreatureStats::getLevel() const { - return mLevel; - } - inline int - CreatureStats::getHello() const { - return mHello; - } - - inline int - CreatureStats::getFight() const { - return mFight; - } - - inline int - CreatureStats::getFlee() const { - return mFlee; - } - - inline int - CreatureStats::getAlarm() const { - return mAlarm; - } - - // Inline non-const getters - - inline Stat & - CreatureStats::getAttribute(int index) { - if (index < 0 || index > 7) { - throw std::runtime_error("attribute index is out of range"); - } - return mAttributes[index]; - } - - inline DynamicStat & - CreatureStats::getHealth() { - return mDynamic[0]; - } - - inline DynamicStat & - CreatureStats::getMagicka() { - return mDynamic[1]; - } - - inline DynamicStat & - CreatureStats::getFatigue() { - return mDynamic[2]; - } - - inline DynamicStat & - CreatureStats::getDynamic(int index) { - if (index < 0 || index > 2) { - throw std::runtime_error("dynamic stat index is out of range"); - } - return mDynamic[index]; - } - - inline Spells & - CreatureStats::getSpells() { - return mSpells; - } - - inline void - CreatureStats::setSpells(const Spells &spells) { - mSpells = spells; - } - - inline ActiveSpells & - CreatureStats::getActiveSpells() { - return mActiveSpells; - } - - inline MagicEffects & - CreatureStats::getMagicEffects() { - return mMagicEffects; - } - - // Inline setters - - inline void - CreatureStats::setAttribute(int index, const Stat &value) { - if (index < 0 || index > 7) { - throw std::runtime_error("attribute index is out of range"); - } - mAttributes[index] = value; - } - - inline void - CreatureStats::setHealth(const DynamicStat &value) { - mDynamic[0] = value; - } - - inline void - CreatureStats::setMagicka(const DynamicStat &value) { - mDynamic[1] = value; - } - - inline void - CreatureStats::setFatigue(const DynamicStat &value) { - mDynamic[2] = value; - } - - inline void - CreatureStats::setLevel(int level) { - mLevel = level; - } - - inline void - CreatureStats::setActiveSpells(const ActiveSpells &active) { - mActiveSpells = active; - } - - inline void - CreatureStats::setMagicEffects(const MagicEffects &effects) { - mMagicEffects = effects; - } - - inline void - CreatureStats::setHello(int value) { - mHello = value; - } - - inline void - CreatureStats::setFight(int value) { - mFight = value; - } - - inline void - CreatureStats::setFlee(int value) { - mFlee = value; - } - - inline void - CreatureStats::setAlarm(int value) { - mAlarm = value; - } + float getFatigueTerm() const; + ///< Return effective fatigue + }; } #endif diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index eba605d0c..60ecd4303 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -11,9 +11,6 @@ #include #include #include -#include -#include -#include #include diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 09d56dbd9..ee1360853 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -24,7 +24,6 @@ namespace Ogre class Entity; class BillboardSet; class TextureUnitState; - class Overlay; } namespace MWRender diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp new file mode 100644 index 000000000..abd1ac4b9 --- /dev/null +++ b/apps/openmw/mwworld/actioneat.cpp @@ -0,0 +1,49 @@ + +#include "actioneat.hpp" + +#include + +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/npcstats.hpp" + +#include "class.hpp" + +namespace MWWorld +{ + void ActionEat::executeImp (const Ptr& actor) + { + // remove used item + getTarget().getRefData().setCount (getTarget().getRefData().getCount()-1); + + // check for success + const MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); + MWMechanics::NpcStats& npcStats = MWWorld::Class::get (actor).getNpcStats (actor); + + float x = + (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + + 0.2 * creatureStats.getAttribute (1).getModified() + + 0.1 * creatureStats.getAttribute (7).getModified()) + * creatureStats.getFatigueTerm(); + + if (x>=100*static_cast (std::rand()) / RAND_MAX) + { + // apply to actor + std::string id = Class::get (getTarget()).getId (getTarget()); + + Class::get (actor).apply (actor, id, actor); + // we ignore the result here. Skill increases no matter if the ingredient did something or not. + + // increase skill + Class::get (actor).skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); + } + } + + ActionEat::ActionEat (const MWWorld::Ptr& object) : Action (false, object) {} +} diff --git a/apps/openmw/mwworld/actioneat.hpp b/apps/openmw/mwworld/actioneat.hpp new file mode 100644 index 000000000..ce5330db7 --- /dev/null +++ b/apps/openmw/mwworld/actioneat.hpp @@ -0,0 +1,19 @@ +#ifndef GAME_MWWORLD_ACTIONEAT_H +#define GAME_MWWORLD_ACTIONEAT_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionEat : public Action + { + virtual void executeImp (const Ptr& actor); + + public: + + ActionEat (const MWWorld::Ptr& object); + }; +} + +#endif diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c3843b831..8a4a09358 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -290,7 +290,6 @@ namespace MWWorld mCurrentCell = *iter; - // adjust player playerCellChange (mCurrentCell, position, adjustPlayerPos); @@ -300,6 +299,8 @@ namespace MWWorld mRendering.switchToExterior(); mCellChanged = true; + + MWBase::Environment::get().getWindowManager ()->loadingDone (); } //We need the ogre renderer and a scene node. @@ -369,6 +370,8 @@ namespace MWWorld MWBase::Environment::get().getWorld()->adjustSky(); mCellChanged = true; + + MWBase::Environment::get().getWindowManager ()->loadingDone (); } void Scene::changeToExteriorCell (const ESM::Position& position) diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index 677642e31..4bd464da6 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -1,8 +1,15 @@ #include "loadgmst.hpp" +#include + +#include "defs.hpp" + namespace ESM { +/// \todo Review GMST "fixing". Probably remove completely or at least make it optional. Its definitely not +/// working properly in its current state and I doubt it can be fixed without breaking other stuff. + // Some handy macros #define cI(s,x) { if(id == (s)) return (i == (x)); } #define cF(s,x) { if(id == (s)) return (f == (x)); } @@ -169,4 +176,32 @@ void GameSetting::load(ESMReader &esm) dirty = true; } +int GameSetting::getInt() const +{ + switch (type) + { + case VT_Float: return static_cast (f); + case VT_Int: return i; + default: throw std::runtime_error ("GMST " + id + " is not of a numeric type"); + } +} + +int GameSetting::getFloat() const +{ + switch (type) + { + case VT_Float: return f; + case VT_Int: return i; + default: throw std::runtime_error ("GMST " + id + " is not of a numeric type"); + } +} + +std::string GameSetting::getString() const +{ + if (type==VT_String) + return str; + + throw std::runtime_error ("GMST " + id + " is not a string"); +} + } diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 01fbc3067..f63028731 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -83,6 +83,15 @@ struct GameSetting bool isDirtyBloodmoon(); void load(ESMReader &esm); + + int getInt() const; + ///< Throws an exception if GMST is not of type int or float. + + int getFloat() const; + ///< Throws an exception if GMST is not of type int or float. + + std::string getString() const; + ///< Throwns an exception if GMST is not of type string. }; } #endif diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 2eda67b61..9aa6b26e3 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -1,5 +1,30 @@ #include "loadmgef.hpp" +namespace +{ + const int NumberOfHardcodedFlags = 143; + const int HardcodedFlags[NumberOfHardcodedFlags] = { + 0x11c8, 0x11c0, 0x11c8, 0x11e0, 0x11e0, 0x11e0, 0x11e0, 0x11d0, + 0x11c0, 0x11c0, 0x11e0, 0x11c0, 0x11184, 0x11184, 0x1f0, 0x1f0, + 0x1f0, 0x11d2, 0x11f0, 0x11d0, 0x11d0, 0x11d1, 0x1d2, 0x1f0, + 0x1d0, 0x1d0, 0x1d1, 0x1f0, 0x11d0, 0x11d0, 0x11d0, 0x11d0, + 0x11d0, 0x11d0, 0x11d0, 0x11d0, 0x11d0, 0x1d0, 0x1d0, 0x11c8, + 0x31c0, 0x11c0, 0x11c0, 0x11c0, 0x1180, 0x11d8, 0x11d8, 0x11d0, + 0x11d0, 0x11180, 0x11180, 0x11180, 0x11180, 0x11180, 0x11180, 0x11180, + 0x11180, 0x11c4, 0x111b8, 0x1040, 0x104c, 0x104c, 0x104c, 0x104c, + 0x1040, 0x1040, 0x1040, 0x11c0, 0x11c0, 0x1cc, 0x1cc, 0x1cc, + 0x1cc, 0x1cc, 0x1c2, 0x1c0, 0x1c0, 0x1c0, 0x1c1, 0x11c2, + 0x11c0, 0x11c0, 0x11c0, 0x11c1, 0x11c0, 0x21192, 0x20190, 0x20190, + 0x20190, 0x21191, 0x11c0, 0x11c0, 0x11c0, 0x11c0, 0x11c0, 0x11c0, + 0x11c0, 0x11c0, 0x11c0, 0x11c0, 0x1c0, 0x11190, 0x9048, 0x9048, + 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, + 0x9048, 0x9048, 0x9048, 0x9048, 0x9048, 0x11c0, 0x1180, 0x1180, + 0x5048, 0x5048, 0x5048, 0x5048, 0x5048, 0x5048, 0x1188, 0x5048, + 0x5048, 0x5048, 0x5048, 0x5048, 0x1048, 0x104c, 0x1048, 0x40, + 0x11c8, 0x1048, 0x1048, 0x1048, 0x1048, 0x1048, 0x1048 + }; +} + namespace ESM { @@ -8,6 +33,10 @@ void MagicEffect::load(ESMReader &esm) esm.getHNT(index, "INDX"); esm.getHNT(data, "MEDT", 36); + + if (index>=0 && indexflags; + // Marker objects: no collision + /// \todo don't do this in the editor + if (node->name.find("marker") != std::string::npos) + { + flags |= 0x800; + } + // Check for extra data Nif::Extra *e = node; while (!e->extra.empty()) @@ -178,12 +185,10 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, // affecting the entire subtree of this node Nif::NiStringExtraData *sd = (Nif::NiStringExtraData*)e; - if (sd->string == "NCO" && !raycastingOnly) + if (sd->string == "NCO") { // No collision. Use an internal flag setting to mark this. - // We ignor this node! flags |= 0x800; - return; } else if (sd->string == "MRK" && !raycastingOnly) // Marker objects. These are only visible in the @@ -229,7 +234,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, } else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { - cShape->collide = true; + cShape->collide = !(flags&0x800); handleNiTriShape(dynamic_cast(node), flags,node->trafo.rotation,node->trafo.pos,node->trafo.scale,raycastingOnly); } else if(node->recType == Nif::RC_RootCollisionNode) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5a5a614ef..5127af966 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -940,6 +940,11 @@ public: { flags |= node->flags; + // Marker objects: just skip the entire node + /// \todo don't do this in the editor + if (node->name.find("marker") != std::string::npos) + return; + Nif::ExtraPtr e = node->extra; while(!e.empty()) {