mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 19:56:38 +00:00 
			
		
		
		
	Merge remote-tracking branch 'scrawl/master'
This commit is contained in:
		
						commit
						6c8e4b27d3
					
				
					 42 changed files with 622 additions and 109 deletions
				
			
		|  | @ -357,9 +357,6 @@ namespace MWClass | |||
|             data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", | ||||
|                                        MWBase::Environment::get().getWorld()->getStore()); | ||||
| 
 | ||||
|             // Relates to NPC gold reset delay
 | ||||
|             data->mNpcStats.setTradeTime(MWWorld::TimeStamp(0.0, 0)); | ||||
| 
 | ||||
|             data->mNpcStats.setGoldPool(gold); | ||||
| 
 | ||||
|             // store
 | ||||
|  |  | |||
|  | @ -233,6 +233,9 @@ namespace MWGui | |||
| 
 | ||||
|             MWBase::World* world = MWBase::Environment::get().getWorld(); | ||||
| 
 | ||||
|             MWBase::Environment::get().getWorld()->breakInvisibility( | ||||
|                         MWBase::Environment::get().getWorld()->getPlayerPtr()); | ||||
| 
 | ||||
|             MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); | ||||
|             MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); | ||||
|             float mouseX = cursorPosition.left / float(viewSize.width); | ||||
|  |  | |||
|  | @ -541,9 +541,11 @@ namespace MWGui | |||
| 
 | ||||
|         int count = object.getRefData().getCount(); | ||||
| 
 | ||||
|         MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); | ||||
|         MWBase::Environment::get().getWorld()->breakInvisibility(player); | ||||
| 
 | ||||
|         // add to player inventory
 | ||||
|         // can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object
 | ||||
|         MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); | ||||
|         MWWorld::Ptr newObject = *player.getClass().getContainerStore (player).add (object, object.getRefData().getCount(), player); | ||||
|         // remove from world
 | ||||
|         MWBase::Environment::get().getWorld()->deleteObject (object); | ||||
|  |  | |||
|  | @ -465,7 +465,18 @@ namespace MWGui | |||
| 
 | ||||
|     void MapWindow::cellExplored(int x, int y) | ||||
|     { | ||||
|         mGlobalMapRender->exploreCell(x,y); | ||||
|         mQueuedToExplore.push_back(std::make_pair(x,y)); | ||||
|     } | ||||
| 
 | ||||
|     void MapWindow::onFrame(float dt) | ||||
|     { | ||||
|         for (std::vector<CellId>::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it) | ||||
|         { | ||||
|             mGlobalMapRender->exploreCell(it->first, it->second); | ||||
|         } | ||||
|         mQueuedToExplore.clear(); | ||||
| 
 | ||||
|         NoDrop::onFrame(dt); | ||||
|     } | ||||
| 
 | ||||
|     void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) | ||||
|  |  | |||
|  | @ -97,14 +97,17 @@ namespace MWGui | |||
| 
 | ||||
|         void renderGlobalMap(Loading::Listener* loadingListener); | ||||
| 
 | ||||
|         void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map
 | ||||
|         // adds the marker to the global map
 | ||||
|         void addVisitedLocation(const std::string& name, int x, int y); | ||||
| 
 | ||||
|         // reveals this cell's map on the global map
 | ||||
|         void cellExplored(int x, int y); | ||||
| 
 | ||||
|         void setGlobalMapPlayerPosition (float worldX, float worldY); | ||||
| 
 | ||||
|         virtual void open(); | ||||
| 
 | ||||
|         void onFrame(float dt) { NoDrop::onFrame(dt); } | ||||
|         void onFrame(float dt); | ||||
| 
 | ||||
|         /// Clear all savegame-specific data
 | ||||
|         void clear(); | ||||
|  | @ -132,6 +135,10 @@ namespace MWGui | |||
|         typedef std::pair<int, int> CellId; | ||||
|         std::vector<CellId> mMarkers; | ||||
| 
 | ||||
|         // Cells that should be explored in the next frame (i.e. their map revealed on the global map)
 | ||||
|         // We can't do this immediately, because the map update is not immediate either (see mNeedMapUpdate in scene.cpp)
 | ||||
|         std::vector<CellId> mQueuedToExplore; | ||||
| 
 | ||||
|         MyGUI::Button* mEventBoxGlobal; | ||||
|         MyGUI::Button* mEventBoxLocal; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1326,9 +1326,6 @@ namespace MWGui | |||
| 
 | ||||
|     void WindowManager::updatePlayer() | ||||
|     { | ||||
|         unsetSelectedSpell(); | ||||
|         unsetSelectedWeapon(); | ||||
| 
 | ||||
|         mInventoryWindow->updatePlayer(); | ||||
|     } | ||||
| 
 | ||||
|  | @ -1425,6 +1422,14 @@ namespace MWGui | |||
| 
 | ||||
|         mQuickKeysMenu->write(writer); | ||||
|         progress.increaseProgress(); | ||||
| 
 | ||||
|         if (!mSelectedSpell.empty()) | ||||
|         { | ||||
|             writer.startRecord(ESM::REC_ASPL); | ||||
|             writer.writeHNString("ID__", mSelectedSpell); | ||||
|             writer.endRecord(ESM::REC_ASPL); | ||||
|             progress.increaseProgress(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type) | ||||
|  | @ -1433,12 +1438,18 @@ namespace MWGui | |||
|             mMap->readRecord(reader, type); | ||||
|         else if (type == ESM::REC_KEYS) | ||||
|             mQuickKeysMenu->readRecord(reader, type); | ||||
|         else if (type == ESM::REC_ASPL) | ||||
|         { | ||||
|             reader.getSubNameIs("ID__"); | ||||
|             mSelectedSpell = reader.getHString(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     int WindowManager::countSavedGameRecords() const | ||||
|     { | ||||
|         return 1 // Global map
 | ||||
|                 + 1; // QuickKeysMenu
 | ||||
|                 + 1 // QuickKeysMenu
 | ||||
|                 + (!mSelectedSpell.empty() ? 1 : 0); | ||||
|     } | ||||
| 
 | ||||
|     bool WindowManager::isSavingAllowed() const | ||||
|  |  | |||
|  | @ -920,9 +920,6 @@ namespace MWMechanics | |||
|                     spells.purge(iter->first.getRefData().getHandle()); | ||||
|                 } | ||||
| 
 | ||||
|                 // FIXME: see http://bugs.openmw.org/issues/869
 | ||||
|                 MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false); | ||||
| 
 | ||||
|                 if (iter->second->kill()) | ||||
|                 { | ||||
|                     ++mDeathCount[cls.getId(iter->first)]; | ||||
|  | @ -939,6 +936,8 @@ namespace MWMechanics | |||
|                     stats.setMagicEffects(MWMechanics::MagicEffects()); | ||||
|                     calculateCreatureStatModifiers(iter->first, 0); | ||||
| 
 | ||||
|                     MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false); | ||||
| 
 | ||||
|                     if (cls.isEssential(iter->first)) | ||||
|                         MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); | ||||
|                 } | ||||
|  |  | |||
|  | @ -17,8 +17,10 @@ namespace MWMechanics | |||
|           mAttacked (false), mHostile (false), | ||||
|           mAttackingOrSpell(false), | ||||
|           mIsWerewolf(false), | ||||
|           mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), | ||||
|           mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f) | ||||
|           mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mKnockdownOneFrame(false), | ||||
|           mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), | ||||
|           mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f), | ||||
|           mTradeTime(0,0), mGoldPool(0) | ||||
|     { | ||||
|         for (int i=0; i<4; ++i) | ||||
|             mAiSettings[i] = 0; | ||||
|  | @ -348,20 +350,6 @@ namespace MWMechanics | |||
|         return mLastHitObject; | ||||
|     } | ||||
| 
 | ||||
