mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-07 12:40:01 +00:00
Fix/workaround for Issue #3246
OpenMW save file assumes the presence of NPC/Creature data but the vanilla save file provides only the delta changes in most situations. The base data are not available without loading all the relevant dependency content files. Duplicating that code in the ESSImporter is not desirable. Ideally a flag should be set but that will mean a change in the save file format. For a minor change such as this doing so seems like an overkill. So a temporary workaround is introduced where the gold carried by the NPC/Creature is used as an indicator as the lack of ACDT data.
This commit is contained in:
parent
bd995817ee
commit
47a841d3b7
@ -2,6 +2,7 @@
|
||||
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <climits> // INT_MIN
|
||||
|
||||
#include <osgDB/WriteFile>
|
||||
|
||||
@ -369,6 +370,8 @@ namespace ESSImport
|
||||
// from the ESM with default values
|
||||
if (cellref.mHasACDT)
|
||||
convertACDT(cellref.mACDT, objstate.mCreatureStats);
|
||||
else
|
||||
objstate.mCreatureStats.mGoldPool = INT_MIN; // HACK: indicates no ACDT
|
||||
if (cellref.mHasACSC)
|
||||
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
||||
convertNpcData(cellref, objstate.mNpcStats);
|
||||
@ -410,6 +413,8 @@ namespace ESSImport
|
||||
// from the ESM with default values
|
||||
if (cellref.mHasACDT)
|
||||
convertACDT(cellref.mACDT, objstate.mCreatureStats);
|
||||
else
|
||||
objstate.mCreatureStats.mGoldPool = INT_MIN; // HACK: indicates no ACDT
|
||||
if (cellref.mHasACSC)
|
||||
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
||||
convertCREC(crecIt->second, objstate);
|
||||
|
@ -748,26 +748,35 @@ namespace MWClass
|
||||
if (!state.mHasCustomState)
|
||||
return;
|
||||
|
||||
const ESM::CreatureState& creatureState = state.asCreatureState();
|
||||
|
||||
if (state.mVersion > 0)
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
// Create a CustomData, but don't fill it from ESM records (not needed)
|
||||
std::unique_ptr<CreatureCustomData> data (new CreatureCustomData);
|
||||
|
||||
if (hasInventoryStore(ptr))
|
||||
data->mContainerStore = std::make_unique<MWWorld::InventoryStore>();
|
||||
// FIXME: the use of mGoldPool can be replaced with another flag the next time
|
||||
// the save file format is changed
|
||||
if (creatureState.mCreatureStats.mGoldPool == INT_MIN)
|
||||
ensureCustomData(ptr);
|
||||
else
|
||||
data->mContainerStore = std::make_unique<MWWorld::ContainerStore>();
|
||||
{
|
||||
// Create a CustomData, but don't fill it from ESM records (not needed)
|
||||
std::unique_ptr<CreatureCustomData> data (new CreatureCustomData);
|
||||
|
||||
ptr.getRefData().setCustomData (std::move(data));
|
||||
if (hasInventoryStore(ptr))
|
||||
data->mContainerStore = std::make_unique<MWWorld::InventoryStore>();
|
||||
else
|
||||
data->mContainerStore = std::make_unique<MWWorld::ContainerStore>();
|
||||
|
||||
ptr.getRefData().setCustomData (std::move(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless.
|
||||
|
||||
CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData();
|
||||
const ESM::CreatureState& creatureState = state.asCreatureState();
|
||||
|
||||
customData.mContainerStore->readState (creatureState.mInventory);
|
||||
bool spellsInitialised = customData.mCreatureStats.getSpells().setSpells(ptr.get<ESM::Creature>()->mBase->mId);
|
||||
if(spellsInitialised)
|
||||
|
@ -1291,19 +1291,26 @@ namespace MWClass
|
||||
if (!state.mHasCustomState)
|
||||
return;
|
||||
|
||||
const ESM::NpcState& npcState = state.asNpcState();
|
||||
|
||||
if (state.mVersion > 0)
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
// Create a CustomData, but don't fill it from ESM records (not needed)
|
||||
ptr.getRefData().setCustomData(std::make_unique<NpcCustomData>());
|
||||
// FIXME: the use of mGoldPool can be replaced with another flag the next time
|
||||
// the save file format is changed
|
||||
if (npcState.mCreatureStats.mGoldPool == INT_MIN)
|
||||
ensureCustomData(ptr);
|
||||
else
|
||||
// Create a CustomData, but don't fill it from ESM records (not needed)
|
||||
ptr.getRefData().setCustomData(std::make_unique<NpcCustomData>());
|
||||
}
|
||||
}
|
||||
else
|
||||
ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless.
|
||||
|
||||
NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
|
||||
const ESM::NpcState& npcState = state.asNpcState();
|
||||
|
||||
customData.mInventoryStore.readState (npcState.mInventory);
|
||||
customData.mNpcStats.readState (npcState.mNpcStats);
|
||||
bool spellsInitialised = customData.mNpcStats.getSpells().setSpells(ptr.get<ESM::NPC>()->mBase->mId);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "creaturestats.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
|
||||
#include <components/esm/creaturestats.hpp>
|
||||
#include <components/esm/esmreader.hpp>
|
||||
@ -562,22 +563,27 @@ namespace MWMechanics
|
||||
|
||||
void CreatureStats::readState (const ESM::CreatureStats& state)
|
||||
{
|
||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||
mAttributes[i].readState (state.mAttributes[i]);
|
||||
// HACK: using mGoldPool as an indicator for lack of ACDT during .ess import
|
||||
if (state.mGoldPool != INT_MIN)
|
||||
{
|
||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||
mAttributes[i].readState (state.mAttributes[i]);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
mDynamic[i].readState (state.mDynamic[i]);
|
||||
for (int i=0; i<3; ++i)
|
||||
mDynamic[i].readState (state.mDynamic[i]);
|
||||
|
||||
mGoldPool = state.mGoldPool;
|
||||
mTalkedTo = state.mTalkedTo;
|
||||
mAttacked = state.mAttacked;
|
||||
}
|
||||
|
||||
mLastRestock = MWWorld::TimeStamp(state.mTradeTime);
|
||||
mGoldPool = state.mGoldPool;
|
||||
|
||||
mDead = state.mDead;
|
||||
mDeathAnimationFinished = state.mDeathAnimationFinished;
|
||||
mDied = state.mDied;
|
||||
mMurdered = state.mMurdered;
|
||||
mTalkedTo = state.mTalkedTo;
|
||||
mAlarmed = state.mAlarmed;
|
||||
mAttacked = state.mAttacked;
|
||||
// TODO: rewrite. does this really need 3 separate bools?
|
||||
mKnockdown = state.mKnockdown;
|
||||
mKnockdownOneFrame = state.mKnockdownOneFrame;
|
||||
|
@ -70,6 +70,8 @@ namespace MWMechanics
|
||||
MWWorld::TimeStamp mLastRestock;
|
||||
|
||||
// The pool of merchant gold (not in inventory)
|
||||
// HACK: value of INT_MIN has a special meaning: indicates a converted .ess file
|
||||
// (this is a workaround to avoid changing the save file format)
|
||||
int mGoldPool;
|
||||
|
||||
int mActorId;
|
||||
|
Loading…
x
Reference in New Issue
Block a user