From d13335ba40f10203cd9e9f86a198eab98c93c168 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 15:31:44 +0100 Subject: [PATCH 01/28] Ensure the item can be equipped in the given slot when loading inventory --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 5 ++--- apps/openmw/mwworld/containerstore.hpp | 5 +++-- apps/openmw/mwworld/inventorystore.cpp | 22 ++++++++++++++++++---- apps/openmw/mwworld/inventorystore.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 4 ++-- components/esm/inventorystate.hpp | 1 + 7 files changed, 29 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 605c8f9d2..545bbd4b3 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -466,7 +466,7 @@ namespace MWWorld // List moved references, from separately tracked list. for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) { - ESM::CellRef &ref = const_cast(*it); + const ESM::CellRef &ref = *it; mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID)); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bd14720f7..ba70e2f8f 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -86,7 +86,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object } template -void MWWorld::ContainerStore::storeStates (const CellRefList& collection, +void MWWorld::ContainerStore::storeStates (CellRefList& collection, std::vector >& states, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); @@ -641,7 +641,7 @@ MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) return Ptr(); } -void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const +void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) { state.mItems.clear(); @@ -688,7 +688,6 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) case ESM::REC_REPA: getState (repairs, iter->first); break; case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; - default: std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; break; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 68ee41a1d..f7c8a369c 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -85,7 +85,7 @@ namespace MWWorld void storeState (const LiveCellRef& ref, ESM::ObjectState& state) const; template - void storeStates (const CellRefList& collection, + void storeStates (CellRefList& collection, std::vector >& states, bool equipable = false) const; @@ -171,7 +171,8 @@ namespace MWWorld Ptr search (const std::string& id); - virtual void writeState (ESM::InventoryState& state) const; + /// \todo make this method const once const-correct ContainerStoreIterators are available + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 445b42d8d..be93824e5 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -58,10 +58,24 @@ int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const return -1; } -void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) +void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) { - if (iter!=end() && slot>=0 && slot, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); + relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); + + // unstack if required + if (!allowedSlots.second && iter->getRefData().getCount() > 1) + { + MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); + iter->getRefData().setCount(iter->getRefData().getCount()-1); + mSlots[allowedSlots.first[relativeSlot]] = newIter; + } + else + mSlots[allowedSlots.first[relativeSlot]] = iter; } MWWorld::InventoryStore::InventoryStore() @@ -703,7 +717,7 @@ bool MWWorld::InventoryStore::isEquipped(const MWWorld::Ptr &item) return false; } -void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) const +void MWWorld::InventoryStore::writeState(ESM::InventoryState &state) { MWWorld::ContainerStore::writeState(state); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9fd18c54b..7bd977e39 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -116,7 +116,7 @@ namespace MWWorld virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); + virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot); ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. public: @@ -209,7 +209,7 @@ namespace MWWorld virtual void clear(); ///< Empty container. - virtual void writeState (ESM::InventoryState& state) const; + virtual void writeState (ESM::InventoryState& state); virtual void readState (const ESM::InventoryState& state); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 104605e65..f7d5d9616 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2031,7 +2031,7 @@ namespace MWWorld bool World::isOnGround(const MWWorld::Ptr &ptr) const { RefData &refdata = ptr.getRefData(); - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); if(!physactor) return false; @@ -2049,7 +2049,7 @@ namespace MWWorld mPhysEngine); if(tracer.mFraction < 1.0f) // collision, must be close to something below { - const_cast (physactor)->setOnGround(true); + physactor->setOnGround(true); return true; } else diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 3d4407e7b..13af28e30 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,6 +15,7 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { + /// std::vector > mItems; std::map mLevelledItemMap; From 7ead963075c0ef0ff036dec10531367548ae4a56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 15:33:30 +0100 Subject: [PATCH 02/28] Revert "Revert "ESSImport: convert inventory equipment slots"" This reverts commit fe31ca0ac0649a0e34617a5821454e04863531ca. --- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 12 +++++++++++- apps/essimporter/importinventory.hpp | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 42535d946..6a31be6a3 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -16,7 +16,7 @@ namespace ESSImport objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags objstate.mRef.mCharge = it->mCondition; - state.mItems.push_back(std::make_pair(objstate, -1)); + state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index b4d193540..2f5c3c054 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -1,5 +1,7 @@ #include "importinventory.hpp" +#include + #include #include @@ -17,6 +19,7 @@ namespace ESSImport InventoryItem item; item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; + item.mRelativeEquipmentSlot = -1; // seems that a stack of items can have a set of subrecords for each item? rings0000.ess // doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place? @@ -55,14 +58,21 @@ namespace ESSImport { // note: same item can be equipped 2 items (e.g. 2 rings) // and will be *stacked* in the NPCO list, unlike openmw! + // this is currently not handled properly. + esm.getSubHeader(); int itemIndex; // index of the item in the NPCO list esm.getT(itemIndex); + if (itemIndex < 0 || itemIndex >= int(mItems.size())) + esm.fail("equipment item index out of range"); + // appears to be a relative index for only the *possible* slots this item can be equipped in, - // i.e. 0 most of the time, unlike openmw slot enum index + // i.e. 0 most of the time int slotIndex; esm.getT(slotIndex); + + mItems[itemIndex].mRelativeEquipmentSlot = slotIndex; } } diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 359e43fa6..8a1594465 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -21,6 +21,7 @@ namespace ESSImport std::string mId; int mCount; int mCondition; + int mRelativeEquipmentSlot; }; std::vector mItems; From c7d15e6f74a81e007b48ddeb5f3a077ac4812312 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 15:33:39 +0100 Subject: [PATCH 03/28] Revert "Revert "Light charge handling fix"" This reverts commit b95748d044a421c2e02fa54cdc7e8aa902039e6c. --- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/convertinventory.cpp | 2 +- apps/essimporter/importinventory.cpp | 6 +-- apps/essimporter/importinventory.hpp | 1 - apps/opencs/model/world/columnimp.hpp | 4 +- apps/openmw/mwclass/light.cpp | 56 +++------------------------ apps/openmw/mwclass/light.hpp | 10 ----- apps/openmw/mwworld/cellref.cpp | 20 ++++++++-- apps/openmw/mwworld/cellref.hpp | 3 ++ apps/openmw/mwworld/manualref.hpp | 2 +- components/esm/cellref.cpp | 10 ++--- components/esm/cellref.hpp | 6 ++- components/esm/objectstate.cpp | 10 ++--- components/esm/objectstate.hpp | 2 - 14 files changed, 47 insertions(+), 87 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index a18736bf2..b23ba72f9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -261,7 +261,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Faction: '" << ref.mFaction << "'" << std::endl; std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; - std::cout << " Uses/health: '" << ref.mCharge << "'\n"; + std::cout << " Uses/health: '" << ref.mChargeInt << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; std::cout << " Deleted: " << deleted << std::endl; diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 6a31be6a3..31272bf5a 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -12,10 +12,10 @@ namespace ESSImport { ESM::ObjectState objstate; objstate.blank(); + objstate.mRef = *it; objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags - objstate.mRef.mCharge = it->mCondition; state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); } } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index 2f5c3c054..a20584ff5 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -45,9 +45,9 @@ namespace ESSImport // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); - item.mCondition = -1; - // FIXME: for Lights, this is actually a float - esm.getHNOT(item.mCondition, "XHLT"); + int charge=-1; + esm.getHNOT(charge, "XHLT"); + item.mChargeInt = charge; } mItems.push_back(item); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 8a1594465..99fed9b20 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -20,7 +20,6 @@ namespace ESSImport { std::string mId; int mCount; - int mCondition; int mRelativeEquipmentSlot; }; std::vector mItems; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index eba73cf0b..da14bb495 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1053,13 +1053,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mCharge; + return record.get().mChargeInt; } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mCharge = data.toInt(); + record2.mChargeInt = data.toInt(); record.setModified (record2); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c50ad52d8..35a21b63e 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -26,27 +26,6 @@ #include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" -namespace -{ - struct LightCustomData : public MWWorld::CustomData - { - float mTime; - ///< Time remaining - - LightCustomData(MWWorld::Ptr ptr) - { - MWWorld::LiveCellRef *ref = ptr.get(); - mTime = ref->mBase->mData.mTime; - } - ///< Constructs this CustomData from the base values for Ptr. - - virtual MWWorld::CustomData *clone() const - { - return new LightCustomData (*this); - } - }; -} - namespace MWClass { std::string Light::getId (const MWWorld::Ptr& ptr) const @@ -219,17 +198,16 @@ namespace MWClass void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const { - ensureCustomData(ptr); - - float &timeRemaining = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - timeRemaining = duration; + ptr.getCellRef().setChargeFloat(duration); } float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const { - ensureCustomData(ptr); - - return dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + MWWorld::LiveCellRef *ref = ptr.get(); + if (ptr.getCellRef().getCharge() == -1) + return ref->mBase->mData.mTime; + else + return ptr.getCellRef().getChargeFloat(); } MWWorld::Ptr @@ -241,12 +219,6 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } - void Light::ensureCustomData (const MWWorld::Ptr& ptr) const - { - if (!ptr.getRefData().getCustomData()) - ptr.getRefData().setCustomData(new LightCustomData(ptr)); - } - bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { return npcServices & ESM::NPC::Lights; @@ -282,22 +254,6 @@ namespace MWClass return std::make_pair(1,""); } - void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - dynamic_cast (*ptr.getRefData().getCustomData()).mTime = state.mTime; - } - - void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const - { - ensureCustomData (ptr); - - state.mTime = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; - } - std::string Light::getSound(const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mSound; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index bbca30113..8658375b7 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -10,8 +10,6 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; - void ensureCustomData (const MWWorld::Ptr& ptr) const; - public: /// Return ID of \a ptr @@ -75,14 +73,6 @@ namespace MWClass std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; - virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const; - ///< Read additional state from \a state into \a ptr. - - virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const; - ///< Write additional state from \a ptr into \a state. - virtual std::string getSound(const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index aa6627de5..744e0e27a 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -81,15 +81,29 @@ namespace MWWorld int CellRef::getCharge() const { - return mCellRef.mCharge; + return mCellRef.mChargeInt; } void CellRef::setCharge(int charge) { - if (charge != mCellRef.mCharge) + if (charge != mCellRef.mChargeInt) { mChanged = true; - mCellRef.mCharge = charge; + mCellRef.mChargeInt = charge; + } + } + + float CellRef::getChargeFloat() const + { + return mCellRef.mChargeFloat; + } + + void CellRef::setChargeFloat(float charge) + { + if (charge != mCellRef.mChargeFloat) + { + mChanged = true; + mCellRef.mChargeFloat = charge; } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index a7ffbe08b..054fd7fc6 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -60,8 +60,11 @@ namespace MWWorld // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + // If this returns int(-1) it means full health. int getCharge() const; + float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); + void setChargeFloat(float charge); // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 4eb93543b..f32b07471 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -28,7 +28,7 @@ namespace MWWorld cellRef.mRefID = name; cellRef.mScale = 1; cellRef.mFactionRank = 0; - cellRef.mCharge = -1; + cellRef.mChargeInt = -1; cellRef.mGoldValue = 1; cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index cd9fe8570..dfc3052ee 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -46,12 +46,12 @@ void ESM::CellRef::loadData(ESMReader &esm) esm.getHNOT (mFactionRank, "INDX"); mGoldValue = 1; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; esm.getHNOT (mEnchantmentCharge, "XCHG"); - esm.getHNOT (mCharge, "INTV"); + esm.getHNOT (mChargeInt, "INTV"); esm.getHNOT (mGoldValue, "NAM9"); @@ -106,8 +106,8 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons if (mEnchantmentCharge != -1) esm.writeHNT("XCHG", mEnchantmentCharge); - if (mCharge != -1) - esm.writeHNT("INTV", mCharge); + if (mChargeInt != -1) + esm.writeHNT("INTV", mChargeInt); if (mGoldValue != 1) { esm.writeHNT("NAM9", mGoldValue); @@ -146,7 +146,7 @@ void ESM::CellRef::blank() mSoul.clear(); mFaction.clear(); mFactionRank = -2; - mCharge = -1; + mChargeInt = -1; mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 7aa0e4d44..56932aa4d 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,7 +59,11 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - int mCharge; + union + { + int mChargeInt; + float mChargeFloat; + }; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 66fd49663..9ef1ccf80 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -24,9 +24,9 @@ void ESM::ObjectState::load (ESMReader &esm) esm.getHNOT (mLocalRotation, "LROT", 12); - // used for lights only - mTime = 0; - esm.getHNOT (mTime, "LTIM"); + // obsolete + int unused; + esm.getHNOT(unused, "LTIM"); // FIXME: assuming "false" as default would make more sense, but also break compatibility with older save files mHasCustomState = true; @@ -55,9 +55,6 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const esm.writeHNT ("LROT", mLocalRotation, 12); } - if (mTime) - esm.writeHNT ("LTIM", mTime); - if (!mHasCustomState) esm.writeHNT ("HCUS", false); } @@ -74,7 +71,6 @@ void ESM::ObjectState::blank() mPosition.rot[i] = 0; mLocalRotation[i] = 0; } - mTime = 0; mHasCustomState = true; } diff --git a/components/esm/objectstate.hpp b/components/esm/objectstate.hpp index b03689653..d1077733a 100644 --- a/components/esm/objectstate.hpp +++ b/components/esm/objectstate.hpp @@ -26,8 +26,6 @@ namespace ESM ESM::Position mPosition; float mLocalRotation[3]; - float mTime; // Used for lights only. Overhead should not be so awful, besides CellRef isn't OO either - // Is there any class-specific state following the ObjectState bool mHasCustomState; From 69676906aef59e4179d8a194425e77a09cb5d812 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 21:24:25 +0100 Subject: [PATCH 04/28] Don't clear known spells when reading from the savegame This is needed because the .ess format doesn't include the racial spells in the player's spell list. --- apps/essimporter/importplayer.cpp | 4 ++++ apps/openmw/mwmechanics/spells.cpp | 20 ++++++++------------ components/esm/spellstate.hpp | 1 + 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index 285605068..ea9f1932c 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -23,6 +23,10 @@ namespace ESSImport mKnownDialogueTopics.push_back(esm.getHString()); } + if (esm.isNextSub("MNAM")) + esm.skipHSub(); // If this field is here it seems to specify the interior cell the player is in, + // but it's not always here, so it's kinda useless + esm.getHNT(mPNAM, "PNAM"); if (esm.isNextSub("SNAM")) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 1f8ada06d..dcbd3f09f 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -312,21 +312,17 @@ namespace MWMechanics 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();) + for (TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(iter->first); - if (!spell) + // Discard spells that are no longer available due to changed content files + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); + if (spell) { - if (iter->first == mSelectedSpell) - mSelectedSpell = ""; - mSpells.erase(iter++); + mSpells[it->first] = it->second; + + if (it->first == state.mSelectedSpell) + mSelectedSpell = it->first; } - else - ++iter; } // No need to discard spells here (doesn't really matter if non existent ids are kept) diff --git a/components/esm/spellstate.hpp b/components/esm/spellstate.hpp index 2ab27e908..028e6a387 100644 --- a/components/esm/spellstate.hpp +++ b/components/esm/spellstate.hpp @@ -12,6 +12,7 @@ namespace ESM class ESMReader; class ESMWriter; + // NOTE: spell ids must be lower case struct SpellState { struct CorprusStats From acf8461841546f5691f3c2e817af7a0d59116433 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 22:25:37 +0100 Subject: [PATCH 05/28] ESSImport: some fixes --- apps/essimporter/converter.cpp | 22 ++++++++++------------ apps/essimporter/converter.hpp | 9 +++++++-- apps/essimporter/importacdt.cpp | 10 ++++------ apps/essimporter/importacdt.hpp | 4 +++- apps/essimporter/importcellref.cpp | 21 ++++++++++++++++----- apps/essimporter/importcellref.hpp | 10 +++------- apps/essimporter/importcrec.cpp | 10 ++++++++++ apps/essimporter/importnpcc.cpp | 3 +++ 8 files changed, 56 insertions(+), 33 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 099987762..81521a028 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -27,6 +27,8 @@ namespace objstate.mEnabled = cellref.mEnabled; objstate.mPosition = cellref.mPos; objstate.mRef.mRefNum = cellref.mRefNum; + if (cellref.mDeleted) + objstate.mCount = 0; } bool isIndexedRefId(const std::string& indexedRefId) @@ -34,6 +36,10 @@ namespace if (indexedRefId.size() <= 8) return false; + if (indexedRefId.find_first_not_of("0123456789") == std::string::npos) + return false; // entirely numeric refid, this is a reference to + // a dynamically created record e.g. player-enchanted weapon + std::string index = indexedRefId.substr(indexedRefId.size()-8); if(index.find_first_not_of("0123456789ABCDEF") == std::string::npos ) return true; @@ -136,13 +142,6 @@ namespace ESSImport { CellRef ref; ref.load (esm); - if (esm.isNextSub("DELE")) - { - // TODO - // strangely this can be e.g. 52 instead of just 1, - //std::cout << "deleted ref " << ref.mIndexedRefId << std::endl; - esm.skipHSub(); - } cellrefs.push_back(ref); } @@ -201,8 +200,7 @@ namespace ESSImport for (std::vector::const_iterator refIt = cell.mRefs.begin(); refIt != cell.mRefs.end(); ++refIt) { const CellRef& cellref = *refIt; - ESM::CellRef out; - out.blank(); + ESM::CellRef out (cellref); if (!isIndexedRefId(cellref.mIndexedRefId)) { @@ -241,8 +239,8 @@ namespace ESSImport objstate.mRef.mRefID = idLower; // probably need more micromanagement here so we don't overwrite values // from the ESM with default values - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); - convertNpcData(cellref.mActorData, objstate.mNpcStats); + convertACDT(cellref.mACDT, objstate.mCreatureStats); + convertNpcData(cellref, objstate.mNpcStats); convertNPCC(npccIt->second, objstate); convertCellRef(cellref, objstate); esm.writeHNT ("OBJE", ESM::REC_NPC_); @@ -273,7 +271,7 @@ namespace ESSImport objstate.blank(); objstate.mRef = out; objstate.mRef.mRefID = idLower; - convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats); + convertACDT(cellref.mACDT, objstate.mCreatureStats); // probably need more micromanagement here so we don't overwrite values // from the ESM with default values convertCREC(crecIt->second, objstate); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index b68f9a218..9f6ad49df 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -90,14 +90,19 @@ public: ESM::NPC npc; std::string id = esm.getHNString("NAME"); npc.load(esm); - if (id != "player") // seems to occur sometimes, with "chargen X" names + if (id != "player") + { + // this handles changes to the NPC struct, but since there is no index here + // it will apply to ALL instances of the class. seems to be the reason for the + // "feature" in MW where changing AI settings of one guard will change it for all guards of that refID. std::cerr << "non-player NPC record: " << id << std::endl; + } else { mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; mContext->mPlayerBase = npc; std::map empty; - // FIXME: player start spells, racial spells and birthsign spells aren't listed here, + // FIXME: player start spells and birthsign spells aren't listed here, // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 84c800897..4d4a87a35 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -9,18 +9,16 @@ namespace ESSImport void ActorData::load(ESM::ESMReader &esm) { - // unsure at which point between NAME and ESM::CellRef - if (esm.isNextSub("MNAM")) - esm.skipHSub(); - if (esm.isNextSub("ACTN")) esm.skipHSub(); if (esm.isNextSub("STPR")) esm.skipHSub(); - ESM::CellRef bla; - bla.ESM::CellRef::loadData(esm); + if (esm.isNextSub("MNAM")) + esm.skipHSub(); + + ESM::CellRef::loadData(esm); // FIXME: not all actors have this, add flag esm.getHNOT(mACDT, "ACDT"); diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 79f67d2c2..271f6df74 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -3,6 +3,8 @@ #include +#include + namespace ESM { struct ESMReader; @@ -37,7 +39,7 @@ namespace ESSImport }; #pragma pack(pop) - struct ActorData + struct ActorData : public ESM::CellRef { ACDT mACDT; diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index fd58d5bc1..7c4af1e02 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -7,6 +7,8 @@ namespace ESSImport void CellRef::load(ESM::ESMReader &esm) { + blank(); + // (FRMR subrecord name is already read by the loop in ConvertCell) esm.getHT(mRefNum.mIndex); // FRMR @@ -25,17 +27,26 @@ namespace ESSImport esm.getHT(lvcr); //std::cout << "LVCR: " << (int)lvcr << std::endl; } - mActorData.load(esm); + ActorData::load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - // should occur for all references but not levelled creature spawners - esm.getHNOT(mPos, "DATA", 24); - - // i've seen DATA record TWICE on a creature record - and with the exact same content too! weird + // DATA should occur for all references, except leveled creature spawners + // I've seen DATA *twice* on a creature record, and with the exact same content too! weird // alarmvoi0000.ess esm.getHNOT(mPos, "DATA", 24); + esm.getHNOT(mPos, "DATA", 24); + + mDeleted = 0; + if (esm.isNextSub("DELE")) + { + int deleted; + esm.getHT(deleted); + // Neither of this seems to work right... + //mDeleted = (deleted != 0); + //mDeleted = (deleted&0x1); + } if (esm.isNextSub("MVRF")) { diff --git a/apps/essimporter/importcellref.hpp b/apps/essimporter/importcellref.hpp index 77763d434..556ed19bf 100644 --- a/apps/essimporter/importcellref.hpp +++ b/apps/essimporter/importcellref.hpp @@ -15,20 +15,16 @@ namespace ESM namespace ESSImport { - // Not sure if we can share any code with ESM::CellRef here - struct CellRef + struct CellRef : public ActorData { std::string mIndexedRefId; - ESM::RefNum mRefNum; - - ActorData mActorData; - - ESM::Position mPos; std::string mScript; bool mEnabled; + bool mDeleted; + void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 9cf455588..28e5ac56f 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -14,6 +14,16 @@ namespace ESSImport float scale; esm.getHNOT(scale, "XSCL"); + // FIXME: use AiPackageList, need to fix getSubName() + if (esm.isNextSub("AI_W")) + esm.skipHSub(); + if (esm.isNextSub("AI_E")) + esm.skipHSub(); + if (esm.isNextSub("AI_T")) + esm.skipHSub(); + if (esm.isNextSub("AI_F")) + esm.skipHSub(); + mInventory.load(esm); } diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index c389ede7f..7b8dda371 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -9,6 +9,9 @@ namespace ESSImport { esm.getHNT(mNPDT, "NPDT"); + // FIXME: use AiPackageList, need to fix getSubName() + if (esm.isNextSub("AI_W")) + esm.skipHSub(); if (esm.isNextSub("AI_E")) esm.skipHSub(); if (esm.isNextSub("AI_T")) From 1e92cab3e76b9b258ae813eb43f020ecba2da754 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 Jan 2015 23:35:09 +0100 Subject: [PATCH 06/28] ESSImport: read dialogue/journal records, not converted yet --- apps/essimporter/CMakeLists.txt | 5 ++ apps/essimporter/converter.hpp | 81 +++++++++++++++++++++++++++++++-- apps/essimporter/importdial.cpp | 13 ++++++ apps/essimporter/importdial.hpp | 20 ++++++++ apps/essimporter/importer.cpp | 10 +++- apps/essimporter/importgame.cpp | 13 ++++++ apps/essimporter/importgame.hpp | 33 ++++++++++++++ apps/essimporter/importinfo.cpp | 14 ++++++ apps/essimporter/importinfo.hpp | 24 ++++++++++ apps/essimporter/importjour.cpp | 13 ++++++ apps/essimporter/importjour.hpp | 25 ++++++++++ apps/essimporter/importques.cpp | 14 ++++++ apps/essimporter/importques.hpp | 28 ++++++++++++ components/esm/defs.hpp | 2 +- components/esm/loadnpcc.hpp | 17 ------- 15 files changed, 290 insertions(+), 22 deletions(-) create mode 100644 apps/essimporter/importdial.cpp create mode 100644 apps/essimporter/importdial.hpp create mode 100644 apps/essimporter/importgame.cpp create mode 100644 apps/essimporter/importgame.hpp create mode 100644 apps/essimporter/importinfo.cpp create mode 100644 apps/essimporter/importinfo.hpp create mode 100644 apps/essimporter/importjour.cpp create mode 100644 apps/essimporter/importjour.hpp create mode 100644 apps/essimporter/importques.cpp create mode 100644 apps/essimporter/importques.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 8d1af714d..70eaefe2c 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -9,6 +9,11 @@ set(ESSIMPORTER_FILES importinventory.cpp importklst.cpp importcntc.cpp + importgame.cpp + importinfo.cpp + importdial.cpp + importques.cpp + importjour.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 9f6ad49df..4ca0e8386 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -19,6 +20,11 @@ #include "importercontext.hpp" #include "importcellref.hpp" #include "importklst.hpp" +#include "importgame.hpp" +#include "importinfo.hpp" +#include "importdial.hpp" +#include "importques.hpp" +#include "importjour.hpp" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -86,16 +92,15 @@ class ConvertNPC : public Converter public: virtual void read(ESM::ESMReader &esm) { - // this is always the player ESM::NPC npc; std::string id = esm.getHNString("NAME"); npc.load(esm); if (id != "player") { - // this handles changes to the NPC struct, but since there is no index here + // TODO: + // this should handle changes to the NPC struct, but since there is no index here // it will apply to ALL instances of the class. seems to be the reason for the // "feature" in MW where changing AI settings of one guard will change it for all guards of that refID. - std::cerr << "non-player NPC record: " << id << std::endl; } else { @@ -110,6 +115,18 @@ public: } }; +class ConvertCREA : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + // See comment in ConvertNPC + ESM::Creature creature; + std::string id = esm.getHNString("NAME"); + creature.load(esm); + } +}; + class ConvertGlobal : public DefaultConverter { public: @@ -350,6 +367,64 @@ private: std::multimap mFactionStolenItems; }; +/// Seen responses for a dialogue topic? +/// Each DIAL record is followed by a number of INFO records, I believe, just like in ESMs +/// Dialogue conversion problems (probably have to adjust OpenMW format) - +/// - Journal is stored in one continuous HTML markup rather than each entry separately with associated info ID. +/// - Seen dialogue responses only store the INFO id, rather than the fulltext. +/// - Quest stages only store the INFO id, rather than the journal entry fulltext. +class ConvertINFO : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + INFO info; + info.load(esm); + } +}; + +class ConvertDIAL : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + DIAL dial; + dial.load(esm); + } +}; + +class ConvertQUES : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + std::string id = esm.getHNString("NAME"); + QUES quest; + quest.load(esm); + } +}; + +class ConvertJOUR : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) + { + JOUR journal; + journal.load(esm); + } +}; + +class ConvertGAME : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + GAME game; + game.load(esm); + } +}; + } #endif diff --git a/apps/essimporter/importdial.cpp b/apps/essimporter/importdial.cpp new file mode 100644 index 000000000..228d00a5a --- /dev/null +++ b/apps/essimporter/importdial.cpp @@ -0,0 +1,13 @@ +#include "importdial.hpp" + +#include + +namespace ESSImport +{ + + void DIAL::load(ESM::ESMReader &esm) + { + esm.getHNT(mIndex, "XIDX"); + } + +} diff --git a/apps/essimporter/importdial.hpp b/apps/essimporter/importdial.hpp new file mode 100644 index 000000000..fe4b0c5b4 --- /dev/null +++ b/apps/essimporter/importdial.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTDIAL_H +#define OPENMW_ESSIMPORT_IMPORTDIAL_H +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + struct DIAL + { + int mIndex; // Journal index + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index c2092ea4d..8603200da 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -201,11 +201,14 @@ namespace ESSImport const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value; const unsigned int recKLST = ESM::FourCC<'K','L','S','T'>::value; const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value; + const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value; + const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value; std::map > converters; converters[ESM::REC_GLOB] = boost::shared_ptr(new ConvertGlobal()); converters[ESM::REC_BOOK] = boost::shared_ptr(new ConvertBook()); converters[ESM::REC_NPC_] = boost::shared_ptr(new ConvertNPC()); + converters[ESM::REC_CREA] = boost::shared_ptr(new ConvertCREA()); converters[ESM::REC_NPCC] = boost::shared_ptr(new ConvertNPCC()); converters[ESM::REC_CREC] = boost::shared_ptr(new ConvertCREC()); converters[recREFR ] = boost::shared_ptr(new ConvertREFR()); @@ -213,6 +216,7 @@ namespace ESSImport converters[recFMAP ] = boost::shared_ptr(new ConvertFMAP()); converters[recKLST ] = boost::shared_ptr(new ConvertKLST()); converters[recSTLN ] = boost::shared_ptr(new ConvertSTLN()); + converters[recGAME ] = boost::shared_ptr(new ConvertGAME()); converters[ESM::REC_CELL] = boost::shared_ptr(new ConvertCell()); converters[ESM::REC_ALCH] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CLAS] = boost::shared_ptr(new ConvertClass()); @@ -226,6 +230,10 @@ namespace ESSImport converters[ESM::REC_LEVI] = boost::shared_ptr(new DefaultConverter()); converters[ESM::REC_CNTC] = boost::shared_ptr(new ConvertCNTC()); converters[ESM::REC_FACT] = boost::shared_ptr(new ConvertFACT()); + converters[ESM::REC_INFO] = boost::shared_ptr(new ConvertINFO()); + converters[ESM::REC_DIAL] = boost::shared_ptr(new ConvertDIAL()); + converters[ESM::REC_QUES] = boost::shared_ptr(new ConvertQUES()); + converters[recJOUR ] = boost::shared_ptr(new ConvertJOUR()); std::set unknownRecords; @@ -248,7 +256,7 @@ namespace ESSImport else { if (unknownRecords.insert(n.val).second) - std::cerr << "unknown record " << n.toString() << std::endl; + std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl; esm.skipRecord(); } diff --git a/apps/essimporter/importgame.cpp b/apps/essimporter/importgame.cpp new file mode 100644 index 000000000..0b3a4f1a7 --- /dev/null +++ b/apps/essimporter/importgame.cpp @@ -0,0 +1,13 @@ +#include "importgame.hpp" + +#include + +namespace ESSImport +{ + +void GAME::load(ESM::ESMReader &esm) +{ + esm.getHNT(mGMDT, "GMDT"); +} + +} diff --git a/apps/essimporter/importgame.hpp b/apps/essimporter/importgame.hpp new file mode 100644 index 000000000..7bb814320 --- /dev/null +++ b/apps/essimporter/importgame.hpp @@ -0,0 +1,33 @@ +#ifndef OPENMW_ESSIMPORT_GAME_H +#define OPENMW_ESSIMPORT_GAME_H + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Weather data + struct GAME + { + struct GMDT + { + char mCellName[64]; + int mFogColour; + float mFogDensity; + int mCurrentWeather, mNextWeather; + int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage + float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition + int masserPhase, secundaPhase; // top 3 bytes may be garbage + }; + + GMDT mGMDT; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importinfo.cpp b/apps/essimporter/importinfo.cpp new file mode 100644 index 000000000..113155370 --- /dev/null +++ b/apps/essimporter/importinfo.cpp @@ -0,0 +1,14 @@ +#include "importinfo.hpp" + +#include + +namespace ESSImport +{ + + void INFO::load(ESM::ESMReader &esm) + { + mInfo = esm.getHNString("INAM"); + mActorRefId = esm.getHNString("ACDT"); + } + +} diff --git a/apps/essimporter/importinfo.hpp b/apps/essimporter/importinfo.hpp new file mode 100644 index 000000000..08f588f8d --- /dev/null +++ b/apps/essimporter/importinfo.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTINFO_H +#define OPENMW_ESSIMPORT_IMPORTINFO_H + +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + struct INFO + { + std::string mInfo; + std::string mActorRefId; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importjour.cpp b/apps/essimporter/importjour.cpp new file mode 100644 index 000000000..e5d24e113 --- /dev/null +++ b/apps/essimporter/importjour.cpp @@ -0,0 +1,13 @@ +#include "importjour.hpp" + +#include + +namespace ESSImport +{ + + void JOUR::load(ESM::ESMReader &esm) + { + mText = esm.getHNString("NAME"); + } + +} diff --git a/apps/essimporter/importjour.hpp b/apps/essimporter/importjour.hpp new file mode 100644 index 000000000..fe8775a93 --- /dev/null +++ b/apps/essimporter/importjour.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTJOUR_H +#define OPENMW_ESSIMPORT_IMPORTJOUR_H + +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + /// Journal + struct JOUR + { + // The entire journal, in HTML + std::string mText; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importques.cpp b/apps/essimporter/importques.cpp new file mode 100644 index 000000000..78b779e43 --- /dev/null +++ b/apps/essimporter/importques.cpp @@ -0,0 +1,14 @@ +#include "importques.hpp" + +#include + +namespace ESSImport +{ + + void QUES::load(ESM::ESMReader &esm) + { + while (esm.isNextSub("DATA")) + mInfo.push_back(esm.getHString()); + } + +} diff --git a/apps/essimporter/importques.hpp b/apps/essimporter/importques.hpp new file mode 100644 index 000000000..d7e718b92 --- /dev/null +++ b/apps/essimporter/importques.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTQUES_H +#define OPENMW_ESSIMPORT_IMPORTQUES_H + +#include +#include + +namespace ESM +{ + struct ESMReader; +} + +namespace ESSImport +{ + + /// State for a quest + /// Presumably this record only exists when Tribunal is installed, + /// since pre-Tribunal there weren't any quest names in the data files. + struct QUES + { + std::string mName; // NAME, should be assigned from outside as usual + std::vector mInfo; // list of journal entries for the quest + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index fe45d6914..effe9a3f1 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -97,7 +97,7 @@ enum RecNameInts // format 0 - saved games REC_SAVE = 0x45564153, - REC_JOUR = 0x524f55a4, + REC_JOUR = 0x524f55a4, // TODO: this is actually "\nOUR" rather than "JOUR", fix REC_QUES = 0x53455551, REC_GSCR = 0x52435347, REC_PLAY = 0x59414c50, diff --git a/components/esm/loadnpcc.hpp b/components/esm/loadnpcc.hpp index 6c087fd01..6b3cd533f 100644 --- a/components/esm/loadnpcc.hpp +++ b/components/esm/loadnpcc.hpp @@ -20,24 +20,7 @@ class ESMWriter; * SCPT records do not define new scripts, but assign values to the * variables of existing ones. * - * STLN - stolen items, ONAM is the owner - * - * GAME - weather data - * struct GMDT - { - char mCellName[64]; - int mFogColour; - float mFogDensity; - int mCurrentWeather, mNextWeather; - int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage - float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition - int masserPhase, secundaPhase; // top 3 bytes may be garbage - }; - * * VFXM, SPLM - no clue - * KLST - kill counter - * - * PCDT - seems to contain a lot of DNAMs, strings? * * FMAP - MAPH and MAPD, global map image. * From 5ce8a931a55fb74041d3690eb1ac4cffe4c73970 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:34:44 +0100 Subject: [PATCH 07/28] ESSImport: fix a subrecord ordering issue --- apps/essimporter/importcellref.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 7c4af1e02..845c574e4 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -19,6 +19,7 @@ namespace ESSImport mIndexedRefId = esm.getHNString("NAME"); + ActorData::load(esm); if (esm.isNextSub("LVCR")) { // occurs on leveled creature spawner references @@ -27,7 +28,6 @@ namespace ESSImport esm.getHT(lvcr); //std::cout << "LVCR: " << (int)lvcr << std::endl; } - ActorData::load(esm); mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); From cc7be1600d7491f8d23081ab6e7a413c943454fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:36:12 +0100 Subject: [PATCH 08/28] Make missing hair/head in NpcAnimation non-fatal for consistency with addOrReplaceIndividualPart --- apps/openmw/mwrender/npcanimation.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5e73a95f2..a8ba1abf5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -263,17 +263,27 @@ void NpcAnimation::updateNpcBase() } else { - if (isVampire) + mHeadModel = ""; + if (isVampire) // FIXME: fall back to regular head when getVampireHead fails? mHeadModel = getVampireHead(mNpc->mRace, mNpc->mFlags & ESM::NPC::Female); else if (!mNpc->mHead.empty()) - mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; - else - mHeadModel = ""; + { + const ESM::BodyPart* bp = store.get().search(mNpc->mHead); + if (bp) + mHeadModel = "meshes\\" + bp->mModel; + else + std::cerr << "Failed to load body part '" << mNpc->mHead << "'" << std::endl; + } + mHairModel = ""; if (!mNpc->mHair.empty()) - mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; - else - mHairModel = ""; + { + const ESM::BodyPart* bp = store.get().search(mNpc->mHair); + if (bp) + mHairModel = "meshes\\" + bp->mModel; + else + std::cerr << "Failed to load body part '" << mNpc->mHair << "'" << std::endl; + } } bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; From 0fd5575efee6495d0fa2eb4322457e543b2d69de Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:39:00 +0100 Subject: [PATCH 09/28] Improve warning message in ContainerStore::readState --- apps/openmw/mwworld/containerstore.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ba70e2f8f..57621b7a4 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -688,8 +688,11 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) case ESM::REC_REPA: getState (repairs, iter->first); break; case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; + case 0: + std::cerr << "Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; + break; default: - std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; + std::cerr << "Invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; break; } } From 98402e579de14b6e203e4073481ef0fb689e2553 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:39:37 +0100 Subject: [PATCH 10/28] ESSImport: fix non-existing items in player record causing load failure in OpenMW --- apps/essimporter/converter.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 4ca0e8386..a88a364d2 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -111,6 +111,14 @@ public: // need to fix openmw to account for this for (std::vector::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it) mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty; + + // Clear the list now that we've written it, this prevents issues cropping up with + // ensureCustomData() in OpenMW tripping over no longer existing spells, where an error would be fatal. + mContext->mPlayerBase.mSpells.mList.clear(); + + // Same with inventory. Actually it's strange this would contain something, since there's already an + // inventory list in NPCC. There seems to be a fair amount of redundancy in this format. + mContext->mPlayerBase.mInventory.mList.clear(); } } }; @@ -127,6 +135,10 @@ public: } }; +// Do we need ConvertCONT? +// I've seen a CONT record in a certain save file, but the container contents in it +// were identical to a corresponding CNTC record. See previous comment about redundancy... + class ConvertGlobal : public DefaultConverter { public: From e2031279520aefbe00f053bd9dd75e2f842e2198 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 03:54:33 +0100 Subject: [PATCH 11/28] ESSImport: read script variables (not converted yet) --- apps/essimporter/CMakeLists.txt | 2 + apps/essimporter/converter.hpp | 12 ++++++ apps/essimporter/importacdt.cpp | 13 +------ apps/essimporter/importacdt.hpp | 4 +- apps/essimporter/importer.cpp | 1 + apps/essimporter/importinventory.cpp | 13 +------ apps/essimporter/importinventory.hpp | 2 + apps/essimporter/importscpt.cpp | 20 ++++++++++ apps/essimporter/importscpt.hpp | 32 ++++++++++++++++ apps/essimporter/importscri.cpp | 55 ++++++++++++++++++++++++++++ apps/essimporter/importscri.hpp | 30 +++++++++++++++ components/esm/loadscpt.cpp | 32 ---------------- components/esm/loadscpt.hpp | 5 +++ 13 files changed, 164 insertions(+), 57 deletions(-) create mode 100644 apps/essimporter/importscpt.cpp create mode 100644 apps/essimporter/importscpt.hpp create mode 100644 apps/essimporter/importscri.cpp create mode 100644 apps/essimporter/importscri.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 70eaefe2c..5db3a86dc 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -14,6 +14,8 @@ set(ESSIMPORTER_FILES importdial.cpp importques.cpp importjour.cpp + importscri.cpp + importscpt.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index a88a364d2..9894de299 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -25,6 +25,7 @@ #include "importdial.hpp" #include "importques.hpp" #include "importjour.hpp" +#include "importscpt.hpp" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -437,6 +438,17 @@ public: } }; +/// Running global script +class ConvertSCPT : public Converter +{ +public: + virtual void read(ESM::ESMReader &esm) + { + SCPT script; + script.load(esm); + } +}; + } #endif diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 4d4a87a35..e590e2826 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -81,18 +81,7 @@ namespace ESSImport if (esm.isNextSub("CRED")) // creature only esm.getHExact(mCombatStats, 3*2*sizeof(int)); - mScript = esm.getHNOString("SCRI"); - - // script variables? - if (!mScript.empty()) - { - if (esm.isNextSub("SLCS")) - esm.skipHSub(); - if (esm.isNextSub("SLSD")) // Short Data? - esm.skipHSub(); - if (esm.isNextSub("SLFD")) // Float Data? - esm.skipHSub(); - } + mSCRI.load(esm); if (esm.isNextSub("ND3D")) esm.skipHSub(); diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 271f6df74..3e3003f58 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -5,6 +5,8 @@ #include +#include "importscri.hpp" + namespace ESM { struct ESMReader; @@ -50,7 +52,7 @@ namespace ESSImport // to change them ingame int mCombatStats[3][2]; - std::string mScript; + SCRI mSCRI; void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 8603200da..a29d26e2a 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -234,6 +234,7 @@ namespace ESSImport converters[ESM::REC_DIAL] = boost::shared_ptr(new ConvertDIAL()); converters[ESM::REC_QUES] = boost::shared_ptr(new ConvertQUES()); converters[recJOUR ] = boost::shared_ptr(new ConvertJOUR()); + converters[ESM::REC_SCPT] = boost::shared_ptr(new ConvertSCPT()); std::set unknownRecords; diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index a20584ff5..d27cd5c8c 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -29,18 +29,7 @@ namespace ESSImport if (esm.isNextSub("XIDX")) // index in the stack? esm.skipHSub(); - std::string script = esm.getHNOString("SCRI"); - // script variables? - // unsure if before or after ESM::CellRef - if (!script.empty()) - { - if (esm.isNextSub("SLCS")) - esm.skipHSub(); - if (esm.isNextSub("SLSD")) // Short Data? - esm.skipHSub(); - if (esm.isNextSub("SLFD")) // Float Data? - esm.skipHSub(); - } + item.mSCRI.load(esm); // for XSOL and XCHG seen so far, but probably others too item.ESM::CellRef::loadData(esm); diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 99fed9b20..0b5405d96 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -5,6 +5,7 @@ #include #include +#include "importscri.hpp" namespace ESM { @@ -21,6 +22,7 @@ namespace ESSImport std::string mId; int mCount; int mRelativeEquipmentSlot; + SCRI mSCRI; }; std::vector mItems; diff --git a/apps/essimporter/importscpt.cpp b/apps/essimporter/importscpt.cpp new file mode 100644 index 000000000..374fd05fa --- /dev/null +++ b/apps/essimporter/importscpt.cpp @@ -0,0 +1,20 @@ +#include "importscpt.hpp" + +#include + + + +namespace ESSImport +{ + + void SCPT::load(ESM::ESMReader &esm) + { + esm.getHNT(mSCHD, "SCHD"); + + mSCRI.load(esm); + + mRNAM = -1; + esm.getHNOT(mRNAM, "RNAM"); + } + +} diff --git a/apps/essimporter/importscpt.hpp b/apps/essimporter/importscpt.hpp new file mode 100644 index 000000000..ca2439dda --- /dev/null +++ b/apps/essimporter/importscpt.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTSCPT_H +#define OPENMW_ESSIMPORT_IMPORTSCPT_H + +#include "importscri.hpp" + +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + // A running global script + // TODO: test how targeted scripts are saved + struct SCPT + { + ESM::Script::SCHD mSCHD; + + // values of local variables + SCRI mSCRI; + + int mRNAM; // unknown, seems to be -1 for some scripts, some huge integer for others + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/apps/essimporter/importscri.cpp b/apps/essimporter/importscri.cpp new file mode 100644 index 000000000..de0b35c86 --- /dev/null +++ b/apps/essimporter/importscri.cpp @@ -0,0 +1,55 @@ +#include "importscri.hpp" + +#include + +namespace ESSImport +{ + + void SCRI::load(ESM::ESMReader &esm) + { + mScript = esm.getHNOString("SCRI"); + + int numShorts = 0, numLongs = 0, numFloats = 0; + if (esm.isNextSub("SLCS")) + { + esm.getSubHeader(); + esm.getT(numShorts); + esm.getT(numLongs); + esm.getT(numFloats); + } + + if (esm.isNextSub("SLSD")) + { + esm.getSubHeader(); + for (int i=0; i + +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + + /// Local variable assigments for a running script + struct SCRI + { + std::string mScript; + + std::vector mShorts; + std::vector mLongs; + std::vector mFloats; + + void load(ESM::ESMReader& esm); + }; + +} + +#endif diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index f2f13d086..2df8e66ce 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -7,12 +7,6 @@ namespace ESM { -struct SCHD -{ - NAME32 mName; - Script::SCHDstruct mData; -}; - unsigned int Script::sRecordId = REC_SCPT; void Script::load(ESMReader &esm) @@ -92,32 +86,6 @@ void Script::load(ESMReader &esm) if (esm.isNextSub("SCVR")) { esm.skipHSub(); } - - // ESS only, TODO: move - if (esm.isNextSub("SLCS")) - { - esm.getSubHeader(); - char unknown[12]; - esm.getExact(unknown, 12); - } - if (esm.isNextSub("SLSD")) - { - float read; - esm.getSubHeader(); - // values of variables? - for (int i=0; i Date: Thu, 22 Jan 2015 04:12:08 +0100 Subject: [PATCH 12/28] Fix Tribunal/BM summon effects not working --- apps/essimporter/importcellref.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 13 ++++++++++--- apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ apps/openmw/mwmechanics/summoning.cpp | 5 +++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 845c574e4..1894b0023 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -23,7 +23,7 @@ namespace ESSImport if (esm.isNextSub("LVCR")) { // occurs on leveled creature spawner references - // probably some identifier for the the creature that has been spawned? + // probably some identifier for the creature that has been spawned? unsigned char lvcr; esm.getHT(lvcr); //std::cout << "LVCR: " << (int)lvcr << std::endl; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ff27ac5f6..49887e560 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -472,9 +472,7 @@ namespace MWMechanics applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); // Re-casting a summon effect will remove the creature from previous castings of that effect. - if (effectIt->mEffectID >= ESM::MagicEffect::SummonScamp - && effectIt->mEffectID <= ESM::MagicEffect::SummonStormAtronach - && !target.isEmpty() && target.getClass().isActor()) + if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor()) { CreatureStats& targetStats = target.getClass().getCreatureStats(target); std::map::iterator found = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId)); @@ -956,4 +954,13 @@ namespace MWMechanics return static_cast((result < 1) ? 1 : result); } + + bool isSummoningEffect(int effectId) + { + return ((effectId >= ESM::MagicEffect::SummonScamp + && effectId <= ESM::MagicEffect::SummonStormAtronach) + || effectId == ESM::MagicEffect::SummonCenturionSphere + || (effectId >= ESM::MagicEffect::SummonFabricant + && effectId <= ESM::MagicEffect::SummonCreature05)); + } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 00fae847f..2d550e085 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -22,6 +22,8 @@ namespace MWMechanics ESM::Skill::SkillEnum spellSchoolToSkill(int school); + bool isSummoningEffect(int effectId); + /** * @param spell spell to cast * @param actor calculate spell success chance for this actor (depends on actor's skills) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 356cb422f..ec9bd0ea0 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -5,6 +5,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwmechanics/spellcasting.hpp" + #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" @@ -51,8 +53,7 @@ namespace MWMechanics void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { - if (key.mId >= ESM::MagicEffect::SummonScamp - && key.mId <= ESM::MagicEffect::SummonStormAtronach && magnitude > 0) + if (isSummoningEffect(key.mId) && magnitude > 0) { mActiveEffects.insert(std::make_pair(key.mId, sourceId)); } From af0e91c2d348b93d65a8db36582db27dac6de971 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 15:21:03 +0100 Subject: [PATCH 13/28] ESSImport: stolen items reading fix --- apps/essimporter/converter.hpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 9894de299..7565b78d4 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -364,15 +364,18 @@ public: { std::string itemid = esm.getHNString("NAME"); - while (esm.isNextSub("ONAM")) + while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) { - std::string ownerid = esm.getHString(); - mStolenItems.insert(std::make_pair(itemid, ownerid)); - } - while (esm.isNextSub("FNAM")) - { - std::string factionid = esm.getHString(); - mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + if (esm.retSubName().toString() == "FNAM") + { + std::string factionid = esm.getHString(); + mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + } + else + { + std::string ownerid = esm.getHString(); + mStolenItems.insert(std::make_pair(itemid, ownerid)); + } } } private: From 8b5effe3e06eb628ac3c12f6fec39052ef26a79b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 17:47:00 +0100 Subject: [PATCH 14/28] Fix wrong magic number for JOUR in openmw savegames --- apps/openmw/mwdialogue/journalimp.cpp | 2 +- apps/openmw/mwstate/statemanagerimp.cpp | 1 + components/esm/defs.hpp | 22 ++++++++++++---------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 1d17134df..597a908e8 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -229,7 +229,7 @@ namespace MWDialogue void Journal::readRecord (ESM::ESMReader& reader, int32_t type) { - if (type==ESM::REC_JOUR) + if (type==ESM::REC_JOUR || type==ESM::REC_JOUR_LEGACY) { ESM::JournalEntry record; record.load (reader); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 87b303b6f..a282f152a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -368,6 +368,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str break; case ESM::REC_JOUR: + case ESM::REC_JOUR_LEGACY: case ESM::REC_QUES: MWBase::Environment::get().getJournal()->readRecord (reader, n.val); diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index effe9a3f1..60926d562 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -96,15 +96,17 @@ enum RecNameInts REC_WEAP = 0x50414557, // format 0 - saved games - REC_SAVE = 0x45564153, - REC_JOUR = 0x524f55a4, // TODO: this is actually "\nOUR" rather than "JOUR", fix - REC_QUES = 0x53455551, - REC_GSCR = 0x52435347, - REC_PLAY = 0x59414c50, - REC_CSTA = 0x41545343, - REC_GMAP = 0x50414d47, - REC_DIAS = 0x53414944, - REC_WTHR = 0x52485457, + REC_SAVE = FourCC<'S','A','V','E'>::value, + REC_JOUR_LEGACY = FourCC<0xa4,'U','O','R'>::value, // "\xa4UOR", rather than "JOUR", little oversight when magic numbers were + // calculated by hand, needs to be supported for older files now + REC_JOUR = FourCC<'J','O','U','R'>::value, + REC_QUES = FourCC<'Q','U','E','S'>::value, + REC_GSCR = FourCC<'G','S','C','R'>::value, + REC_PLAY = FourCC<'P','L','A','Y'>::value, + REC_CSTA = FourCC<'C','S','T','A'>::value, + REC_GMAP = FourCC<'G','M','A','P'>::value, + REC_DIAS = FourCC<'D','I','A','S'>::value, + REC_WTHR = FourCC<'W','T','H','R'>::value, REC_KEYS = FourCC<'K','E','Y','S'>::value, REC_DYNA = FourCC<'D','Y','N','A'>::value, REC_ASPL = FourCC<'A','S','P','L'>::value, @@ -117,7 +119,7 @@ enum RecNameInts REC_CAM_ = FourCC<'C','A','M','_'>::value, // format 1 - REC_FILT = 0x544C4946, + REC_FILT = FourCC<'F','I','L','T'>::value, REC_DBGP = FourCC<'D','B','G','P'>::value ///< only used in project files }; From c883a73d30adc988738c6c577f5c4ae67d8da8a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 19:04:59 +0100 Subject: [PATCH 15/28] Several warning fixes --- apps/bsatool/bsatool.cpp | 8 +++---- apps/esmtool/esmtool.cpp | 24 +++++++++---------- apps/esmtool/labels.cpp | 21 ++++++++-------- apps/esmtool/record.cpp | 22 +++++++++-------- apps/esmtool/record.hpp | 10 +++----- apps/essimporter/main.cpp | 2 +- apps/openmw/mwbase/dialoguemanager.hpp | 2 +- apps/openmw/mwbase/journal.hpp | 2 +- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 +- apps/openmw/mwdialogue/journalimp.cpp | 2 +- apps/openmw/mwdialogue/journalimp.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.hpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/actors.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwscript/globalscripts.cpp | 2 +- apps/openmw/mwscript/globalscripts.hpp | 2 +- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cells.hpp | 2 +- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/openmw/mwworld/esmstore.hpp | 2 +- apps/openmw/mwworld/globals.cpp | 2 +- apps/openmw/mwworld/globals.hpp | 2 +- apps/openmw/mwworld/player.cpp | 2 +- apps/openmw/mwworld/player.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/projectilemanager.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 2 +- apps/openmw/mwworld/weather.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/esmcommon.hpp | 2 +- 42 files changed, 78 insertions(+), 81 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 5b1f7d6bb..c0a6dcc81 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -27,8 +27,8 @@ struct Arguments void replaceAll(std::string& str, const std::string& needle, const std::string& substitute) { - int pos = str.find(needle); - while(pos != -1) + size_t pos = str.find(needle); + while(pos != std::string::npos) { str.replace(pos, needle.size(), substitute); pos = str.find(needle); @@ -138,8 +138,8 @@ bool parseOptions (int argc, char** argv, Arguments &info) else if (variables["input-file"].as< std::vector >().size() > 1) info.outdir = variables["input-file"].as< std::vector >()[1]; - info.longformat = variables.count("long"); - info.fullpath = variables.count("full-path"); + info.longformat = variables.count("long") != 0; + info.fullpath = variables.count("full-path") != 0; return true; } diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index b23ba72f9..9bbf20266 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -22,7 +22,7 @@ struct ESMData { std::string author; std::string description; - int version; + unsigned int version; std::vector masters; std::deque mRecords; @@ -48,9 +48,9 @@ const std::set ESMData::sLabeledRec = // Based on the legacy struct struct Arguments { - unsigned int raw_given; - unsigned int quiet_given; - unsigned int loadcells_given; + bool raw_given; + bool quiet_given; + bool loadcells_given; bool plain_given; std::string mode; @@ -177,10 +177,10 @@ bool parseOptions (int argc, char** argv, Arguments &info) if (variables["input-file"].as< std::vector >().size() > 1) info.outname = variables["input-file"].as< std::vector >()[1]; - info.raw_given = variables.count ("raw"); - info.quiet_given = variables.count ("quiet"); - info.loadcells_given = variables.count ("loadcells"); - info.plain_given = (variables.count("plain") > 0); + info.raw_given = variables.count ("raw") != 0; + info.quiet_given = variables.count ("quiet") != 0; + info.loadcells_given = variables.count ("loadcells") != 0; + info.plain_given = variables.count("plain") != 0; // Font encoding settings info.encoding = variables["encoding"].as(); @@ -430,7 +430,7 @@ int clone(Arguments& info) return 1; } - int recordCount = info.data.mRecords.size(); + size_t recordCount = info.data.mRecords.size(); int digitCount = 1; // For a nicer output if (recordCount > 9) ++digitCount; @@ -501,9 +501,9 @@ int clone(Arguments& info) if (!info.data.mCellRefs[ptr].empty()) { typedef std::deque RefList; RefList &refs = info.data.mCellRefs[ptr]; - for (RefList::iterator it = refs.begin(); it != refs.end(); ++it) + for (RefList::iterator refIt = refs.begin(); refIt != refs.end(); ++refIt) { - it->save(esm); + refIt->save(esm); } } } @@ -511,7 +511,7 @@ int clone(Arguments& info) esm.endRecord(name.toString()); saved++; - int perc = (saved / (float)recordCount)*100; + int perc = (int)((saved / (float)recordCount)*100); if (perc % 10 == 0) { std::cerr << "\r" << perc << "%"; diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 9543628f5..88e188df0 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -13,14 +13,13 @@ #include #include -#include #include std::string bodyPartLabel(int idx) { if (idx >= 0 && idx <= 26) { - const char *bodyPartLabels[] = { + static const char *bodyPartLabels[] = { "Head", "Hair", "Neck", @@ -59,7 +58,7 @@ std::string meshPartLabel(int idx) { if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail) { - const char *meshPartLabels[] = { + static const char *meshPartLabels[] = { "Head", "Hair", "Neck", @@ -86,7 +85,7 @@ std::string meshTypeLabel(int idx) { if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor) { - const char *meshTypeLabels[] = { + static const char *meshTypeLabels[] = { "Skin", "Clothing", "Armor" @@ -101,7 +100,7 @@ std::string clothingTypeLabel(int idx) { if (idx >= 0 && idx <= 9) { - const char *clothingTypeLabels[] = { + static const char *clothingTypeLabels[] = { "Pants", "Shoes", "Shirt", @@ -123,7 +122,7 @@ std::string armorTypeLabel(int idx) { if (idx >= 0 && idx <= 10) { - const char *armorTypeLabels[] = { + static const char *armorTypeLabels[] = { "Helmet", "Cuirass", "Left Pauldron", @@ -146,7 +145,7 @@ std::string dialogTypeLabel(int idx) { if (idx >= 0 && idx <= 4) { - const char *dialogTypeLabels[] = { + static const char *dialogTypeLabels[] = { "Topic", "Voice", "Greeting", @@ -165,7 +164,7 @@ std::string questStatusLabel(int idx) { if (idx >= 0 && idx <= 4) { - const char *questStatusLabels[] = { + static const char *questStatusLabels[] = { "None", "Name", "Finished", @@ -182,7 +181,7 @@ std::string creatureTypeLabel(int idx) { if (idx >= 0 && idx <= 3) { - const char *creatureTypeLabels[] = { + static const char *creatureTypeLabels[] = { "Creature", "Daedra", "Undead", @@ -198,7 +197,7 @@ std::string soundTypeLabel(int idx) { if (idx >= 0 && idx <= 7) { - const char *soundTypeLabels[] = { + static const char *soundTypeLabels[] = { "Left Foot", "Right Foot", "Swim Left", @@ -218,7 +217,7 @@ std::string weaponTypeLabel(int idx) { if (idx >= 0 && idx <= 13) { - const char *weaponTypeLabels[] = { + static const char *weaponTypeLabels[] = { "Short Blade One Hand", "Long Blade One Hand", "Long Blade Two Hand", diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 3f2ebc2ba..2f07a5f08 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -25,7 +25,7 @@ void printAIPackage(ESM::AIPackage p) { std::cout << " Travel Coordinates: (" << p.mTravel.mX << "," << p.mTravel.mY << "," << p.mTravel.mZ << ")" << std::endl; - std::cout << " Travel Unknown: " << (int)p.mTravel.mUnk << std::endl; + std::cout << " Travel Unknown: " << p.mTravel.mUnk << std::endl; } else if (p.mType == ESM::AI_Follow || p.mType == ESM::AI_Escort) { @@ -33,12 +33,12 @@ void printAIPackage(ESM::AIPackage p) << p.mTarget.mY << "," << p.mTarget.mZ << ")" << std::endl; std::cout << " Duration: " << p.mTarget.mDuration << std::endl; std::cout << " Target ID: " << p.mTarget.mId.toString() << std::endl; - std::cout << " Unknown: " << (int)p.mTarget.mUnk << std::endl; + std::cout << " Unknown: " << p.mTarget.mUnk << std::endl; } else if (p.mType == ESM::AI_Activate) { std::cout << " Name: " << p.mActivate.mName.toString() << std::endl; - std::cout << " Activate Unknown: " << (int)p.mActivate.mUnk << std::endl; + std::cout << " Activate Unknown: " << p.mActivate.mUnk << std::endl; } else { std::cout << " BadPackage: " << boost::format("0x%08x") % p.mType << std::endl; @@ -89,6 +89,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case 'A': if (indicator == 'R') type_str = "Not Race"; break; case 'B': if (indicator == 'L') type_str = "Not Cell"; break; case 'C': if (indicator == 's') type_str = "Not Local"; break; + default: break; } // Append the variable name to the function string if any. @@ -110,6 +111,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case '3': oper_str = ">="; break; case '4': oper_str = "< "; break; case '5': oper_str = "<="; break; + default: break; } std::ostringstream stream; @@ -430,7 +432,7 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Type: " << apparatusTypeLabel(mData.mData.mType) - << " (" << (int)mData.mData.mType << ")" << std::endl; + << " (" << mData.mData.mType << ")" << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; @@ -816,7 +818,7 @@ void Record::print() // Seems like this should done with reference counting in the // loader to me. But I'm not really knowledgable about this // record type yet. --Cory - bool wasLoaded = mData.mDataLoaded; + bool wasLoaded = (mData.mDataLoaded != 0); if (mData.mDataTypes) mData.loadData(mData.mDataTypes); if (mData.mDataLoaded) { @@ -999,7 +1001,7 @@ void Record::print() << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl; std::cout << " Unknown3: " << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl; - std::cout << " Gold: " << (int)mData.mNpdt12.mGold << std::endl; + std::cout << " Gold: " << mData.mNpdt12.mGold << std::endl; } else { std::cout << " Level: " << mData.mNpdt52.mLevel << std::endl; @@ -1021,7 +1023,7 @@ void Record::print() std::cout << " Skills:" << std::endl; for (int i = 0; i != ESM::Skill::Length; i++) std::cout << " " << skillLabel(i) << ": " - << (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl; + << (int)(mData.mNpdt52.mSkills[i]) << std::endl; std::cout << " Health: " << mData.mNpdt52.mHealth << std::endl; std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl; @@ -1123,9 +1125,9 @@ void Record::print() std::cout << (male ? " Male:" : " Female:") << std::endl; - for (int i=0; i<8; ++i) - std::cout << " " << sAttributeNames[i] << ": " - << mData.mData.mAttributeValues[i].getValue (male) << std::endl; + for (int j=0; j<8; ++j) + std::cout << " " << sAttributeNames[j] << ": " + << mData.mData.mAttributeValues[j].getValue (male) << std::endl; std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl; std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl; diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index 45b6d0426..c1b90ac2b 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -19,7 +19,7 @@ namespace EsmTool { protected: std::string mId; - int mFlags; + uint32_t mFlags; ESM::NAME mType; bool mPrintPlain; @@ -40,11 +40,11 @@ namespace EsmTool mId = id; } - int getFlags() const { + uint32_t getFlags() const { return mFlags; } - void setFlags(int flags) { + void setFlags(uint32_t flags) { mFlags = flags; } @@ -52,10 +52,6 @@ namespace EsmTool return mType; } - bool getPrintPlain() const { - return mPrintPlain; - } - void setPrintPlain(bool plain) { mPrintPlain = plain; } diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index 1c7d51116..5a9e0c77d 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -12,7 +12,7 @@ namespace bfs = boost::filesystem; -int main(int argc, const char** argv) +int main(int argc, char** argv) { try { diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index d35b5950f..1fe63e633 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -69,7 +69,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0; diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index 938cec74b..738014ba6 100644 --- a/apps/openmw/mwbase/journal.hpp +++ b/apps/openmw/mwbase/journal.hpp @@ -92,7 +92,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; }; } diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index a51e3a301..33a2ef1ea 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -193,7 +193,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; virtual void clear() = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 3e957ef14..02cbc69e9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -310,7 +310,7 @@ namespace MWBase virtual void clear() = 0; virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0; virtual int countSavedGameRecords() const = 0; /// Does the current stack of GUI-windows permit saving? diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index db0f0a763..f58ef0809 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -108,7 +108,7 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0; - virtual void readRecord (ESM::ESMReader& reader, int32_t type, + virtual void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) = 0; virtual MWWorld::CellStore *getExterior (int x, int y) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 0ee7dfe94..d2534cd82 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -647,7 +647,7 @@ namespace MWDialogue writer.endRecord (ESM::REC_DIAS); } - void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type) + void DialogueManager::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_DIAS) { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index c06299736..77035bc60 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -92,7 +92,7 @@ namespace MWDialogue virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); /// Changes faction1's opinion of faction2 by \a diff. virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff); diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 597a908e8..3b57912da 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -227,7 +227,7 @@ namespace MWDialogue } } - void Journal::readRecord (ESM::ESMReader& reader, int32_t type) + void Journal::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_JOUR || type==ESM::REC_JOUR_LEGACY) { diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index d15b909fa..7f26a5bb9 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -71,7 +71,7 @@ namespace MWDialogue virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); }; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index abd1256d7..00d60f23b 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -886,7 +886,7 @@ namespace MWGui writer.endRecord(ESM::REC_GMAP); } - void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type) + void MapWindow::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_GMAP) { diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 684069467..7b6c1f205 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -177,7 +177,7 @@ namespace MWGui void clear(); void write (ESM::ESMWriter& writer, Loading::Listener& progress); - void readRecord (ESM::ESMReader& reader, int32_t type); + void readRecord (ESM::ESMReader& reader, uint32_t type); private: void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index deba64434..a102de1e5 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -431,7 +431,7 @@ namespace MWGui writer.endRecord(ESM::REC_KEYS); } - void QuickKeysMenu::readRecord(ESM::ESMReader &reader, int32_t type) + void QuickKeysMenu::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type != ESM::REC_KEYS) return; diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 30e672891..00afa4561 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -47,7 +47,7 @@ namespace MWGui void write (ESM::ESMWriter& writer); - void readRecord (ESM::ESMReader& reader, int32_t type); + void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5b2bbee90..e976b984f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1620,7 +1620,7 @@ namespace MWGui } } - void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type) + void WindowManager::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_GMAP) mMap->readRecord(reader, type); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 44d5819c2..a08c59a2f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -306,7 +306,7 @@ namespace MWGui virtual void clear(); virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress); - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); virtual int countSavedGameRecords() const; /// Does the current stack of GUI-windows permit saving? diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 64434a304..f8068e800 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1468,7 +1468,7 @@ namespace MWMechanics writer.endRecord(ESM::REC_DCOU); } - void Actors::readRecord (ESM::ESMReader& reader, int32_t type) + void Actors::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type == ESM::REC_DCOU) { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 39fe38208..39598b2a2 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -128,7 +128,7 @@ namespace MWMechanics void write (ESM::ESMWriter& writer, Loading::Listener& listener) const; - void readRecord (ESM::ESMReader& reader, int32_t type); + void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); // Clear death counter diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3d757bde6..0a2c3cfff 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1360,7 +1360,7 @@ namespace MWMechanics mActors.write(writer, listener); } - void MechanicsManager::readRecord(ESM::ESMReader &reader, int32_t type) + void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type) { mActors.readRecord(reader, type); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index fc9c58974..2f443ad59 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -158,7 +158,7 @@ namespace MWMechanics virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type); + virtual void readRecord (ESM::ESMReader& reader, uint32_t type); virtual void clear(); diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index c7371100f..6c4bb3be5 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -145,7 +145,7 @@ namespace MWScript } } - bool GlobalScripts::readRecord (ESM::ESMReader& reader, int32_t type) + bool GlobalScripts::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_GSCR) { diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 55c2e9321..9f009db98 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -62,7 +62,7 @@ namespace MWScript void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< Records for variables that do not exist are dropped silently. /// /// \return Known type? diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 3a8b7d5c4..fd5ec20dc 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -299,7 +299,7 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress) } } -bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type, +bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) { if (type==ESM::REC_CSTA) diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index a9c17fa93..0b7d9444f 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -76,7 +76,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type, + bool readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap); }; } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index b096f4b90..caa88d751 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -175,7 +175,7 @@ void ESMStore::setUp() mCreatureLists.write (writer, progress); } - bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type) + bool ESMStore::readRecord (ESM::ESMReader& reader, uint32_t type) { switch (type) { diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 01770e6b3..05b633956 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -233,7 +233,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< \return Known type? }; diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 302a05824..e7cb04590 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -88,7 +88,7 @@ namespace MWWorld } } - bool Globals::readRecord (ESM::ESMReader& reader, int32_t type) + bool Globals::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_GLOB) { diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index 3ff4a5d6e..bb4ab13d9 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -53,7 +53,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); ///< Records for variables that do not exist are dropped silently. /// /// \return Known type? diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index a57934bd3..c1e176b91 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -227,7 +227,7 @@ namespace MWWorld writer.endRecord (ESM::REC_PLAY); } - bool Player::readRecord (ESM::ESMReader& reader, int32_t type) + bool Player::readRecord (ESM::ESMReader& reader, uint32_t type) { if (type==ESM::REC_PLAY) { diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index d8cde5952..25d8981cd 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -102,7 +102,7 @@ namespace MWWorld void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); int getNewCrimeId(); // get new id for witnesses void recordCrimeId(); // record the paid crime id when bounty is 0 diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index e4b2d5a1e..41fbfea9f 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -343,7 +343,7 @@ namespace MWWorld } } - bool ProjectileManager::readRecord(ESM::ESMReader &reader, int32_t type) + bool ProjectileManager::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_PROJ) { diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 6e84b9efb..93f54c008 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -53,7 +53,7 @@ namespace MWWorld void clear(); void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - bool readRecord (ESM::ESMReader& reader, int32_t type); + bool readRecord (ESM::ESMReader& reader, uint32_t type); int countSavedGameRecords() const; private: diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index cd05cb798..6532c5969 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -762,7 +762,7 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) writer.endRecord(ESM::REC_WTHR); } -bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type) +bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index dee9fc52a..830b5c376 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -199,7 +199,7 @@ namespace MWWorld void write(ESM::ESMWriter& writer, Loading::Listener& progress); - bool readRecord(ESM::ESMReader& reader, int32_t type); + bool readRecord(ESM::ESMReader& reader, uint32_t type); private: float mHour; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f7d5d9616..ceac85bca 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -345,7 +345,7 @@ namespace MWWorld writer.endRecord(ESM::REC_CAM_); } - void World::readRecord (ESM::ESMReader& reader, int32_t type, + void World::readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) { switch (type) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f050c498d..9834015ac 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -170,7 +170,7 @@ namespace MWWorld virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; - virtual void readRecord (ESM::ESMReader& reader, int32_t type, + virtual void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap); virtual CellStore *getExterior (int x, int y); diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index d3e6e7fea..1bdadead2 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -23,7 +23,7 @@ template union NAME_T { char name[LEN]; - int32_t val; + uint32_t val; bool operator==(const char *str) const { From a619cff615f011beb2ed89fc2d1900671f3107d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 21:39:07 +0100 Subject: [PATCH 16/28] Implement EnableLevelupMenu to trigger level-up --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/guiextensions.cpp | 2 ++ components/compiler/extensions0.cpp | 2 +- components/compiler/opcodes.hpp | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index b139d6138..41cc6b88a 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -443,5 +443,6 @@ op 0x20002fc: RemoveFromLevCreature op 0x20002fd: AddToLevItem op 0x20002fe: RemoveFromLevItem op 0x20002ff: SetFactionReaction +op 0x2000300: EnableLevelupMenu -opcodes 0x2000300-0x3ffffff unused +opcodes 0x2000301-0x3ffffff unused diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 1d34adbca..f5549a172 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -231,6 +231,8 @@ namespace MWScript new OpShowDialogue (MWGui::GM_Race)); interpreter.installSegment5 (Compiler::Gui::opcodeEnableStatsReviewMenu, new OpShowDialogue (MWGui::GM_Review)); + interpreter.installSegment5 (Compiler::Gui::opcodeEnableLevelupMenu, + new OpShowDialogue (MWGui::GM_Levelup)); interpreter.installSegment5 (Compiler::Gui::opcodeEnableInventoryMenu, new OpEnableWindow (MWGui::GW_Inventory)); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index a5cc0da62..70338669e 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -215,7 +215,7 @@ namespace Compiler extensions.registerInstruction ("enablestatsmenu", "", opcodeEnableStatsMenu); extensions.registerInstruction ("enablerest", "", opcodeEnableRest); - extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableRest); + extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableLevelupMenu); extensions.registerInstruction ("showrestmenu", "", opcodeShowRestMenu, opcodeShowRestMenuExplicit); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 04666e976..e5cf2e965 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -185,6 +185,7 @@ namespace Compiler const int opcodeEnableMapMenu = 0x2000015; const int opcodeEnableStatsMenu = 0x2000016; const int opcodeEnableRest = 0x2000017; + const int opcodeEnableLevelupMenu = 0x2000300; const int opcodeShowRestMenu = 0x2000018; const int opcodeShowRestMenuExplicit = 0x2000234; const int opcodeGetButtonPressed = 0x2000137; From ba7cd04ff7ac7546ef71ebd999e97dd4ef36028f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 23:28:31 +0100 Subject: [PATCH 17/28] ESSImport: prevent accidental overwriting of file --- apps/essimporter/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index 5a9e0c77d..d467e053e 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -50,7 +50,15 @@ int main(int argc, char** argv) if (vm.count("compare")) importer.compare(); else + { + const std::string& ext = ".omwsave"; + if (boost::filesystem::exists(boost::filesystem::path(outputFile)) + && (outputFile.size() < ext.size() || outputFile.substr(outputFile.size()-ext.size()) != ext)) + { + throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?"); + } importer.run(); + } } catch (std::exception& e) { From 1d29180e003f00406b5dafef6364534ef84dac07 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 23:28:43 +0100 Subject: [PATCH 18/28] ESSImport: handle deleted cell references --- apps/essimporter/importcellref.cpp | 6 ++---- apps/essimporter/importer.cpp | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 1894b0023..906b2ed24 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -41,11 +41,9 @@ namespace ESSImport mDeleted = 0; if (esm.isNextSub("DELE")) { - int deleted; + unsigned int deleted; esm.getHT(deleted); - // Neither of this seems to work right... - //mDeleted = (deleted != 0); - //mDeleted = (deleted&0x1); + mDeleted = (deleted >> 24) & 0x2; // the other 3 bytes seem to be uninitialized garbage } if (esm.isNextSub("MVRF")) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index a29d26e2a..9fd2903d8 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -105,6 +105,7 @@ namespace ESSImport blacklist.insert(std::make_pair("REFR", "DATA")); // player position blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war blacklist.insert(std::make_pair("GAME", "GMDT")); // weather data, current time always changes + blacklist.insert(std::make_pair("CELL", "DELE")); // first 3 bytes are uninitialized // this changes way too often, name suggests some renderer internal data? blacklist.insert(std::make_pair("CELL", "ND3D")); From c354f48a07080a08e713d4114ede4c13ca869996 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 Jan 2015 23:42:43 +0100 Subject: [PATCH 19/28] ESSImport: some fixes --- apps/essimporter/importcrec.cpp | 9 ++------- apps/essimporter/importdial.cpp | 12 +++++++++++- apps/essimporter/importnpcc.cpp | 9 ++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 28e5ac56f..7a8a3eb00 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -15,13 +15,8 @@ namespace ESSImport esm.getHNOT(scale, "XSCL"); // FIXME: use AiPackageList, need to fix getSubName() - if (esm.isNextSub("AI_W")) - esm.skipHSub(); - if (esm.isNextSub("AI_E")) - esm.skipHSub(); - if (esm.isNextSub("AI_T")) - esm.skipHSub(); - if (esm.isNextSub("AI_F")) + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") + || esm.isNextSub("AI_A")) esm.skipHSub(); mInventory.load(esm); diff --git a/apps/essimporter/importdial.cpp b/apps/essimporter/importdial.cpp index 228d00a5a..5797a708a 100644 --- a/apps/essimporter/importdial.cpp +++ b/apps/essimporter/importdial.cpp @@ -7,7 +7,17 @@ namespace ESSImport void DIAL::load(ESM::ESMReader &esm) { - esm.getHNT(mIndex, "XIDX"); + // See ESM::Dialogue::Type enum, not sure why we would need this here though + int type = 0; + esm.getHNOT(type, "DATA"); + + // Deleted dialogue in a savefile. No clue what this means... + int deleted = 0; + esm.getHNOT(deleted, "DELE"); + + mIndex = 0; + // *should* always occur except when the dialogue is deleted, but leaving it optional just in case... + esm.getHNOT(mIndex, "XIDX"); } } diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 7b8dda371..547b01441 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -10,13 +10,8 @@ namespace ESSImport esm.getHNT(mNPDT, "NPDT"); // FIXME: use AiPackageList, need to fix getSubName() - if (esm.isNextSub("AI_W")) - esm.skipHSub(); - if (esm.isNextSub("AI_E")) - esm.skipHSub(); - if (esm.isNextSub("AI_T")) - esm.skipHSub(); - if (esm.isNextSub("AI_F")) + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") + || esm.isNextSub("AI_A")) esm.skipHSub(); mInventory.load(esm); From e484a91708683c5f6f0d26ea4c46ad73fce2bdd3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 00:15:57 +0100 Subject: [PATCH 20/28] ESSImport: convert global map markers --- apps/essimporter/converter.cpp | 10 ++++++++++ apps/essimporter/importer.cpp | 4 ++-- apps/essimporter/importercontext.hpp | 8 ++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 81521a028..75c2911fd 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -76,6 +76,12 @@ namespace ESSImport cell.mName = id; cell.load(esm, false); + // I wonder what 0x40 does? + if (cell.isExterior() && cell.mData.mFlags & 0x20) + { + mContext->mGlobalMapState.mMarkers.insert(std::make_pair(cell.mData.mX, cell.mData.mY)); + } + // note if the player is in a nameless exterior cell, we will assign the cellId later based on player position if (id == mContext->mPlayerCellName) { @@ -304,6 +310,10 @@ namespace ESSImport it->save(esm); esm.endRecord(ESM::REC_MARK); } + + esm.startRecord(ESM::REC_GMAP); + mContext->mGlobalMapState.save(esm); + esm.endRecord(ESM::REC_GMAP); } } diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 9fd2903d8..ed149b023 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -123,7 +123,7 @@ namespace ESSImport if (i >= file2.mRecords.size()) { - std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset; + std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl; return; } @@ -142,7 +142,7 @@ namespace ESSImport if (j >= rec2.mSubrecords.size()) { - std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset; + std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl; return; } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 02585799a..211195d3f 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "importnpcc.hpp" #include "importcrec.hpp" @@ -28,6 +29,8 @@ namespace ESSImport ESM::DialogueState mDialogueState; + ESM::GlobalMap mGlobalMapState; + int mDay, mMonth, mYear; float mHour; @@ -48,6 +51,11 @@ namespace ESSImport mPlayer.mCurrentCrimeId = 0; // TODO mPlayer.mObject.blank(); mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame + + mGlobalMapState.mBounds.mMinX = 0; + mGlobalMapState.mBounds.mMaxX = 0; + mGlobalMapState.mBounds.mMinY = 0; + mGlobalMapState.mBounds.mMaxY = 0; } }; From 79d2eebe5435b9e1e92acbec2c191dc416b12a7b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 16:45:47 +0100 Subject: [PATCH 21/28] Store selected enchant item in savegame (Fixes #1702) --- apps/essimporter/convertinventory.cpp | 9 ++- apps/openmw/mwworld/containerstore.cpp | 87 ++++++++++++++------------ apps/openmw/mwworld/containerstore.hpp | 9 +-- apps/openmw/mwworld/inventorystore.cpp | 48 +++++++++----- apps/openmw/mwworld/inventorystore.hpp | 7 +-- components/esm/inventorystate.cpp | 76 +++++++++++++--------- components/esm/inventorystate.hpp | 9 ++- 7 files changed, 145 insertions(+), 100 deletions(-) diff --git a/apps/essimporter/convertinventory.cpp b/apps/essimporter/convertinventory.cpp index 31272bf5a..f476fe1ee 100644 --- a/apps/essimporter/convertinventory.cpp +++ b/apps/essimporter/convertinventory.cpp @@ -7,6 +7,7 @@ namespace ESSImport void convertInventory(const Inventory &inventory, ESM::InventoryState &state) { + int index = 0; for (std::vector::const_iterator it = inventory.mItems.begin(); it != inventory.mItems.end(); ++it) { @@ -16,7 +17,13 @@ namespace ESSImport objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId); objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile // openmw handles them differently, so no need to set any flags - state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot)); + state.mItems.push_back(objstate); + if (it->mRelativeEquipmentSlot != -1) + // Note we should really write the absolute slot here, which we do not know about + // Not a big deal, OpenMW will auto-correct to a valid slot, the only problem is when + // an item could be equipped in two different slots (e.g. equipped two rings) + state.mEquipmentSlots[index] = it->mRelativeEquipmentSlot; + ++index; } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 57621b7a4..b21486c2c 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -79,6 +79,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState (CellRefList void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::ObjectState& state) const { @@ -87,7 +95,7 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef& ref, ESM::Object template void MWWorld::ContainerStore::storeStates (CellRefList& collection, - std::vector >& states, bool equipable) const + ESM::InventoryState& inventory, int& index, bool equipable) const { for (typename CellRefList::List::const_iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) @@ -96,18 +104,13 @@ void MWWorld::ContainerStore::storeStates (CellRefList& collection, continue; ESM::ObjectState state; storeState (*iter, state); - int slot = equipable ? getSlot (*iter) : -1; - states.push_back (std::make_pair (state, slot)); + if (equipable) + storeEquipmentState(*iter, index, inventory); + inventory.mItems.push_back (state); + ++index; } } -int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const -{ - return -1; -} - -void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {} - const std::string MWWorld::ContainerStore::sGoldId = "gold_001"; MWWorld::ContainerStore::ContainerStore() : mCachedWeight (0), mWeightUpToDate (false) {} @@ -645,49 +648,51 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) { state.mItems.clear(); - storeStates (potions, state.mItems); - storeStates (appas, state.mItems); - storeStates (armors, state.mItems, true); - storeStates (books, state.mItems); - storeStates (clothes, state.mItems, true); - storeStates (ingreds, state.mItems); - storeStates (lockpicks, state.mItems, true); - storeStates (miscItems, state.mItems); - storeStates (probes, state.mItems, true); - storeStates (repairs, state.mItems); - storeStates (weapons, state.mItems, true); - storeStates (lights, state.mItems, true); + int index = 0; + storeStates (potions, state, index); + storeStates (appas, state, index); + storeStates (armors, state, index, true); + storeStates (books, state, index, true); // not equipable as such, but for selectedEnchantItem + storeStates (clothes, state, index, true); + storeStates (ingreds, state, index); + storeStates (lockpicks, state, index, true); + storeStates (miscItems, state, index); + storeStates (probes, state, index, true); + storeStates (repairs, state, index); + storeStates (weapons, state, index, true); + storeStates (lights, state, index, true); state.mLevelledItemMap = mLevelledItemMap; } -void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) +void MWWorld::ContainerStore::readState (const ESM::InventoryState& inventory) { clear(); - for (std::vector >::const_iterator - iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter) + int index = 0; + for (std::vector::const_iterator + iter (inventory.mItems.begin()); iter!=inventory.mItems.end(); ++iter) { - int slot = iter->second; - - const ESM::ObjectState& state = iter->first; + const ESM::ObjectState& state = *iter; int type = MWBase::Environment::get().getWorld()->getStore().find(state.mRef.mRefID); + int thisIndex = index++; + switch (type) { - case ESM::REC_ALCH: getState (potions, iter->first); break; - case ESM::REC_APPA: getState (appas, iter->first); break; - case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break; - case ESM::REC_BOOK: getState (books, iter->first); break; - case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break; - case ESM::REC_INGR: getState (ingreds, iter->first); break; - case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break; - case ESM::REC_MISC: getState (miscItems, iter->first); break; - case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break; - case ESM::REC_REPA: getState (repairs, iter->first); break; - case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break; - case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break; + case ESM::REC_ALCH: getState (potions, state); break; + case ESM::REC_APPA: getState (appas, state); break; + case ESM::REC_ARMO: readEquipmentState (getState (armors, state), thisIndex, inventory); break; + case ESM::REC_BOOK: readEquipmentState (getState (books, state), thisIndex, inventory); break; // not equipable as such, but for selectedEnchantItem + case ESM::REC_CLOT: readEquipmentState (getState (clothes, state), thisIndex, inventory); break; + case ESM::REC_INGR: getState (ingreds, state); break; + case ESM::REC_LOCK: readEquipmentState (getState (lockpicks, state), thisIndex, inventory); break; + case ESM::REC_MISC: getState (miscItems, state); break; + case ESM::REC_PROB: readEquipmentState (getState (probes, state), thisIndex, inventory); break; + case ESM::REC_REPA: getState (repairs, state); break; + case ESM::REC_WEAP: readEquipmentState (getState (weapons, state), thisIndex, inventory); break; + case ESM::REC_LIGH: readEquipmentState (getState (lights, state), thisIndex, inventory); break; case 0: std::cerr << "Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; break; @@ -698,7 +703,7 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& state) } - mLevelledItemMap = state.mLevelledItemMap; + mLevelledItemMap = inventory.mLevelledItemMap; } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index f7c8a369c..d909a98cc 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -86,15 +86,12 @@ namespace MWWorld template void storeStates (CellRefList& collection, - std::vector >& states, + ESM::InventoryState& inventory, int& index, bool equipable = false) const; - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; - ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot); - ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. + virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; + virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); public: ContainerStore(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index be93824e5..4950be912 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -49,33 +49,47 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_) slots_.push_back (end()); } -int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const +void MWWorld::InventoryStore::storeEquipmentState(const MWWorld::LiveCellRefBase &ref, int index, ESM::InventoryState &inventory) const { for (int i = 0; i (mSlots.size()); ++i) if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref) - return i; + { + inventory.mEquipmentSlots[index] = i; + } - return -1; + if (mSelectedEnchantItem.getType()!=-1 && mSelectedEnchantItem->getBase() == &ref) + inventory.mSelectedEnchantItem = index; } -void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot) +void MWWorld::InventoryStore::readEquipmentState(const MWWorld::ContainerStoreIterator &iter, int index, const ESM::InventoryState &inventory) { - if (relativeSlot < 0 || iter == end()) - return; - - // make sure the item can actually be equipped in this slot - std::pair, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); - relativeSlot = std::min(int(allowedSlots.first.size()-1), relativeSlot); + if (index == inventory.mSelectedEnchantItem) + mSelectedEnchantItem = iter; - // unstack if required - if (!allowedSlots.second && iter->getRefData().getCount() > 1) + std::map::const_iterator found = inventory.mEquipmentSlots.find(index); + if (found != inventory.mEquipmentSlots.end()) { - MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); - iter->getRefData().setCount(iter->getRefData().getCount()-1); - mSlots[allowedSlots.first[relativeSlot]] = newIter; + if (found->second < 0 || found->second >= MWWorld::InventoryStore::Slots) + throw std::runtime_error("Invalid slot index in inventory state"); + + // make sure the item can actually be equipped in this slot + int slot = found->second; + std::pair, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter); + if (!allowedSlots.first.size()) + return; + if (std::find(allowedSlots.first.begin(), allowedSlots.first.end(), slot) == allowedSlots.first.end()) + slot = allowedSlots.first.front(); + + // unstack if required + if (!allowedSlots.second && iter->getRefData().getCount() > 1) + { + MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1); + iter->getRefData().setCount(iter->getRefData().getCount()-1); + mSlots[slot] = newIter; + } + else + mSlots[slot] = iter; } - else - mSlots[allowedSlots.first[relativeSlot]] = iter; } MWWorld::InventoryStore::InventoryStore() diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 7bd977e39..9a154373a 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -113,11 +113,8 @@ namespace MWWorld void fireEquipmentChangedEvent(); - virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const; - ///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot). - - virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot); - ///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1. + virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; + virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); public: diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index b946f9501..4eaaa9f9f 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -4,42 +4,33 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -namespace -{ - void read (ESM::ESMReader &esm, ESM::ObjectState& state, int& slot) - { - slot = -1; - esm.getHNOT (slot, "SLOT"); - - state.mRef.loadId(esm, true); - state.load (esm); - } - - void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, int slot) - { - int unused = 0; - esm.writeHNT ("IOBJ", unused); - - if (slot!=-1) - esm.writeHNT ("SLOT", slot); - - state.save (esm, true); - } -} - void ESM::InventoryState::load (ESMReader &esm) { + int index = 0; while (esm.isNextSub ("IOBJ")) { int unused; // no longer used esm.getHT(unused); ObjectState state; - int slot; - read (esm, state, slot); + + // obsolete + if (esm.isNextSub("SLOT")) + { + int slot; + esm.getHT(slot); + mEquipmentSlots[index] = slot; + } + + state.mRef.loadId(esm, true); + state.load (esm); + if (state.mCount == 0) continue; - mItems.push_back (std::make_pair (state, slot)); + + mItems.push_back (state); + + ++index; } while (esm.isNextSub("LEVM")) @@ -64,12 +55,30 @@ void ESM::InventoryState::load (ESMReader &esm) } mPermanentMagicEffectMagnitudes[id] = params; } + + while (esm.isNextSub("EQUI")) + { + esm.getSubHeader(); + int index; + esm.getT(index); + int slot; + esm.getT(slot); + mEquipmentSlots[index] = slot; + } + + mSelectedEnchantItem = -1; + esm.getHNOT(mSelectedEnchantItem, "SELE"); } void ESM::InventoryState::save (ESMWriter &esm) const { - for (std::vector >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) - write (esm, iter->first, iter->second); + for (std::vector::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter) + { + int unused = 0; + esm.writeHNT ("IOBJ", unused); + + iter->save (esm, true); + } for (std::map::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) { @@ -88,4 +97,15 @@ void ESM::InventoryState::save (ESMWriter &esm) const esm.writeHNT ("MULT", pIt->second); } } + + for (std::map::const_iterator it = mEquipmentSlots.begin(); it != mEquipmentSlots.end(); ++it) + { + esm.startSubRecord("EQUI"); + esm.writeT(it->first); + esm.writeT(it->second); + esm.endRecord("EQUI"); + } + + if (mSelectedEnchantItem != -1) + esm.writeHNT ("SELE", mSelectedEnchantItem); } diff --git a/components/esm/inventorystate.hpp b/components/esm/inventorystate.hpp index 13af28e30..d5c317beb 100644 --- a/components/esm/inventorystate.hpp +++ b/components/esm/inventorystate.hpp @@ -15,14 +15,19 @@ namespace ESM /// \brief State for inventories and containers struct InventoryState { - /// - std::vector > mItems; + std::vector mItems; + + // + std::map mEquipmentSlots; std::map mLevelledItemMap; typedef std::map > > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; + int mSelectedEnchantItem; // For inventories only + + InventoryState() : mSelectedEnchantItem(-1) {} virtual ~InventoryState() {} virtual void load (ESMReader &esm); From b0c2aec374e7faddbcc9927c537457f63de6a6be Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 17:29:03 +0100 Subject: [PATCH 22/28] Add warning for missing body parts --- apps/openmw/mwrender/npcanimation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a8ba1abf5..9b05ce0a2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -811,6 +811,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormData.mPart == ESM::BodyPart::MP_Upperarm)) bodypart = NULL; } + else if (!bodypart) + std::cerr << "Failed to find body part '" << part->mFemale << "'" << std::endl; } if(!bodypart && !part->mMale.empty()) { @@ -824,6 +826,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectormData.mPart == ESM::BodyPart::MP_Upperarm)) bodypart = NULL; } + else if (!bodypart) + std::cerr << "Failed to find body part '" << part->mMale << "'" << std::endl; } if(bodypart) From bf90b86f73d47a95442865b9254b46d8e350c0ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 20:09:30 +0100 Subject: [PATCH 23/28] ESSImport: add some missing subrecords --- apps/essimporter/importacdt.cpp | 4 ++++ apps/essimporter/importplayer.cpp | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index e590e2826..00bd4ad80 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -60,6 +60,10 @@ namespace ESSImport if (esm.isNextSub("PWPS")) esm.skipHSub(); + // unsure at which point between LSTN and CHRD + if (esm.isNextSub("APUD")) + esm.skipHSub(); // 40 bytes, starts with string "ancestor guardian"... + if (esm.isNextSub("WNAM")) { esm.skipHSub(); // seen values: "ancestor guardian", "bound dagger_en". Summoned creature / bound weapons? diff --git a/apps/essimporter/importplayer.cpp b/apps/essimporter/importplayer.cpp index ea9f1932c..9845ab072 100644 --- a/apps/essimporter/importplayer.cpp +++ b/apps/essimporter/importplayer.cpp @@ -63,8 +63,11 @@ namespace ESSImport mFactions.push_back(fnam); } + if (esm.isNextSub("AADT")) + esm.skipHSub(); // 44 bytes, no clue + if (esm.isNextSub("KNAM")) - esm.skipHSub(); + esm.skipHSub(); // assigned Quick Keys, I think if (esm.isNextSub("WERE")) { @@ -73,6 +76,10 @@ namespace ESSImport esm.getSubHeader(); esm.skip(152); } + + // unsure if before or after WERE + if (esm.isNextSub("ANIS")) + esm.skipHSub(); } } From 8e5c8aa562ba4d03c112bf78ee3a840d0c05c12d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 Jan 2015 23:57:00 +0100 Subject: [PATCH 24/28] Add support for passing in Ogre plugin directory via CMake --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ceee29e6..c3def1381 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,8 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binarie option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) +set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre plugins (autodetected by default)") + option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) # Apps and tools @@ -323,8 +325,10 @@ if (APPLE AND OPENMW_OSX_DEPLOYMENT) # make it empty so plugin loading code can check this and try to find plugins inside app bundle add_definitions(-DOGRE_PLUGIN_DIR="") else() - if (NOT DEFINED ${OGRE_PLUGIN_DIR}) + if (CUSTOM_OGRE_PLUGIN_DIR STREQUAL "") set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) + else() + set(OGRE_PLUGIN_DIR ${CUSTOM_OGRE_PLUGIN_DIR}) endif() add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") From 09f11fbff224b0c5c364629d56bd2929d0956875 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 00:18:17 +0100 Subject: [PATCH 25/28] ESSImport: convert selected spell / selected enchant item --- apps/essimporter/converter.hpp | 21 +++++++++++++++++++++ apps/essimporter/importacdt.cpp | 11 +++++------ apps/essimporter/importacdt.hpp | 3 +++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 7565b78d4..6f85b01cf 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -226,7 +226,28 @@ public: ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats; convertNpcData(refr.mActorData, npcStats); + + mSelectedSpell = refr.mActorData.mSelectedSpell; + if (!refr.mActorData.mSelectedEnchantItem.empty()) + { + ESM::InventoryState& invState = mContext->mPlayer.mObject.mInventory; + + for (unsigned int i=0; i Date: Sat, 24 Jan 2015 14:32:02 +0100 Subject: [PATCH 26/28] Fix loading faction reactions for older savegames (Fixes #2301) --- components/esm/dialoguestate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index f546462a3..f302e36dc 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -25,7 +25,7 @@ void ESM::DialogueState::load (ESMReader &esm) while (esm.isNextSub ("REAC")) { esm.skipHSub(); - esm.getSubHeader(); + esm.getSubName(); esm.skipHSub(); } } From b1bd236345fbe4fbd84f9855c958c02d323a9863 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 16:15:52 +0100 Subject: [PATCH 27/28] ESSImport: convert script local variables Had to add special reading code to openmw, because the variable names are not stored. --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.cpp | 3 ++ apps/essimporter/convertscri.cpp | 32 ++++++++++++++++ apps/essimporter/convertscri.hpp | 16 ++++++++ apps/essimporter/importer.cpp | 6 +++ apps/openmw/mwscript/locals.cpp | 63 +++++++++++++++++++++++++------- components/esm/locals.cpp | 6 +-- components/esm/variant.cpp | 26 ++++++++++++- components/esm/variant.hpp | 3 +- components/esm/variantimp.cpp | 33 +++++++++++++++-- 10 files changed, 167 insertions(+), 22 deletions(-) create mode 100644 apps/essimporter/convertscri.cpp create mode 100644 apps/essimporter/convertscri.hpp diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 5db3a86dc..409b8bcff 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -23,6 +23,7 @@ set(ESSIMPORTER_FILES convertinventory.cpp convertcrec.cpp convertcntc.cpp + convertscri.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 75c2911fd..3b82988b8 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -9,6 +9,7 @@ #include "convertcrec.hpp" #include "convertcntc.hpp" +#include "convertscri.hpp" namespace { @@ -29,6 +30,8 @@ namespace objstate.mRef.mRefNum = cellref.mRefNum; if (cellref.mDeleted) objstate.mCount = 0; + convertSCRI(cellref.mSCRI, objstate.mLocals); + objstate.mHasLocals = !objstate.mLocals.mVariables.empty(); } bool isIndexedRefId(const std::string& indexedRefId) diff --git a/apps/essimporter/convertscri.cpp b/apps/essimporter/convertscri.cpp new file mode 100644 index 000000000..dbe35a010 --- /dev/null +++ b/apps/essimporter/convertscri.cpp @@ -0,0 +1,32 @@ +#include "convertscri.hpp" + +#include + +namespace +{ + + template + void storeVariables(const std::vector& variables, ESM::Locals& locals, const std::string& scriptname) + { + for (typename std::vector::const_iterator it = variables.begin(); it != variables.end(); ++it) + { + ESM::Variant val(*it); + val.setType(VariantType); + locals.mVariables.push_back(std::make_pair(std::string(), val)); + } + } + +} + +namespace ESSImport +{ + + void convertSCRI(const SCRI &scri, ESM::Locals &locals) + { + // order *is* important, as we do not have variable names available in this format + storeVariables (scri.mShorts, locals, scri.mScript); + storeVariables (scri.mLongs, locals, scri.mScript); + storeVariables (scri.mFloats, locals, scri.mScript); + } + +} diff --git a/apps/essimporter/convertscri.hpp b/apps/essimporter/convertscri.hpp new file mode 100644 index 000000000..2d8945666 --- /dev/null +++ b/apps/essimporter/convertscri.hpp @@ -0,0 +1,16 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTSCRI_H +#define OPENMW_ESSIMPORT_CONVERTSCRI_H + +#include "importscri.hpp" + +#include + +namespace ESSImport +{ + + /// Convert script variable assignments + void convertSCRI (const SCRI& scri, ESM::Locals& locals); + +} + +#endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index ed149b023..73a12769a 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -237,6 +237,12 @@ namespace ESSImport converters[recJOUR ] = boost::shared_ptr(new ConvertJOUR()); converters[ESM::REC_SCPT] = boost::shared_ptr(new ConvertSCPT()); + // TODO: + // - REGN (weather in certain regions?) + // - VFXM + // - SPLM (active spell effects) + // - PROJ (magic projectiles in air) + std::set unknownRecords; for (std::map >::const_iterator it = converters.begin(); diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index a1ee48ae6..fe3e49827 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -10,6 +10,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" +#include + namespace MWScript { void Locals::configure (const ESM::Script& script) @@ -124,27 +126,60 @@ namespace MWScript const Compiler::Locals& declarations = MWBase::Environment::get().getScriptManager()->getLocals(script); - for (std::vector >::const_iterator iter - = locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter) + int index = 0, numshorts = 0, numlongs = 0; + for (unsigned int v=0; vfirst); - char index = declarations.getIndex (iter->first); + ESM::VarType type = locals.mVariables[v].second.getType(); + if (type == ESM::VT_Short) + ++numshorts; + else if (type == ESM::VT_Int) + ++numlongs; + } - try + for (std::vector >::const_iterator iter + = locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter,++index) + { + if (iter->first.empty()) { - switch (type) + // no variable names available (this will happen for legacy, i.e. ESS-imported savegames only) + try { - case 's': mShorts.at (index) = iter->second.getInteger(); break; - case 'l': mLongs.at (index) = iter->second.getInteger(); break; - case 'f': mFloats.at (index) = iter->second.getFloat(); break; - - // silently ignore locals that don't exist anymore + if (index >= numshorts+numlongs) + mFloats.at(index - (numshorts+numlongs)) = iter->second.getFloat(); + else if (index >= numshorts) + mLongs.at(index - numshorts) = iter->second.getInteger(); + else + mShorts.at(index) = iter->second.getInteger(); + } + catch (std::exception& e) + { + std::cerr << "Failed to read local variable state for script '" + << script << "' (legacy format): " << e.what() + << "\nNum shorts: " << numshorts << " / " << mShorts.size() + << " Num longs: " << numlongs << " / " << mLongs.size() << std::endl; } } - catch (...) + else { - // ignore type changes - /// \todo write to log + char type = declarations.getType (iter->first); + char index = declarations.getIndex (iter->first); + + try + { + switch (type) + { + case 's': mShorts.at (index) = iter->second.getInteger(); break; + case 'l': mLongs.at (index) = iter->second.getInteger(); break; + case 'f': mFloats.at (index) = iter->second.getFloat(); break; + + // silently ignore locals that don't exist anymore + } + } + catch (...) + { + // ignore type changes + /// \todo write to log + } } } } diff --git a/components/esm/locals.cpp b/components/esm/locals.cpp index 9c470a025..f0cfd49f0 100644 --- a/components/esm/locals.cpp +++ b/components/esm/locals.cpp @@ -11,7 +11,7 @@ void ESM::Locals::load (ESMReader &esm) std::string id = esm.getHString(); Variant value; - value.read (esm, Variant::Format_Info); + value.read (esm, Variant::Format_Local); mVariables.push_back (std::make_pair (id, value)); } @@ -23,6 +23,6 @@ void ESM::Locals::save (ESMWriter &esm) const iter!=mVariables.end(); ++iter) { esm.writeHNString ("LOCA", iter->first); - iter->second.write (esm, Variant::Format_Info); + iter->second.write (esm, Variant::Format_Local); } -} \ No newline at end of file +} diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index 4127a9d62..c65eed5e0 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -13,6 +13,7 @@ namespace const uint32_t STRV = ESM::FourCC<'S','T','R','V'>::value; const uint32_t INTV = ESM::FourCC<'I','N','T','V'>::value; const uint32_t FLTV = ESM::FourCC<'F','L','T','V'>::value; + const uint32_t STTV = ESM::FourCC<'S','T','T','V'>::value; } ESM::Variant::Variant() : mType (VT_None), mData (0) {} @@ -141,7 +142,7 @@ void ESM::Variant::read (ESMReader& esm, Format format) esm.fail ("invalid subrecord: " + name.toString()); } } - else // info + else if (format == Format_Info) { esm.getSubName(); NAME name = esm.retSubName(); @@ -157,6 +158,26 @@ void ESM::Variant::read (ESMReader& esm, Format format) else esm.fail ("invalid subrecord: " + name.toString()); } + else if (format == Format_Local) + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name==INTV) + { + type = VT_Int; + } + else if (name==FLTV) + { + type = VT_Float; + } + else if (name==STTV) + { + type = VT_Short; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } setType (type); @@ -179,6 +200,9 @@ void ESM::Variant::write (ESMWriter& esm, Format format) const if (format==Format_Info) throw std::runtime_error ("can not serialise variant of type none to info format"); + if (format==Format_Local) + throw std::runtime_error ("can not serialise variant of type none to local format"); + // nothing to do here for GMST format } else diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index d6c1a5489..5f179a7bd 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -33,7 +33,8 @@ namespace ESM { Format_Global, Format_Gmst, - Format_Info // also used for local variables in saved game files + Format_Info, + Format_Local // local script variables in save game files }; Variant(); diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index 1bacdc077..fd068fc19 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -81,6 +81,9 @@ void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarTy if (format==Variant::Format_Info) esm.fail ("info variables of type string not supported"); + if (format==Variant::Format_Local) + esm.fail ("local variables of type string not supported"); + // GMST mValue = esm.getHString(); } @@ -173,6 +176,21 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT esm.getHT (mValue); } + else if (format==Variant::Format_Local) + { + if (type==VT_Short) + { + short value; + esm.getHT(value); + mValue = value; + } + else if (type==VT_Int) + { + esm.getHT(mValue); + } + else + esm.fail("unsupported local variable integer type"); + } } void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, VarType type) const @@ -204,6 +222,15 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var esm.writeHNT ("INTV", mValue); } + else if (format==Variant::Format_Local) + { + if (type==VT_Short) + esm.writeHNT ("STTV", (short)mValue); + else if (type == VT_Int) + esm.writeHNT ("INTV", mValue); + else + throw std::runtime_error("unsupported local variable integer type"); + } } bool ESM::VariantIntegerData::isEqual (const VariantDataBase& value) const @@ -252,7 +279,7 @@ void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarTyp { esm.getHNT (mValue, "FLTV"); } - else if (format==Variant::Format_Gmst || format==Variant::Format_Info) + else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local) { esm.getHT (mValue); } @@ -268,7 +295,7 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy esm.writeHNString ("FNAM", "f"); esm.writeHNT ("FLTV", mValue); } - else if (format==Variant::Format_Gmst || format==Variant::Format_Info) + else if (format==Variant::Format_Gmst || format==Variant::Format_Info || format==Variant::Format_Local) { esm.writeHNT ("FLTV", mValue); } @@ -277,4 +304,4 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy bool ESM::VariantFloatData::isEqual (const VariantDataBase& value) const { return dynamic_cast (value).mValue==mValue; -} \ No newline at end of file +} From 72f7c2e555222120b870765758ab41e0ff29245c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 16:26:43 +0100 Subject: [PATCH 28/28] Move weather reset to clear() method --- apps/openmw/mwworld/weather.cpp | 18 ++++++++++-------- apps/openmw/mwworld/weather.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 1 + 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 6532c5969..a74c24768 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -770,14 +770,6 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) ESM::WeatherState state; state.load(reader); - // reset other temporary state, now that we loaded successfully - stopSounds(); // let's hope this never throws - mRegionOverrides.clear(); - mRegionMods.clear(); - mThunderFlash = 0.0; - mThunderChance = 0.0; - mThunderChanceNeeded = 50.0; - // swap in the loaded values now that we can't fail mHour = state.mHour; mWindSpeed = state.mWindSpeed; @@ -794,6 +786,16 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) return false; } +void WeatherManager::clear() +{ + stopSounds(); + mRegionOverrides.clear(); + mRegionMods.clear(); + mThunderFlash = 0.0; + mThunderChance = 0.0; + mThunderChanceNeeded = 50.0; +} + void WeatherManager::switchToNextWeather(bool instantly) { MWBase::World* world = MWBase::Environment::get().getWorld(); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 830b5c376..a2e668159 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -201,6 +201,8 @@ namespace MWWorld bool readRecord(ESM::ESMReader& reader, uint32_t type); + void clear(); + private: float mHour; float mWindSpeed; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ceac85bca..8bcfcb421 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -265,6 +265,7 @@ namespace MWWorld void World::clear() { + mWeatherManager->clear(); mRendering->clear(); mProjectileManager->clear();