|     bool CreatureStats::canUsePower(const std::string &power) const | ||||
|     { | ||||
|         std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.find(power); | ||||
|         if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp()) | ||||
|             return true; | ||||
|         else | ||||
|             return false; | ||||
|     } | ||||
| 
 | ||||
|     void CreatureStats::usePower(const std::string &power) | ||||
|     { | ||||
|         mUsedPowers[power] = MWBase::Environment::get().getWorld()->getTimeStamp(); | ||||
|     } | ||||
| 
 | ||||
|     void CreatureStats::addToFallHeight(float height) | ||||
|     { | ||||
|         mFallHeight += height; | ||||
|  | @ -481,20 +469,75 @@ namespace MWMechanics | |||
| 
 | ||||
|     void CreatureStats::writeState (ESM::CreatureStats& state) const | ||||
|     { | ||||
|         for (int i=0; i<8; ++i) | ||||
|         for (int i=0; i<ESM::Attribute::Length; ++i) | ||||
|             mAttributes[i].writeState (state.mAttributes[i]); | ||||
| 
 | ||||
|         for (int i=0; i<3; ++i) | ||||
|             mDynamic[i].writeState (state.mDynamic[i]); | ||||
| 
 | ||||
|         state.mTradeTime = mTradeTime.toEsm(); | ||||
|         state.mGoldPool = mGoldPool; | ||||
| 
 | ||||
|         state.mDead = mDead; | ||||
|         state.mDied = mDied; | ||||
|         state.mFriendlyHits = mFriendlyHits; | ||||
|         state.mTalkedTo = mTalkedTo; | ||||
|         state.mAlarmed = mAlarmed; | ||||
|         state.mAttacked = mAttacked; | ||||
|         state.mHostile = mHostile; | ||||
|         state.mAttackingOrSpell = mAttackingOrSpell; | ||||
|         // TODO: rewrite. does this really need 3 separate bools?
 | ||||
|         state.mKnockdown = mKnockdown; | ||||
|         state.mKnockdownOneFrame = mKnockdownOneFrame; | ||||
|         state.mKnockdownOverOneFrame = mKnockdownOverOneFrame; | ||||
|         state.mHitRecovery = mHitRecovery; | ||||
|         state.mBlock = mBlock; | ||||
|         state.mMovementFlags = mMovementFlags; | ||||
|         state.mAttackStrength = mAttackStrength; | ||||
|         state.mFallHeight = mFallHeight; | ||||
|         state.mLastHitObject = mLastHitObject; | ||||
|         state.mRecalcDynamicStats = mRecalcDynamicStats; | ||||
|         state.mDrawState = mDrawState; | ||||
|         state.mLevel = mLevel; | ||||
| 
 | ||||
|         mSpells.writeState(state.mSpells); | ||||
|     } | ||||
| 
 | ||||
|     void CreatureStats::readState (const ESM::CreatureStats& state) | ||||
|     { | ||||
|         for (int i=0; i<8; ++i) | ||||
|         for (int i=0; i<ESM::Attribute::Length; ++i) | ||||
|             mAttributes[i].readState (state.mAttributes[i]); | ||||
| 
 | ||||
|         for (int i=0; i<3; ++i) | ||||
|             mDynamic[i].readState (state.mDynamic[i]); | ||||
| 
 | ||||
|         mTradeTime = MWWorld::TimeStamp(state.mTradeTime); | ||||
|         mGoldPool = state.mGoldPool; | ||||
|         mFallHeight = state.mFallHeight; | ||||
| 
 | ||||
|         mDead = state.mDead; | ||||
|         mDied = state.mDied; | ||||
|         mFriendlyHits = state.mFriendlyHits; | ||||
|         mTalkedTo = state.mTalkedTo; | ||||
|         mAlarmed = state.mAlarmed; | ||||
|         mAttacked = state.mAttacked; | ||||
|         mHostile = state.mHostile; | ||||
|         mAttackingOrSpell = state.mAttackingOrSpell; | ||||
|         // TODO: rewrite. does this really need 3 separate bools?
 | ||||
|         mKnockdown = state.mKnockdown; | ||||
|         mKnockdownOneFrame = state.mKnockdownOneFrame; | ||||
|         mKnockdownOverOneFrame = state.mKnockdownOverOneFrame; | ||||
|         mHitRecovery = state.mHitRecovery; | ||||
|         mBlock = state.mBlock; | ||||
|         mMovementFlags = state.mMovementFlags; | ||||
|         mAttackStrength = state.mAttackStrength; | ||||
|         mFallHeight = state.mFallHeight; | ||||
|         mLastHitObject = state.mLastHitObject; | ||||
|         mRecalcDynamicStats = state.mRecalcDynamicStats; | ||||
|         mDrawState = DrawState_(state.mDrawState); | ||||
|         mLevel = state.mLevel; | ||||
| 
 | ||||
|         mSpells.readState(state.mSpells); | ||||
|     } | ||||
| 
 | ||||
|     // Relates to NPC gold reset delay
 | ||||
|  |  | |||
|  | @ -55,15 +55,15 @@ namespace MWMechanics | |||
|         // Do we need to recalculate stats derived from attributes or other factors?
 | ||||
|         bool mRecalcDynamicStats; | ||||
| 
 | ||||
|         std::map<std::string, MWWorld::TimeStamp> mUsedPowers; | ||||
| 
 | ||||
|         MWWorld::TimeStamp mTradeTime; // Relates to NPC gold reset delay
 | ||||
| 
 | ||||
|         int mGoldPool; // the pool of merchant gold not in inventory
 | ||||
| 
 | ||||
|     protected: | ||||
|         // These two are only set by NpcStats, but they are declared in CreatureStats to prevent using virtual methods.
 | ||||
|         bool mIsWerewolf; | ||||
|         AttributeValue mWerewolfAttributes[8]; | ||||
| 
 | ||||
|         int mLevel; | ||||
| 
 | ||||
|     public: | ||||
|  | @ -84,9 +84,6 @@ namespace MWMechanics | |||
|         /// @return total fall height
 | ||||
|         float land(); | ||||
| 
 | ||||
|         bool canUsePower (const std::string& power) const; | ||||
|         void usePower (const std::string& power); | ||||
| 
 | ||||
|         const AttributeValue & getAttribute(int index) const; | ||||
| 
 | ||||
|         const DynamicStat<float> & getHealth() const; | ||||
|  |  | |||
|  | @ -6,9 +6,9 @@ namespace MWMechanics | |||
|     /// \note The _ suffix is required to avoid a collision with a Windoze macro. Die, Microsoft! Die!
 | ||||
|     enum DrawState_ | ||||
|     { | ||||
|         DrawState_Weapon = 0, | ||||
|         DrawState_Spell = 1, | ||||
|         DrawState_Nothing = 2 | ||||
|         DrawState_Nothing = 0, | ||||
|         DrawState_Weapon = 1, | ||||
|         DrawState_Spell = 2 | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -342,7 +342,9 @@ namespace MWMechanics | |||
|             MWWorld::ContainerStoreIterator enchantItem = inv.getSelectedEnchantItem(); | ||||
|             if (enchantItem != inv.end()) | ||||
|                 winMgr->setSelectedEnchantItem(*enchantItem); | ||||
|             else if (winMgr->getSelectedSpell() == "") | ||||
|             else if (!winMgr->getSelectedSpell().empty()) | ||||
|                 winMgr->setSelectedSpell(winMgr->getSelectedSpell(), int(MWMechanics::getSpellSuccessChance(winMgr->getSelectedSpell(), mWatched))); | ||||
|             else | ||||
|                 winMgr->unsetSelectedSpell(); | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -432,9 +432,9 @@ float MWMechanics::NpcStats::getTimeToStartDrowning() const | |||
| { | ||||
|     return mTimeToStartDrowning; | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::NpcStats::setTimeToStartDrowning(float time) | ||||
| { | ||||
|     assert(time>=0 && time<=20); | ||||
|     mTimeToStartDrowning=time; | ||||
| } | ||||
| 
 | ||||
|  | @ -446,11 +446,16 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const | |||
| 
 | ||||
|     state.mDisposition = mDisposition; | ||||
| 
 | ||||
|     for (int i=0; i<27; ++i) | ||||
|     for (int i=0; i<ESM::Skill::Length; ++i) | ||||
|     { | ||||
|         mSkill[i].writeState (state.mSkills[i].mRegular); | ||||
|         mWerewolfSkill[i].writeState (state.mSkills[i].mWerewolf); | ||||
|     } | ||||
|     for (int i=0; i<ESM::Attribute::Length; ++i) | ||||
|     { | ||||
|         mWerewolfAttributes[i].writeState (state.mWerewolfAttributes[i]); | ||||
|     } | ||||
|     state.mIsWerewolf = mIsWerewolf; | ||||
| 
 | ||||
|     state.mCrimeId = mCrimeId; | ||||
| 
 | ||||
|  | @ -467,10 +472,9 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const | |||
|     state.mReputation = mReputation; | ||||
|     state.mWerewolfKills = mWerewolfKills; | ||||
|     state.mProfit = mProfit; | ||||
|     state.mAttackStrength = mAttackStrength; | ||||
|     state.mLevelProgress = mLevelProgress; | ||||
| 
 | ||||
|     for (int i=0; i<8; ++i) | ||||
|     for (int i=0; i<ESM::Attribute::Length; ++i) | ||||
|         state.mSkillIncrease[i] = mSkillIncreases[i]; | ||||
| 
 | ||||
|     std::copy (mUsedIds.begin(), mUsedIds.end(), std::back_inserter (state.mUsedIds)); | ||||
|  | @ -500,21 +504,26 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) | |||
| 
 | ||||
|     mDisposition = state.mDisposition; | ||||
| 
 | ||||
|     for (int i=0; i<27; ++i) | ||||
|     for (int i=0; i<ESM::Skill::Length; ++i) | ||||
|     { | ||||
|         mSkill[i].readState (state.mSkills[i].mRegular); | ||||
|         mWerewolfSkill[i].readState (state.mSkills[i].mWerewolf); | ||||
|     } | ||||
|     for (int i=0; i<ESM::Attribute::Length; ++i) | ||||
|     { | ||||
|         mWerewolfAttributes[i].readState (state.mWerewolfAttributes[i]); | ||||
|     } | ||||
| 
 | ||||
|     mIsWerewolf = state.mIsWerewolf; | ||||
| 
 | ||||
|     mCrimeId = state.mCrimeId; | ||||
|     mBounty = state.mBounty; | ||||
|     mReputation = state.mReputation; | ||||
|     mWerewolfKills = state.mWerewolfKills; | ||||
|     mProfit = state.mProfit; | ||||
|     mAttackStrength = state.mAttackStrength; | ||||
|     mLevelProgress = state.mLevelProgress; | ||||
| 
 | ||||
|     for (int i=0; i<8; ++i) | ||||
|     for (int i=0; i<ESM::Attribute::Length; ++i) | ||||
|         mSkillIncreases[i] = state.mSkillIncrease[i]; | ||||
| 
 | ||||
|     for (std::vector<std::string>::const_iterator iter (state.mUsedIds.begin()); | ||||
|  |  | |||
|  | @ -31,8 +31,8 @@ namespace MWMechanics | |||
|             std::map<std::string, int> mFactionRank; | ||||
| 
 | ||||
|             int mDisposition; | ||||
|             SkillValue mSkill[27]; | ||||
|             SkillValue mWerewolfSkill[27]; | ||||
|             SkillValue mSkill[ESM::Skill::Length]; | ||||
|             SkillValue mWerewolfSkill[ESM::Skill::Length]; | ||||
|             int mBounty; | ||||
|             std::set<std::string> mExpelled; | ||||
|             std::map<std::string, int> mFactionReputation; | ||||
|  | @ -40,7 +40,6 @@ namespace MWMechanics | |||
|             int mCrimeId; | ||||
|             int mWerewolfKills; | ||||
|             int mProfit; | ||||
|             float mAttackStrength; | ||||
| 
 | ||||
|             int mLevelProgress; // 0-10
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include <cstdlib> | ||||
| 
 | ||||
| #include <components/esm/loadspel.hpp> | ||||
| #include <components/esm/spellstate.hpp> | ||||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
|  | @ -30,10 +31,19 @@ namespace MWMechanics | |||
|         { | ||||
|             const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId); | ||||
| 
 | ||||
|             std::vector<float> random; | ||||
|             random.resize(spell->mEffects.mList.size()); | ||||
|             for (unsigned int i=0; i<random.size();++i) | ||||
|                 random[i] = static_cast<float> (std::rand()) / RAND_MAX; | ||||
|             std::map<const int, float> random; | ||||
| 
 | ||||
|             // Determine the random magnitudes (unless this is a castable spell, in which case
 | ||||
|             // they will be determined when the spell is cast)
 | ||||
|             if (spell->mData.mType != ESM::Spell::ST_Power && spell->mData.mType != ESM::Spell::ST_Spell) | ||||
|             { | ||||
|                 for (unsigned int i=0; i<spell->mEffects.mList.size();++i) | ||||
|                 { | ||||
|                     if (spell->mEffects.mList[i].mMagnMin != spell->mEffects.mList[i].mMagnMax) | ||||
|                         random[i] = static_cast<float> (std::rand()) / RAND_MAX; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             mSpells.insert (std::make_pair (Misc::StringUtils::lowerCase(spellId), random)); | ||||
|         } | ||||
|     } | ||||
|  | @ -67,7 +77,11 @@ namespace MWMechanics | |||
|                 int i=0; | ||||
|                 for (std::vector<ESM::ENAMstruct>::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it) | ||||
|                 { | ||||
|                     effects.add (*it, it->mMagnMin + (it->mMagnMax - it->mMagnMin) * iter->second[i]); | ||||
|                     float random = 1.f; | ||||
|                     if (iter->second.find(i) != iter->second.end()) | ||||
|                         random = iter->second.at(i); | ||||
| 
 | ||||
|                     effects.add (*it, it->mMagnMin + (it->mMagnMax - it->mMagnMin) * random); | ||||
|                     ++i; | ||||
|                 } | ||||
|             } | ||||
|  | @ -192,9 +206,60 @@ namespace MWMechanics | |||
|             for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = list.mList.begin(); | ||||
|                  effectIt != list.mList.end(); ++effectIt, ++i) | ||||
|             { | ||||
|                 float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * it->second[i]; | ||||
|                 float random = 1.f; | ||||
|                 if (it->second.find(i) != it->second.end()) | ||||
|                     random = it->second.at(i); | ||||
| 
 | ||||
|                 float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; | ||||
|                 visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, "", magnitude); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool Spells::canUsePower(const std::string &power) const | ||||
|     { | ||||
|         std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.find(power); | ||||
|         if (it == mUsedPowers.end() || it->second + 24 <= MWBase::Environment::get().getWorld()->getTimeStamp()) | ||||
|             return true; | ||||
|         else | ||||
|             return false; | ||||
|     } | ||||
| 
 | ||||
|     void Spells::usePower(const std::string &power) | ||||
|     { | ||||
|         mUsedPowers[power] = MWBase::Environment::get().getWorld()->getTimeStamp(); | ||||
|     } | ||||
| 
 | ||||
|     void Spells::readState(const ESM::SpellState &state) | ||||
|     { | ||||
|         mSpells = state.mSpells; | ||||
|         mSelectedSpell = state.mSelectedSpell; | ||||
| 
 | ||||
|         // Discard spells that are no longer available due to changed content files
 | ||||
|         for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();) | ||||
|         { | ||||
|             const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(iter->first); | ||||
|             if (!spell) | ||||
|             { | ||||
|                 if (iter->first == mSelectedSpell) | ||||
|                     mSelectedSpell = ""; | ||||
|                 mSpells.erase(iter++); | ||||
|             } | ||||
|             else | ||||
|                 ++iter; | ||||
|         } | ||||
| 
 | ||||
|         // No need to discard spells here (doesn't really matter if non existent ids are kept)
 | ||||
|         for (std::map<std::string, ESM::TimeStamp>::const_iterator it = state.mUsedPowers.begin(); it != state.mUsedPowers.end(); ++it) | ||||
|             mUsedPowers[it->first] = MWWorld::TimeStamp(it->second); | ||||
|     } | ||||
| 
 | ||||
