ESSImport: player is placed in correct cell, npc cellrefs work

openmw-35
scrawl 10 years ago
parent c8ed24cc84
commit 08ad4d73bb

@ -5,9 +5,11 @@ set(ESSIMPORTER_FILES
importnpcc.cpp
importcrec.cpp
importcellref.cpp
importacdt.hpp
importacdt.cpp
importercontext.cpp
converter.cpp
convertacdt.cpp
convertnpcc.cpp
)
add_executable(openmw-essimporter

@ -0,0 +1,42 @@
#include "convertacdt.hpp"
namespace ESSImport
{
int translateDynamicIndex(int mwIndex)
{
if (mwIndex == 1)
return 2;
else if (mwIndex == 2)
return 1;
return mwIndex;
}
void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats)
{
for (int i=0; i<3; ++i)
{
int writeIndex = translateDynamicIndex(i);
cStats.mDynamic[writeIndex].mBase = acdt.mDynamic[i][1];
cStats.mDynamic[writeIndex].mMod = acdt.mDynamic[i][1];
cStats.mDynamic[writeIndex].mCurrent = acdt.mDynamic[i][0];
}
for (int i=0; i<8; ++i)
{
cStats.mAttributes[i].mBase = acdt.mAttributes[i][1];
cStats.mAttributes[i].mMod = acdt.mAttributes[i][0];
cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0];
}
}
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats)
{
for (int i=0; i<ESM::Skill::Length; ++i)
{
npcStats.mSkills[i].mRegular.mMod = actorData.mSkills[i][1];
npcStats.mSkills[i].mRegular.mCurrent = actorData.mSkills[i][1];
npcStats.mSkills[i].mRegular.mBase = actorData.mSkills[i][0];
}
}
}

@ -0,0 +1,22 @@
#ifndef OPENMW_ESSIMPORT_CONVERTACDT_H
#define OPENMW_ESSIMPORT_CONVERTACDT_H
#include <components/esm/creaturestats.hpp>
#include <components/esm/npcstats.hpp>
#include <components/esm/loadskil.hpp>
#include "importacdt.hpp"
namespace ESSImport
{
// OpenMW uses Health,Magicka,Fatigue, MW uses Health,Fatigue,Magicka
int translateDynamicIndex(int mwIndex);
void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats);
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats);
}
#endif

@ -43,8 +43,15 @@ namespace ESSImport
{
ESM::Cell cell;
std::string id = esm.getHNString("NAME");
cell.mName = id;
cell.load(esm, false);
// note if the player is in a nameless exterior cell, we will assign the cellId later based on player position
if (id == mContext->mPlayerCellName)
{
mContext->mPlayer.mCellId = cell.getCellId();
}
Cell newcell;
newcell.mCell = cell;
@ -55,7 +62,12 @@ namespace ESSImport
unsigned char nam8[32];
if (esm.isNextSub("NAM8"))
{
esm.getHExact(nam8, 32);
esm.getSubHeader();
// FIXME: different size in interior cells for some reason
if (esm.getSubSize() == 36)
esm.skip(4);
esm.getExact(nam8, 32);
newcell.mFogOfWar.reserve(16*16);
for (int x=0; x<16; ++x)
@ -87,6 +99,8 @@ namespace ESSImport
}
newcell.mRefs = cellrefs;
// FIXME: map by ID for exterior cells
mCells[id] = newcell;
}
@ -127,20 +141,36 @@ namespace ESSImport
std::make_pair(refIndex, out.mRefID));
if (crecIt != mContext->mCreatureChanges.end())
{
std::cerr << "Can't' find CREC for " << refIndex << " " << out.mRefID << std::endl;
ESM::CreatureState objstate;
objstate.blank();
convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats);
objstate.mEnabled = cellref.mEnabled;
objstate.mPosition = cellref.mPos;
objstate.mRef = out;
objstate.mRef.mRefNum = cellref.mRefNum;
esm.writeHNT ("OBJE", ESM::REC_CREA);
objstate.save(esm);
continue;
}
std::map<std::pair<int, std::string>, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find(
std::make_pair(refIndex, out.mRefID));
if (npccIt != mContext->mNpcChanges.end())
{
ESM::NpcState objstate;
objstate.blank();
convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats);
convertNpcData(cellref.mActorData, objstate.mNpcStats);
objstate.mEnabled = cellref.mEnabled;
objstate.mPosition = cellref.mPos;
objstate.mRef = out;
objstate.mRef.mRefNum = cellref.mRefNum;
esm.writeHNT ("OBJE", ESM::REC_NPC_);
objstate.save(esm);
continue;
}
ESM::CreatureState objstate;
objstate.mCount = 1;
objstate.mEnabled = cellref.mEnabled;
objstate.mHasLocals = 0;
objstate.mLocalRotation[0] = objstate.mLocalRotation[1] = objstate.mLocalRotation[2] = 0;
objstate.mPosition = cellref.mPos;
objstate.mRef = out;
objstate.mRef.mRefNum = cellref.mRefNum;
esm.writeHNT ("OBJE", ESM::REC_CREA);
objstate.save(esm);
std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl;
}
esm.endRecord(ESM::REC_CSTA);