|     void Spells::writeState(ESM::SpellState &state) const | ||||
|     { | ||||
|         state.mSpells = mSpells; | ||||
|         state.mSelectedSpell = mSelectedSpell; | ||||
| 
 | ||||
|         for (std::map<std::string, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it) | ||||
|             state.mUsedPowers[it->first] = it->second.toEsm(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -7,12 +7,16 @@ | |||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| #include "../mwworld/ptr.hpp" | ||||
| #include "../mwworld/timestamp.hpp" | ||||
| 
 | ||||
| #include "magiceffects.hpp" | ||||
| 
 | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     struct Spell; | ||||
| 
 | ||||
|     struct SpellState; | ||||
| } | ||||
| 
 | ||||
| namespace MWMechanics | ||||
|  | @ -22,21 +26,29 @@ namespace MWMechanics | |||
|     /// \brief Spell list
 | ||||
|     ///
 | ||||
|     /// This class manages known spells as well as abilities, powers and permanent negative effects like
 | ||||
|     /// diseases.
 | ||||
|     /// diseases. It also keeps track of used powers (which can only be used every 24h).
 | ||||
|     class Spells | ||||
|     { | ||||
|         public: | ||||
| 
 | ||||
|             typedef std::map<std::string, std::vector<float> > TContainer; // ID, normalised magnitudes
 | ||||
| 
 | ||||
|             typedef std::map<std::string, std::map<const int, float> > TContainer; // ID, <effect index, normalised random magnitude>
 | ||||
|             typedef TContainer::const_iterator TIterator; | ||||
| 
 | ||||
|         private: | ||||
| 
 | ||||
|             TContainer mSpells; | ||||
| 
 | ||||
|             // Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different)
 | ||||
|             std::string mSelectedSpell; | ||||
| 
 | ||||
|             std::map<std::string, MWWorld::TimeStamp> mUsedPowers; | ||||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|             bool canUsePower (const std::string& power) const; | ||||
|             void usePower (const std::string& power); | ||||
| 
 | ||||
|             void purgeCommonDisease(); | ||||
|             void purgeBlightDisease(); | ||||
|             void purgeCorprusDisease(); | ||||
|  | @ -72,6 +84,9 @@ namespace MWMechanics | |||
|             bool hasBlightDisease() const; | ||||
| 
 | ||||
|             void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor) const; | ||||
| 
 | ||||
|             void readState (const ESM::SpellState& state); | ||||
|             void writeState (ESM::SpellState& state) const; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -168,7 +168,10 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) | |||
| 
 | ||||
|     mCameraPosNode->setPosition(Vector3(0,0,0)); | ||||
| 
 | ||||
|     render((x+0.5)*sSize, (y+0.5)*sSize, zMin, zMax, sSize, sSize, name); | ||||
|     // Note: using force=true for exterior cell maps.
 | ||||
|     // They must be updated even if they were visited before, because the set of surrounding active cells might be different
 | ||||
|     // (and objects in a different cell can "bleed" into another cell's map if they cross the border)
 | ||||
|     render((x+0.5)*sSize, (y+0.5)*sSize, zMin, zMax, sSize, sSize, name, true); | ||||
| 
 | ||||
|     if (mBuffers.find(name) == mBuffers.end()) | ||||
|     { | ||||
|  | @ -296,7 +299,8 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, | |||
|                 ESM::FogState* fog = cell->getFog(); | ||||
| 
 | ||||
|                 // We are using the same bounds and angle as we were using when the textures were originally made. Segments should come out the same.
 | ||||
|                 assert (i < int(fog->mFogTextures.size())); | ||||
|                 if (i >= int(fog->mFogTextures.size())) | ||||
|                     throw std::runtime_error("fog texture count mismatch"); | ||||
| 
 | ||||
|                 ESM::FogTexture& esm = fog->mFogTextures[i]; | ||||
|                 loadFogOfWar(texturePrefix, esm); | ||||
|  | @ -338,8 +342,6 @@ Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName) | |||
|                         PF_A8R8G8B8, | ||||
|                         TU_DYNAMIC_WRITE_ONLY); | ||||
|     } | ||||
|     else | ||||
|         tex->unload(); | ||||
| 
 | ||||
|     return tex; | ||||
| } | ||||
|  | @ -351,12 +353,14 @@ void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& | |||
|     Ogre::Image image; | ||||
|     image.load(stream, "tga"); | ||||
| 
 | ||||
|     assert (image.getWidth() == sFogOfWarResolution && image.getHeight() == sFogOfWarResolution); | ||||
|     if (image.getWidth() != sFogOfWarResolution || image.getHeight() != sFogOfWarResolution) | ||||
|         throw std::runtime_error("fog texture size mismatch"); | ||||
| 
 | ||||
|     std::string texName = texturePrefix + "_fog"; | ||||
| 
 | ||||
|     Ogre::TexturePtr tex = createFogOfWarTexture(texName); | ||||
| 
 | ||||
|     tex->unload(); | ||||
|     tex->loadImage(image); | ||||
| 
 | ||||
|     // create a buffer to use for dynamic operations
 | ||||
|  | @ -369,7 +373,7 @@ void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& | |||
| 
 | ||||
| void LocalMap::render(const float x, const float y, | ||||
|                     const float zlow, const float zhigh, | ||||
|                     const float xw, const float yw, const std::string& texture) | ||||
|                     const float xw, const float yw, const std::string& texture, bool force) | ||||
| { | ||||
|     mCellCamera->setFarClipDistance( (zhigh-zlow) + 2000 ); | ||||
|     mCellCamera->setNearClipDistance(50); | ||||
|  | @ -408,6 +412,11 @@ void LocalMap::render(const float x, const float y, | |||
|                         PF_R8G8B8); | ||||
|         tex->getBuffer()->blit(mRenderTexture->getBuffer()); | ||||
|     } | ||||
|     else if (force) | ||||
|     { | ||||
|         mRenderTarget->update(); | ||||
|         tex->getBuffer()->blit(mRenderTexture->getBuffer()); | ||||
|     } | ||||
| 
 | ||||
|     mRenderingManager->enableLights(true); | ||||
|     mLight->setVisible(false); | ||||
|  |  | |||
|  | @ -106,10 +106,11 @@ namespace MWRender | |||
|         float mAngle; | ||||
|         const Ogre::Vector2 rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle); | ||||
| 
 | ||||
|         /// @param force Always render, even if we already have a cached map
 | ||||
|         void render(const float x, const float y, | ||||
|                     const float zlow, const float zhigh, | ||||
|                     const float xw, const float yw, | ||||
|                     const std::string& texture); | ||||
|                     const std::string& texture, bool force=false); | ||||
| 
 | ||||
|         // Creates a fog of war texture and initializes it to full black
 | ||||