@ -14,6 +14,9 @@
#include "importercontext.hpp"
#include "importcellref.hpp"
#include "convertacdt.hpp"
#include "convertnpcc.hpp"
namespace ESSImport
{
@ -151,9 +154,10 @@ public:
npcc.load(esm);
if (id == "PlayerSaveGame")
{
mContext->mPlayer.mObject.mNpcStats.mReputation = npcc.mNPDT.mReputation;
convertNPCC(npcc, mContext->mPlayer.mObject);
}
//mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), crec));
else
mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), npcc));
}
};
@ -168,36 +172,10 @@ public:
mContext->mPlayer.mObject.mPosition = refr.mPos;
ESM::CreatureStats& cStats = mContext->mPlayer.mObject.mCreatureStats;
for (int i=0; i<3; ++i)
{
int writeIndex = translateDynamicIndex(i);
cStats.mDynamic[writeIndex].mBase = refr.mACDT.mDynamic[i][1];
cStats.mDynamic[writeIndex].mMod = refr.mACDT.mDynamic[i][1];
cStats.mDynamic[writeIndex].mCurrent = refr.mACDT.mDynamic[i][0];
}
for (int i=0; i<8; ++i)
{
cStats.mAttributes[i].mBase = refr.mACDT.mAttributes[i][1];
cStats.mAttributes[i].mMod = refr.mACDT.mAttributes[i][0];
cStats.mAttributes[i].mCurrent = refr.mACDT.mAttributes[i][0];
}
ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats;
for (int i=0; i<ESM::Skill::Length; ++i)
{
npcStats.mSkills[i].mRegular.mMod = refr.mSkills[i][1];
npcStats.mSkills[i].mRegular.mCurrent = refr.mSkills[i][1];
npcStats.mSkills[i].mRegular.mBase = refr.mSkills[i][0];
}
}
convertACDT(refr.mActorData.mACDT, cStats);
// OpenMW uses Health,Magicka,Fatigue, MW uses Health,Fatigue,Magicka
int translateDynamicIndex(int mwIndex)
{
if (mwIndex == 1)
return 2;
else if (mwIndex == 2)
return 1;
return mwIndex;
ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats;
convertNpcData(refr.mActorData, npcStats);
}
};

@ -0,0 +1,22 @@
#include "convertnpcc.hpp"
namespace ESSImport
{
void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState)
{
npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation;
for (std::vector<NPCC::InventoryItem>::const_iterator it = npcc.mInventory.begin();
it != npcc.mInventory.end(); ++it)
{
ESM::ObjectState obj;
obj.blank();
obj.mRef.mRefID = it->mId;
obj.mRef.mCharge = it->mCondition;
// Don't know type of object :( change save format?
// npcState.mInventory.mItems.push_back(std::make_pair(obj, std::make_pair(0,0)));
}
}
}

@ -0,0 +1,15 @@
#ifndef OPENMW_ESSIMPORT_CONVERTNPCC_H
#define OPENMW_ESSIMPORT_CONVERTNPCC_H
#include "importnpcc.hpp"
#include <components/esm/npcstate.hpp>
namespace ESSImport
{
void convertNPCC (const NPCC& npcc, ESM::NpcState& npcState);
}
#endif

@ -0,0 +1,28 @@
#include "importacdt.hpp"
#include <components/esm/esmreader.hpp>
namespace ESSImport
{
void ActorData::load(ESM::ESMReader &esm)
{
esm.getHNT(mACDT, "ACDT");
ACSC acsc;
esm.getHNOT(acsc, "ACSC");
esm.getHNOT(acsc, "ACSL");
if (esm.isNextSub("CHRD")) // npc only
esm.getHExact(mSkills, 27*2*sizeof(int));
if (esm.isNextSub("CRED")) // creature only
esm.getHExact(mCombatStats, 3*2*sizeof(int));
mScript = esm.getHNOString("SCRI");
if (esm.isNextSub("ND3D"))
esm.skipHSub();
}
}

@ -1,9 +1,17 @@
#ifndef OPENMW_ESSIMPORT_ACDT_H
#define OPENMW_ESSIMPORT_ACDT_H
#include <string>
namespace ESM
{
struct ESMReader;
}
namespace ESSImport
{
/// Actor data, shared by (at least) REFR and CellRef
struct ACDT
{
@ -14,6 +22,22 @@ namespace ESSImport
unsigned char mUnknown3[120];
};
struct ActorData
{
ACDT mACDT;
int mSkills[27][2];
// creature combat stats, base and modified
// I think these can be ignored in the conversion, because it is not possible
// to change them ingame
int mCombatStats[3][2];
std::string mScript;
void load(ESM::ESMReader& esm);
};
/// Unknown, shared by (at least) REFR and CellRef
struct ACSC
{

@ -16,22 +16,19 @@ namespace ESSImport
mIndexedRefId = esm.getHNString("NAME");
esm.getHNT(mACDT, "ACDT");
// the following two occur in ESM::CellRef too (Charge and Gold),
// but may have entirely different meanings here
int intv;
esm.getHNOT(intv, "INTV");
int nam9;
esm.getHNOT(nam9, "NAM9");
ACSC acsc;
esm.getHNOT(acsc, "ACSC");
esm.getHNOT(acsc, "ACSL");
if (esm.isNextSub("CRED"))
esm.skipHSub();
if (esm.isNextSub("ND3D"))
esm.skipHSub();
mActorData.load(esm);
mEnabled = true;
esm.getHNOT(mEnabled, "ZNAM");
esm.getHNOT(mPos, "DATA", 24);
esm.getHNT(mPos, "DATA", 24);
}
}

@ -21,10 +21,12 @@ namespace ESSImport
std::string mIndexedRefId;
ESM::RefNum mRefNum;
ACDT mACDT;
ActorData mActorData;
ESM::Position mPos;
std::string mScript;
bool mEnabled;
void load(ESM::ESMReader& esm);

@ -185,6 +185,9 @@ namespace ESSImport
Context context;
const ESM::Header& header = esm.getHeader();
context.mPlayerCellName = header.mGameData.mCurrentCell.toString();
const unsigned int recREFR = ESM::FourCC<'R','E','F','R'>::value;
const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value;
const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value;
@ -234,8 +237,6 @@ namespace ESSImport
}
}
const ESM::Header& header = esm.getHeader();
ESM::ESMWriter writer;
writer.setFormat (ESM::Header::CurrentFormat);
@ -247,6 +248,11 @@ namespace ESSImport
writer.setAuthor("");
writer.setDescription("");
writer.setRecordCount (0);
for (std::vector<ESM::Header::MasterData>::const_iterator it = header.mMaster.begin();
it != header.mMaster.end(); ++it)
writer.addMaster (it->name, 0); // not using the size information anyway -> use value of 0
writer.save (stream);
ESM::SavedGame profile;
@ -298,6 +304,15 @@ namespace ESSImport
}
writer.startRecord(ESM::REC_PLAY);
if (context.mPlayer.mCellId.mPaged)
{
// exterior cell -> determine cell coordinates based on position
const int cellSize = 8192;
int cellX = std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize);
int cellY = std::floor(context.mPlayer.mObject.mPosition.pos[1]/cellSize);
context.mPlayer.mCellId.mIndex.mX = cellX;
context.mPlayer.mCellId.mIndex.mY = cellY;
}
context.mPlayer.save(writer);
writer.endRecord(ESM::REC_PLAY);
}

@ -17,6 +17,9 @@ namespace ESSImport
struct Context
{
// set from the TES3 header
std::string mPlayerCellName;
ESM::Player mPlayer;
ESM::NPC mPlayerBase;
std::string mCustomPlayerClassName;
@ -38,33 +41,8 @@ namespace ESSImport
//mPlayer.mLastKnownExteriorPosition
mPlayer.mHasMark = 0; // TODO
mPlayer.mCurrentCrimeId = 0; // TODO
mPlayer.mObject.mCount = 1;
mPlayer.mObject.mEnabled = 1;
mPlayer.mObject.mHasLocals = false;
mPlayer.mObject.blank();
mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame
mPlayer.mObject.mCreatureStats.mHasAiSettings = true;
mPlayer.mObject.mCreatureStats.mDead = false;
mPlayer.mObject.mCreatureStats.mDied = false;
mPlayer.mObject.mCreatureStats.mKnockdown = false;
mPlayer.mObject.mCreatureStats.mKnockdownOneFrame = false;
mPlayer.mObject.mCreatureStats.mKnockdownOverOneFrame = false;
mPlayer.mObject.mCreatureStats.mHitRecovery = false;
mPlayer.mObject.mCreatureStats.mBlock = false;
mPlayer.mObject.mCreatureStats.mMovementFlags = 0;
mPlayer.mObject.mCreatureStats.mAttackStrength = 0.f;
mPlayer.mObject.mCreatureStats.mFallHeight = 0.f;
mPlayer.mObject.mCreatureStats.mRecalcDynamicStats = false;
mPlayer.mObject.mCreatureStats.mDrawState = 0;
mPlayer.mObject.mCreatureStats.mDeathAnimation = 0;
mPlayer.mObject.mNpcStats.mIsWerewolf = false;
mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20;
mPlayer.mObject.mNpcStats.mLevelProgress = 0;
mPlayer.mObject.mNpcStats.mDisposition = 0;
mPlayer.mObject.mNpcStats.mTimeToStartDrowning = 20;
mPlayer.mObject.mNpcStats.mReputation = 0;
mPlayer.mObject.mNpcStats.mCrimeId = -1;
mPlayer.mObject.mNpcStats.mWerewolfKills = 0;
mPlayer.mObject.mNpcStats.mProfit = 0;
}
};

@ -7,12 +7,29 @@ namespace ESSImport
void NPCC::load(ESM::ESMReader &esm)
{
mIndex = 0;
esm.getHNOT(mIndex, "INDX");
esm.getHNT(mNPDT, "NPDT");
// container:
// XIDX
// XHLT - condition
// WIDX - equipping?
while (esm.isNextSub("NPCO"))
{
InventoryItem item;
item.mId = esm.getHString();
if (esm.isNextSub("XIDX"))
esm.skipHSub();
item.mCondition = -1;
esm.getHNOT(item.mCondition, "XHLT");
mInventory.push_back(item);
}
while (esm.isNextSub("WIDX"))
{
// equipping?
esm.skipHSub();
}
}
}

@ -1,7 +1,6 @@
#ifndef OPENMW_ESSIMPORT_NPCC_H
#define OPENMW_ESSIMPORT_NPCC_H
#include <components/esm/loadnpc.hpp>
#include <components/esm/loadcont.hpp>
namespace ESM
@ -12,7 +11,7 @@ namespace ESM
namespace ESSImport
{
struct NPCC : public ESM::NPC
struct NPCC
{
struct NPDT
{
@ -21,6 +20,15 @@ namespace ESSImport
unsigned char unknown2[5];
} mNPDT;
struct InventoryItem
{
std::string mId;
int mCondition;
};
std::vector<InventoryItem> mInventory;
int mIndex;
void load(ESM::ESMReader &esm);
};

@ -14,16 +14,7 @@ namespace ESSImport
if (esm.isNextSub("STPR"))
esm.skipHSub(); // ESS TODO
esm.getHNT(mACDT, "ACDT");
ACSC acsc;
esm.getHNOT(acsc, "ACSC");
esm.getHNOT(acsc, "ACSL");
esm.getHNExact(mSkills, 27*2*sizeof(int), "CHRD");
if (esm.isNextSub("ND3D"))
esm.skipHSub(); // ESS TODO (1 byte)
mActorData.load(esm);
esm.getHNOT(mPos, "DATA", 24);
}
@ -45,6 +36,9 @@ namespace ESSImport
if (esm.isNextSub("ENAM"))
esm.skipHSub();
if (esm.isNextSub("LNAM"))
esm.skipHSub();
while (esm.isNextSub("FNAM"))
{
FNAM fnam;

@ -21,15 +21,12 @@ namespace ESSImport
/// Player-agnostic player data
struct REFR
{
ACDT mACDT;
ActorData mActorData;
std::string mRefID;
ESM::Position mPos;
ESM::RefNum mRefNum;
int mSkills[27][2];
float mAttributes[8][2];
void load(ESM::ESMReader& esm);
};

@ -17,4 +17,10 @@ void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const
mInventory.save (esm);
mCreatureStats.save (esm);
}
}
void ESM::CreatureState::blank()
{
ObjectState::blank();
mCreatureStats.blank();
}

@ -14,6 +14,9 @@ namespace ESM
InventoryState mInventory;
CreatureStats mCreatureStats;
/// Initialize to default state
void blank();
virtual void load (ESMReader &esm);
virtual void save (ESMWriter &esm, bool inInventory = false) const;
};

@ -218,6 +218,38 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
}
esm.writeHNT("AISE", mHasAiSettings);
for (int i=0; i<4; ++i)
mAiSettings[i].save(esm);
if (mHasAiSettings)
{
for (int i=0; i<4; ++i)
mAiSettings[i].save(esm);
}
}
void ESM::CreatureStats::blank()
{
mTradeTime.mHour = 0;
mTradeTime.mDay = 0;
mGoldPool = 0;
mActorId = 0;
mHasAiSettings = false;
mDead = false;
mDied = false;
mMurdered = false;
mFriendlyHits = 0;
mTalkedTo = false;
mAlarmed = false;
mAttacked = false;
mAttackingOrSpell = false;
mKnockdown = false;
mKnockdownOneFrame = false;
mKnockdownOverOneFrame = false;
mHitRecovery = false;
mBlock = false;
mMovementFlags = 0;
mAttackStrength = 0.f;
mFallHeight = 0.f;
mRecalcDynamicStats = false;
mDrawState = 0;
mDeathAnimation = 0;
mLevel = 1;
}

@ -66,6 +66,9 @@ namespace ESM
SpellState mSpells;
ActiveSpells mActiveSpells;
/// Initialize to default state
void blank();
void load (ESMReader &esm);
void save (ESMWriter &esm) const;
};

@ -21,4 +21,11 @@ void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const
mNpcStats.save (esm);
mCreatureStats.save (esm);
}
}
void ESM::NpcState::blank()
{
ObjectState::blank();
mNpcStats.blank();
mCreatureStats.blank();
}

@ -16,6 +16,9 @@ namespace ESM
NpcStats mNpcStats;
CreatureStats mCreatureStats;
/// Initialize to default state
void blank();
virtual void load (ESMReader &esm);
virtual void save (ESMWriter &esm, bool inInventory = false) const;
};

@ -150,3 +150,18 @@ void ESM::NpcStats::save (ESMWriter &esm) const
if (mCrimeId != -1)
esm.writeHNT ("CRID", mCrimeId);
}
void ESM::NpcStats::blank()
{
mIsWerewolf = false;
mDisposition = 0;
mBounty = 0;
mReputation = 0;
mWerewolfKills = 0;
mProfit = 0;
mLevelProgress = 0;
for (int i=0; i<8; ++i)
mSkillIncrease[i] = 0;
mTimeToStartDrowning = 20;
mCrimeId = -1;
}

@ -47,6 +47,9 @@ namespace ESM
float mTimeToStartDrowning;
int mCrimeId;
/// Initialize to default state
void blank();
void load (ESMReader &esm);
void save (ESMWriter &esm) const;
};

@ -48,4 +48,18 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const
}
}
ESM::ObjectState::~ObjectState() {}
void ESM::ObjectState::blank()
{
mRef.blank();
mHasLocals = 0;
mEnabled = false;
mCount = 1;
for (int i=0;i<3;++i)
{
mPosition.pos[i] = 0;
mPosition.rot[i] = 0;
mLocalRotation[i] = 0;
}
}
ESM::ObjectState::~ObjectState() {}

@ -29,8 +29,11 @@ namespace ESM
virtual void load (ESMReader &esm);
virtual void save (ESMWriter &esm, bool inInventory = false) const;
/// Initialize to default state
void blank();
virtual ~ObjectState();
};
}
#endif
#endif

Loading…
Cancel
Save