|         void createFogOfWar(const std::string& texturePrefix); | ||||
|  |  | |||
|  | @ -380,6 +380,10 @@ void RenderingManager::update (float duration, bool paused) | |||
| 
 | ||||
|     mCamera->update(duration, paused); | ||||
| 
 | ||||
|     Ogre::SceneNode *node = data.getBaseNode(); | ||||
|     Ogre::Quaternion orient = node->_getDerivedOrientation(); | ||||
|     mLocalMap->updatePlayer(playerPos, orient); | ||||
| 
 | ||||
|     if(paused) | ||||
|         return; | ||||
| 
 | ||||
|  | @ -393,10 +397,6 @@ void RenderingManager::update (float duration, bool paused) | |||
| 
 | ||||
|     mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); | ||||
| 
 | ||||
|     Ogre::SceneNode *node = data.getBaseNode(); | ||||
|     Ogre::Quaternion orient = node->_getDerivedOrientation(); | ||||
| 
 | ||||
|     mLocalMap->updatePlayer(playerPos, orient); | ||||
| 
 | ||||
|     mWater->updateUnderwater(world->isUnderwater(player.getCell(), cam)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -326,6 +326,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl | |||
| 
 | ||||
|                 case ESM::REC_GMAP: | ||||
|                 case ESM::REC_KEYS: | ||||
|                 case ESM::REC_ASPL: | ||||
| 
 | ||||
|                     MWBase::Environment::get().getWindowManager()->readRecord(reader, n.val); | ||||
|                     break; | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,9 @@ | |||
| 
 | ||||
| #include "class.hpp" | ||||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| 
 | ||||
| namespace MWWorld | ||||
| { | ||||
|     ActionApply::ActionApply (const Ptr& target, const std::string& id) | ||||
|  | @ -11,6 +14,8 @@ namespace MWWorld | |||
| 
 | ||||
|     void ActionApply::executeImp (const Ptr& actor) | ||||
|     { | ||||
|         MWBase::Environment::get().getWorld()->breakInvisibility(actor); | ||||
| 
 | ||||
|         MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor); | ||||
|     } | ||||
| 
 | ||||
|  | @ -22,6 +27,8 @@ namespace MWWorld | |||
| 
 | ||||
|     void ActionApplyWithSkill::executeImp (const Ptr& actor) | ||||
|     { | ||||
|         MWBase::Environment::get().getWorld()->breakInvisibility(actor); | ||||
| 
 | ||||
|         if (MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor) && mUsageType!=-1) | ||||
|             MWWorld::Class::get (getTarget()).skillUsageSucceeded (actor, mSkillIndex, mUsageType); | ||||
|     } | ||||
|  |  | |||
|  | @ -199,7 +199,7 @@ void ESMStore::setUp() | |||
| 
 | ||||
|                     if (!mRaces.find (player->mRace) || | ||||
|                         !mClasses.find (player->mClass)) | ||||
|                         throw std::runtime_error ("Invalid player record (race or class unavilable"); | ||||
|                         throw std::runtime_error ("Invalid player record (race or class unavailable"); | ||||
|                 } | ||||
| 
 | ||||
|                 return true; | ||||
|  |  | |||
|  | @ -87,6 +87,7 @@ namespace MWWorld | |||
|                 float mMultiplier; | ||||
|             }; | ||||
| 
 | ||||
|             // TODO: store in savegame
 | ||||
|             typedef std::map<std::string, std::vector<EffectParams> > TEffectMagnitudes; | ||||
|             TEffectMagnitudes mPermanentMagicEffectMagnitudes; | ||||
| 
 | ||||
|  |  | |||
|  | @ -626,12 +626,12 @@ namespace MWWorld | |||
|                 bool cmode = act->getCollisionMode(); | ||||
|                 if(cmode) | ||||
|                 { | ||||
|                     act->enableCollisions(false); | ||||
|                     act->enableCollisionMode(false); | ||||
|                     return false; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     act->enableCollisions(true); | ||||
|                     act->enableCollisionMode(true); | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|  |  | |||
|  | @ -85,7 +85,17 @@ namespace | |||
| namespace MWWorld | ||||
| { | ||||
| 
 | ||||
|     void Scene::update (float duration, bool paused){ | ||||
|     void Scene::update (float duration, bool paused) | ||||
|     { | ||||
|         if (mNeedMapUpdate) | ||||
|         { | ||||
|             // Note: exterior cell maps must be updated, even if they were visited before, because the set of surrounding cells might be different
 | ||||
|             // (and objects in a different cell can "bleed" into another cells map if they cross the border)
 | ||||
|             for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) | ||||
|                 mRendering.requestMap(*active); | ||||
|             mNeedMapUpdate = false; | ||||
|         } | ||||
| 
 | ||||
|         mRendering.update (duration, paused); | ||||
|     } | ||||
| 
 | ||||
|  | @ -197,8 +207,9 @@ namespace MWWorld | |||
| 
 | ||||
|         mRendering.updateTerrain(); | ||||
| 
 | ||||
|         for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) | ||||
|             mRendering.requestMap(*active); | ||||
|         // Delay the map update until scripts have been given a chance to run.
 | ||||
|         // If we don't do this, objects that should be disabled will still appear on the map.
 | ||||
|         mNeedMapUpdate = true; | ||||
| 
 | ||||
|         MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); | ||||
|     } | ||||
|  | @ -342,7 +353,7 @@ namespace MWWorld | |||
| 
 | ||||
|     //We need the ogre renderer and a scene node.
 | ||||
|     Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) | ||||
|     : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering) | ||||
|     : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNeedMapUpdate(false) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -58,6 +58,8 @@ namespace MWWorld | |||
|             PhysicsSystem *mPhysics; | ||||
|             MWRender::RenderingManager& mRendering; | ||||
| 
 | ||||
|             bool mNeedMapUpdate; | ||||
| 
 | ||||
|             void playerCellChange (CellStore *cell, const ESM::Position& position, | ||||
|                 bool adjustPlayerPos = true); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| 
 | ||||
| #include "timestamp.hpp" | ||||
| 
 | ||||
| #include <cmath> | ||||
| 
 | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| #include <components/esm/defs.hpp> | ||||
| 
 | ||||
| namespace MWWorld | ||||
| { | ||||
|     TimeStamp::TimeStamp (float hour, int day) | ||||
|  | @ -105,4 +105,18 @@ namespace MWWorld | |||
| 
 | ||||
|         return hours + 24*days; | ||||
|     } | ||||
| 
 | ||||
|     ESM::TimeStamp TimeStamp::toEsm() const | ||||
|     { | ||||
|         ESM::TimeStamp ret; | ||||
|         ret.mDay = mDay; | ||||
|         ret.mHour = mHour; | ||||
|         return ret; | ||||
|     } | ||||
| 
 | ||||
|     TimeStamp::TimeStamp(const ESM::TimeStamp &esm) | ||||
|     { | ||||
|         mDay = esm.mDay; | ||||
|         mHour = esm.mHour; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,11 @@ | |||
| #ifndef GAME_MWWORLD_TIMESTAMP_H | ||||
| #define GAME_MWWORLD_TIMESTAMP_H | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class TimeStamp; | ||||
| } | ||||
| 
 | ||||
| namespace MWWorld | ||||
| { | ||||
|     /// \brief In-game time stamp
 | ||||
|  | @ -14,9 +19,12 @@ namespace MWWorld | |||
|         public: | ||||
| 
 | ||||
|             explicit TimeStamp (float hour = 0, int day = 0); | ||||
|             ///< \oaram hour [0, 23)
 | ||||
|             ///< \param hour [0, 23)
 | ||||
|             /// \param day >=0
 | ||||
| 
 | ||||
|             explicit TimeStamp (const ESM::TimeStamp& esm); | ||||
|             ESM::TimeStamp toEsm () const; | ||||
| 
 | ||||
|             float getHour() const; | ||||
| 
 | ||||
|             int getDay() const; | ||||
|  |  | |||
|  | @ -1491,6 +1491,9 @@ namespace MWWorld | |||
|         { | ||||
|             MWWorld::LiveCellRef<ESM::Door>& ref = *it; | ||||
| 
 | ||||
|             if (!ref.mData.isEnabled()) | ||||
|                 continue; | ||||
| 
 | ||||
|             if (ref.mRef.mTeleport) | ||||
|             { | ||||
|                 World::DoorMarker newMarker; | ||||
|  | @ -1954,7 +1957,7 @@ namespace MWWorld | |||
|     { | ||||
|         OEngine::Physic::PhysicActor *physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); | ||||
| 
 | ||||
|         physicActor->enableCollisions(enable); | ||||
|         physicActor->enableCollisionBody(enable); | ||||
|     } | ||||
| 
 | ||||
|     bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) | ||||
|  | @ -2161,8 +2164,8 @@ namespace MWWorld | |||
|             // If this is a power, check if it was already used in the last 24h
 | ||||
|             if (!fail && spell->mData.mType == ESM::Spell::ST_Power) | ||||
|             { | ||||
|                 if (stats.canUsePower(spell->mId)) | ||||
|                     stats.usePower(spell->mId); | ||||
|                 if (stats.getSpells().canUsePower(spell->mId)) | ||||
|                     stats.getSpells().usePower(spell->mId); | ||||
|                 else | ||||
|                 { | ||||
|                     message = "#{sPowerAlreadyUsed}"; | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ add_component_dir (esm | |||
|     loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat | ||||
|     loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter | ||||
|     savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate | ||||
|     npcstats creaturestats weatherstate quickkeys fogstate | ||||
|     npcstats creaturestats weatherstate quickkeys fogstate spellstate | ||||
|     ) | ||||
| 
 | ||||
| add_component_dir (misc | ||||
|  |  | |||
|  | @ -8,13 +8,143 @@ void ESM::CreatureStats::load (ESMReader &esm) | |||
| 
 | ||||
|     for (int i=0; i<3; ++i) | ||||
|         mDynamic[i].load (esm); | ||||
| 
 | ||||
|     mGoldPool = 0; | ||||
|     esm.getHNOT (mGoldPool, "GOLD"); | ||||
| 
 | ||||
|     mTradeTime.mDay = 0; | ||||
|     mTradeTime.mHour = 0; | ||||
|     esm.getHNOT (mTradeTime, "TIME"); | ||||
| 
 | ||||
|     mDead = false; | ||||
|     esm.getHNOT (mDead, "DEAD"); | ||||
| 
 | ||||
|     mDied = false; | ||||
|     esm.getHNOT (mDied, "DIED"); | ||||
| 
 | ||||
|     mFriendlyHits = 0; | ||||
|     esm.getHNOT (mFriendlyHits, "FRHT"); | ||||
| 
 | ||||
|     mTalkedTo = false; | ||||
|     esm.getHNOT (mTalkedTo, "TALK"); | ||||
| 
 | ||||
|     mAlarmed = false; | ||||
|     esm.getHNOT (mAlarmed, "ALRM"); | ||||
| 
 | ||||
|     mHostile = false; | ||||
|     esm.getHNOT (mHostile, "HOST"); | ||||
| 
 | ||||
|     mAttackingOrSpell = false; | ||||
|     esm.getHNOT (mAttackingOrSpell, "ATCK"); | ||||
| 
 | ||||
|     mKnockdown = false; | ||||
|     esm.getHNOT (mKnockdown, "KNCK"); | ||||
| 
 | ||||
|     mKnockdownOneFrame = false; | ||||
|     esm.getHNOT (mKnockdownOneFrame, "KNC1"); | ||||
| 
 | ||||
|     mKnockdownOverOneFrame = false; | ||||
|     esm.getHNOT (mKnockdownOverOneFrame, "KNCO"); | ||||
| 
 | ||||
|     mHitRecovery = false; | ||||
|     esm.getHNOT (mHitRecovery, "HITR"); | ||||
| 
 | ||||
|     mBlock = false; | ||||
|     esm.getHNOT (mBlock, "BLCK"); | ||||
| 
 | ||||
|     mMovementFlags = 0; | ||||
|     esm.getHNOT (mMovementFlags, "MOVE"); | ||||
| 
 | ||||
|     mAttackStrength = 0; | ||||
|     esm.getHNOT (mAttackStrength, "ASTR"); | ||||
| 
 | ||||
|     mFallHeight = 0; | ||||
|     esm.getHNOT (mFallHeight, "FALL"); | ||||
| 
 | ||||
|     mLastHitObject = esm.getHNOString ("LHIT"); | ||||
| 
 | ||||
|     mRecalcDynamicStats = false; | ||||
|     esm.getHNOT (mRecalcDynamicStats, "CALC"); | ||||
| 
 | ||||
|     mDrawState = 0; | ||||
|     esm.getHNOT (mDrawState, "DRAW"); | ||||
| 
 | ||||
|     mLevel = 1; | ||||
|     esm.getHNOT (mLevel, "LEVL"); | ||||
| 
 | ||||
|     mSpells.load(esm); | ||||
| } | ||||
| 
 | ||||
| void ESM::CreatureStats::save (ESMWriter &esm) const | ||||
| { | ||||
| 
 | ||||
|     for (int i=0; i<8; ++i) | ||||
|         mAttributes[i].save (esm); | ||||
| 
 | ||||
|     for (int i=0; i<3; ++i) | ||||
|         mDynamic[i].save (esm); | ||||
| } | ||||
| 
 | ||||
|     if (mGoldPool) | ||||
|         esm.writeHNT ("GOLD", mGoldPool); | ||||
| 
 | ||||
|     esm.writeHNT ("TIME", mTradeTime); | ||||
| 
 | ||||
|     if (mDead) | ||||
|         esm.writeHNT ("DEAD", mDead); | ||||
| 
 | ||||
|     if (mDied) | ||||
|         esm.writeHNT ("DIED", mDied); | ||||
| 
 | ||||
|     if (mFriendlyHits) | ||||
|         esm.writeHNT ("FRHT", mFriendlyHits); | ||||
| 
 | ||||
|     if (mTalkedTo) | ||||
|         esm.writeHNT ("TALK", mTalkedTo); | ||||
| 
 | ||||
|     if (mAlarmed) | ||||
|         esm.writeHNT ("ALRM", mAlarmed); | ||||
| 
 | ||||
|     if (mHostile) | ||||
|         esm.writeHNT ("HOST", mHostile); | ||||
| 
 | ||||
|     if (mAttackingOrSpell) | ||||
|         esm.writeHNT ("ATCK", mAttackingOrSpell); | ||||
| 
 | ||||
|     if (mKnockdown) | ||||
|         esm.writeHNT ("KNCK", mKnockdown); | ||||
| 
 | ||||
|     if (mKnockdownOneFrame) | ||||
|         esm.writeHNT ("KNC1", mKnockdownOneFrame); | ||||
| 
 | ||||
|     if (mKnockdownOverOneFrame) | ||||
|         esm.writeHNT ("KNCO", mKnockdownOverOneFrame); | ||||
| 
 | ||||
|     if (mHitRecovery) | ||||
|         esm.writeHNT ("HITR", mHitRecovery); | ||||
| 
 | ||||
|     if (mBlock) | ||||
|         esm.writeHNT ("BLCK", mBlock); | ||||
| 
 | ||||
|     if (mMovementFlags) | ||||
|         esm.writeHNT ("MOVE", mMovementFlags); | ||||
| 
 | ||||
|     if (mAttackStrength) | ||||
|         esm.writeHNT ("ASTR", mAttackStrength); | ||||
| 
 | ||||
|     if (mFallHeight) | ||||
|         esm.writeHNT ("FALL", mFallHeight); | ||||
| 
 | ||||
|     if (!mLastHitObject.empty()) | ||||
|         esm.writeHNString ("LHIT", mLastHitObject); | ||||
| 
 | ||||
|     if (mRecalcDynamicStats) | ||||
|         esm.writeHNT ("CALC", mRecalcDynamicStats); | ||||
| 
 | ||||
|     if (mDrawState) | ||||
|         esm.writeHNT ("DRAW", mDrawState); | ||||
| 
 | ||||
|     if (mLevel != 1) | ||||
|         esm.writeHNT ("LEVL", mLevel); | ||||
| 
 | ||||
|     mSpells.save(esm); | ||||
| } | ||||
|  |  | |||
|  | @ -7,21 +7,51 @@ | |||
| 
 | ||||
| #include "statstate.hpp" | ||||
| 
 | ||||
| #include "defs.hpp" | ||||
| 
 | ||||
| #include "spellstate.hpp" | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class ESMReader; | ||||
|     class ESMWriter; | ||||
| 
 | ||||
|     // format 0, saved games only
 | ||||
| 
 | ||||
|     struct CreatureStats | ||||
|     { | ||||
|         StatState<int> mAttributes[8]; | ||||
|         StatState<float> mDynamic[3]; | ||||
| 
 | ||||
|         ESM::TimeStamp mTradeTime; | ||||
|         int mGoldPool; | ||||
| 
 | ||||
|         bool mDead; | ||||
|         bool mDied; | ||||
|         int mFriendlyHits; | ||||
|         bool mTalkedTo; | ||||
|         bool mAlarmed; | ||||
|         bool mAttacked; | ||||
|         bool mHostile; | ||||
|         bool mAttackingOrSpell; | ||||
|         bool mKnockdown; | ||||
|         bool mKnockdownOneFrame; | ||||
|         bool mKnockdownOverOneFrame; | ||||
|         bool mHitRecovery; | ||||
|         bool mBlock; | ||||
|         unsigned int mMovementFlags; | ||||
|         float mAttackStrength; | ||||
|         float mFallHeight; | ||||
|         std::string mLastHitObject; | ||||
|         bool mRecalcDynamicStats; | ||||
|         int mDrawState; | ||||
| 
 | ||||
|         int mLevel; | ||||
| 
 | ||||
|         SpellState mSpells; | ||||
| 
 | ||||
|         void load (ESMReader &esm); | ||||
|         void save (ESMWriter &esm) const; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| #endif | ||||
|  |  | |||
|  | @ -6,6 +6,12 @@ | |||
| namespace ESM | ||||
| { | ||||
| 
 | ||||
| struct TimeStamp | ||||
| { | ||||
|     float mHour; | ||||
|     int mDay; | ||||
| }; | ||||
| 
 | ||||
| // Pixel color value. Standard four-byte rr,gg,bb,aa format.
 | ||||
| typedef int32_t Color; | ||||
| 
 | ||||
|  | @ -101,6 +107,7 @@ enum RecNameInts | |||
|     REC_WTHR = 0x52485457, | ||||
|     REC_KEYS = FourCC<'K','E','Y','S'>::value, | ||||
|     REC_DYNA = FourCC<'D','Y','N','A'>::value, | ||||
|     REC_ASPL = FourCC<'A','S','P','L'>::value, | ||||
| 
 | ||||
|     // format 1
 | ||||
|     REC_FILT = 0x544C4946 | ||||
|  |  | |||
|  | @ -100,6 +100,9 @@ namespace ESM | |||
| 
 | ||||
|     void ESMWriter::startSubRecord(const std::string& name) | ||||
|     { | ||||
|         // Sub-record hierarchies are not properly supported in ESMReader. This should be fixed later.
 | ||||
|         assert (mRecords.size() <= 1); | ||||
| 
 | ||||
|         writeName(name); | ||||
|         RecordData rec; | ||||
|         rec.name = name; | ||||
|  |  | |||
|  | @ -96,6 +96,7 @@ class ESMWriter | |||
| 
 | ||||
|         void startRecord(const std::string& name, uint32_t flags = 0); | ||||
|         void startRecord(uint32_t name, uint32_t flags = 0); | ||||
|         /// @note Sub-record hierarchies are not properly supported in ESMReader. This should be fixed later.
 | ||||
|         void startSubRecord(const std::string& name); | ||||
|         void endRecord(const std::string& name); | ||||
|         void endRecord(uint32_t name); | ||||
|  |  | |||
|  | @ -36,6 +36,18 @@ void ESM::NpcStats::load (ESMReader &esm) | |||
|         mSkills[i].mWerewolf.load (esm); | ||||
|     } | ||||
| 
 | ||||
|     bool hasWerewolfAttributes = false; | ||||
|     esm.getHNOT (hasWerewolfAttributes, "HWAT"); | ||||
| 
 | ||||
|     if (hasWerewolfAttributes) | ||||
|     { | ||||
|         for (int i=0; i<8; ++i) | ||||
|             mWerewolfAttributes[i].load (esm); | ||||
|     } | ||||
| 
 | ||||
|     mIsWerewolf = false; | ||||
|     esm.getHNOT (mIsWerewolf, "WOLF"); | ||||
| 
 | ||||
|     mBounty = 0; | ||||
|     esm.getHNOT (mBounty, "BOUN"); | ||||
| 
 | ||||
|  | @ -48,8 +60,9 @@ void ESM::NpcStats::load (ESMReader &esm) | |||
|     mProfit = 0; | ||||
|     esm.getHNOT (mProfit, "PROF"); | ||||
| 
 | ||||
|     mAttackStrength = 0; | ||||
|     esm.getHNOT (mAttackStrength, "ASTR"); | ||||
|     // No longer used. Now part of CreatureStats.
 | ||||
|     float attackStrength = 0; | ||||
|     esm.getHNOT (attackStrength, "ASTR"); | ||||
| 
 | ||||
|     mLevelProgress = 0; | ||||
|     esm.getHNOT (mLevelProgress, "LPRO"); | ||||
|  | @ -101,6 +114,13 @@ void ESM::NpcStats::save (ESMWriter &esm) const | |||
|         mSkills[i].mWerewolf.save (esm); | ||||
|     } | ||||
| 
 | ||||
|     esm.writeHNT ("HWAT", true); | ||||
|     for (int i=0; i<8; ++i) | ||||
|         mWerewolfAttributes[i].save (esm); | ||||
| 
 | ||||
|     if (mIsWerewolf) | ||||
|         esm.writeHNT ("WOLF", mIsWerewolf); | ||||
| 
 | ||||
|     if (mBounty) | ||||
|         esm.writeHNT ("BOUN", mBounty); | ||||
| 
 | ||||
|  | @ -113,9 +133,6 @@ void ESM::NpcStats::save (ESMWriter &esm) const | |||
|     if (mProfit) | ||||
|         esm.writeHNT ("PROF", mProfit); | ||||
| 
 | ||||
|     if (mAttackStrength) | ||||
|         esm.writeHNT ("ASTR", mAttackStrength); | ||||
| 
 | ||||
|     if (mLevelProgress) | ||||
|         esm.writeHNT ("LPRO", mLevelProgress); | ||||
| 
 | ||||
|  | @ -136,4 +153,4 @@ void ESM::NpcStats::save (ESMWriter &esm) const | |||
| 
 | ||||
|     if (mCrimeId != -1) | ||||
|         esm.writeHNT ("CRID", mCrimeId); | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -31,6 +31,9 @@ namespace ESM | |||
|             Faction(); | ||||
|         }; | ||||
| 
 | ||||
|         StatState<int> mWerewolfAttributes[8]; | ||||
|         bool mIsWerewolf; | ||||
| 
 | ||||
|         std::map<std::string, Faction> mFactions; | ||||
|         int mDisposition; | ||||
|         Skill mSkills[27]; | ||||
|  | @ -38,7 +41,6 @@ namespace ESM | |||
|         int mReputation; | ||||
|         int mWerewolfKills; | ||||
|         int mProfit; | ||||
|         float mAttackStrength; | ||||
|         int mLevelProgress; | ||||
|         int mSkillIncrease[8]; | ||||
|         std::vector<std::string> mUsedIds; | ||||
|  | @ -52,4 +54,4 @@ namespace ESM | |||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| #endif | ||||
|  |  | |||
|  | @ -8,11 +8,13 @@ namespace ESM | |||
| 
 | ||||
|     void QuickKeys::load(ESMReader &esm) | ||||
|     { | ||||
|         while (esm.isNextSub("KEY_")) | ||||
|         if (esm.isNextSub("KEY_")) | ||||
|             esm.getSubHeader(); // no longer used, because sub-record hierachies do not work properly in esmreader
 | ||||
| 
 | ||||
|         while (esm.isNextSub("TYPE")) | ||||
|         { | ||||
|             esm.getSubHeader(); | ||||
|             int keyType; | ||||
|             esm.getHNT(keyType, "TYPE"); | ||||
|             esm.getHT(keyType); | ||||
|             std::string id; | ||||
|             id = esm.getHNString("ID__"); | ||||
| 
 | ||||
|  | @ -21,21 +23,18 @@ namespace ESM | |||
|             key.mId = id; | ||||
| 
 | ||||
|             mKeys.push_back(key); | ||||
| 
 | ||||
|             if (esm.isNextSub("KEY_")) | ||||
|                 esm.getSubHeader();  // no longer used, because sub-record hierachies do not work properly in esmreader
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void QuickKeys::save(ESMWriter &esm) const | ||||
|     { | ||||
|         const std::string recKey = "KEY_"; | ||||
| 
 | ||||
|         for (std::vector<QuickKey>::const_iterator it = mKeys.begin(); it != mKeys.end(); ++it) | ||||
|         { | ||||
|             esm.startSubRecord(recKey); | ||||
| 
 | ||||
|             esm.writeHNT("TYPE", it->mType); | ||||
|             esm.writeHNString("ID__", it->mId); | ||||
| 
 | ||||
|             esm.endRecord(recKey); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										66
									
								
								components/esm/spellstate.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								components/esm/spellstate.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | |||
| #include "spellstate.hpp" | ||||
| 
 | ||||
| #include "esmreader.hpp" | ||||
| #include "esmwriter.hpp" | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
| 
 | ||||
|     void SpellState::load(ESMReader &esm) | ||||
|     { | ||||
|         while (esm.isNextSub("SPEL")) | ||||
|         { | ||||
|             std::string id = esm.getHString(); | ||||
| 
 | ||||
|             std::map<const int, float> random; | ||||
|             while (esm.isNextSub("INDX")) | ||||
|             { | ||||
|                 int index; | ||||
|                 esm.getHT(index); | ||||
| 
 | ||||
|                 float magnitude; | ||||
|                 esm.getHNT(magnitude, "RAND"); | ||||
| 
 | ||||
|                 random[index] = magnitude; | ||||
|             } | ||||
| 
 | ||||
|             mSpells[id] = random; | ||||
|         } | ||||
| 
 | ||||
|         while (esm.isNextSub("USED")) | ||||
|         { | ||||
|             std::string id = esm.getHString(); | ||||
|             TimeStamp time; | ||||
|             esm.getHNT(time, "TIME"); | ||||
| 
 | ||||
|             mUsedPowers[id] = time; | ||||
|         } | ||||
| 
 | ||||
|         mSelectedSpell = esm.getHNOString("SLCT"); | ||||
|     } | ||||
| 
 | ||||
|     void SpellState::save(ESMWriter &esm) const | ||||
|     { | ||||
|         for (TContainer::const_iterator it = mSpells.begin(); it != mSpells.end(); ++it) | ||||
|         { | ||||
|             esm.writeHNString("SPEL", it->first); | ||||
| 
 | ||||
|             const std::map<const int, float>& random = it->second; | ||||
|             for (std::map<const int, float>::const_iterator rIt = random.begin(); rIt != random.end(); ++rIt) | ||||
|             { | ||||
|                 esm.writeHNT("INDX", rIt->first); | ||||
|                 esm.writeHNT("RAND", rIt->second); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (std::map<std::string, TimeStamp>::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it) | ||||
|         { | ||||
|             esm.writeHNString("USED", it->first); | ||||
|             esm.writeHNT("TIME", it->second); | ||||
|         } | ||||
| 
 | ||||
|         if (!mSelectedSpell.empty()) | ||||
|             esm.writeHNString("SLCT", mSelectedSpell); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										29
									
								
								components/esm/spellstate.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								components/esm/spellstate.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| #ifndef OPENMW_ESM_SPELLSTATE_H | ||||
| #define OPENMW_ESM_SPELLSTATE_H | ||||
| 
 | ||||
| #include <map> | ||||
| #include <string> | ||||
| 
 | ||||
| #include "defs.hpp" | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class ESMReader; | ||||
|     class ESMWriter; | ||||
| 
 | ||||
|     struct SpellState | ||||
|     { | ||||
|         typedef std::map<std::string, std::map<const int, float> > TContainer; | ||||
|         TContainer mSpells; | ||||
| 
 | ||||
|         std::map<std::string, TimeStamp> mUsedPowers; | ||||
| 
 | ||||
|         std::string mSelectedSpell; | ||||
| 
 | ||||
|         void load (ESMReader &esm); | ||||
|         void save (ESMWriter &esm) const; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -41,15 +41,18 @@ namespace Physic | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void PhysicActor::enableCollisions(bool collision) | ||||
|     void PhysicActor::enableCollisionMode(bool collision) | ||||
|     { | ||||
|         mCollisionMode = collision; | ||||
|     } | ||||
| 
 | ||||
|     void PhysicActor::enableCollisionBody(bool collision) | ||||
|     { | ||||
|         assert(mBody); | ||||
|         if(collision && !mCollisionMode) enableCollisionBody(); | ||||
|         if(!collision && mCollisionMode) disableCollisionBody(); | ||||
|         mCollisionMode = collision; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void PhysicActor::setPosition(const Ogre::Vector3 &pos) | ||||
|     { | ||||
|         assert(mBody); | ||||
|  |  | |||
|  | @ -99,7 +99,15 @@ namespace Physic | |||
|          */ | ||||
|         void setRotation(const Ogre::Quaternion &quat); | ||||
| 
 | ||||
|         void enableCollisions(bool collision); | ||||
|         /**
 | ||||
|          * Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry. | ||||
|          */ | ||||
|         void enableCollisionMode(bool collision); | ||||
| 
 | ||||
|         /**
 | ||||
|          * Enables or disables the *external* collision body. If disabled, other actors will not collide with this actor. | ||||
|          */ | ||||
|         void enableCollisionBody(bool collision); | ||||
| 
 | ||||
|         bool getCollisionMode() const | ||||
|         { | ||||
|  |  | |||
|  | @ -116,7 +116,7 @@ void ActorTracer::findGround(btCollisionObject *actor, const Ogre::Vector3 &star | |||
|         mFraction = newTraceCallback.m_closestHitFraction; | ||||
|         mPlaneNormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); | ||||
|         mEndPos = (end-start)*mFraction + start; | ||||
|         mEndPos[2] -= 1.0f; | ||||
|         mEndPos[2] += 1.0f; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue