mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 03:45:32 +00:00
Merge remote-tracking branch 'scrawl/essimporter'
This commit is contained in:
commit
cd62dbc5b7
68 changed files with 843 additions and 452 deletions
51
README.md
51
README.md
|
@ -41,51 +41,58 @@ Command line options
|
|||
--version print version information and quit
|
||||
--data arg (=data) set data directories (later directories
|
||||
have higher priority)
|
||||
--data-local arg set local data directory (highest
|
||||
--data-local arg set local data directory (highest
|
||||
priority)
|
||||
--fallback-archive arg (=fallback-archive)
|
||||
set fallback BSA archives (later
|
||||
set fallback BSA archives (later
|
||||
archives have higher priority)
|
||||
--resources arg (=resources) set resources directory
|
||||
--start arg (=Beshara) set initial cell
|
||||
--content arg content file(s): esm/esp, or
|
||||
--start arg set initial cell
|
||||
--content arg content file(s): esm/esp, or
|
||||
omwgame/omwaddon
|
||||
--anim-verbose [=arg(=1)] (=0) output animation indices files
|
||||
--no-sound [=arg(=1)] (=0) disable all sounds
|
||||
--script-verbose [=arg(=1)] (=0) verbose script output
|
||||
--script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue
|
||||
scripts) at startup
|
||||
--script-console [=arg(=1)] (=0) enable console-only script
|
||||
--script-all-dialogue [=arg(=1)] (=0) compile all dialogue scripts at startup
|
||||
--script-console [=arg(=1)] (=0) enable console-only script
|
||||
functionality
|
||||
--script-run arg select a file containing a list of
|
||||
console commands that is executed on
|
||||
--script-run arg select a file containing a list of
|
||||
console commands that is executed on
|
||||
startup
|
||||
--script-warn [=arg(=1)] (=1) handling of warnings when compiling
|
||||
--script-warn [=arg(=1)] (=1) handling of warnings when compiling
|
||||
scripts
|
||||
0 - ignore warning
|
||||
1 - show warning but consider script as
|
||||
correctly compiled anyway
|
||||
2 - treat warnings as errors
|
||||
--script-blacklist arg ignore the specified script (if the use
|
||||
of the blacklist is enabled)
|
||||
--script-blacklist-use [=arg(=1)] (=1)
|
||||
enable script blacklisting
|
||||
--load-savegame arg load a save game file on game startup
|
||||
--skip-menu [=arg(=1)] (=0) skip main menu on game startup
|
||||
--new-game [=arg(=1)] (=0) run new game sequence (ignored if
|
||||
--new-game [=arg(=1)] (=0) run new game sequence (ignored if
|
||||
skip-menu=0)
|
||||
--fs-strict [=arg(=1)] (=0) strict file system handling (no case
|
||||
--fs-strict [=arg(=1)] (=0) strict file system handling (no case
|
||||
folding)
|
||||
--encoding arg (=win1252) Character encoding used in OpenMW game
|
||||
--encoding arg (=win1252) Character encoding used in OpenMW game
|
||||
messages:
|
||||
|
||||
win1250 - Central and Eastern European
|
||||
such as Polish, Czech, Slovak,
|
||||
Hungarian, Slovene, Bosnian, Croatian,
|
||||
Serbian (Latin script), Romanian and
|
||||
|
||||
win1250 - Central and Eastern European
|
||||
such as Polish, Czech, Slovak,
|
||||
Hungarian, Slovene, Bosnian, Croatian,
|
||||
Serbian (Latin script), Romanian and
|
||||
Albanian languages
|
||||
|
||||
win1251 - Cyrillic alphabet such as
|
||||
Russian, Bulgarian, Serbian Cyrillic
|
||||
|
||||
win1251 - Cyrillic alphabet such as
|
||||
Russian, Bulgarian, Serbian Cyrillic
|
||||
and other languages
|
||||
|
||||
win1252 - Western European (Latin)
|
||||
|
||||
win1252 - Western European (Latin)
|
||||
alphabet, used by default
|
||||
--fallback arg fallback values
|
||||
--no-grab Don't grab mouse cursor
|
||||
--export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG
|
||||
image and XML file in current directory
|
||||
--activate-dist arg (=-1) activation distance override
|
||||
|
|
|
@ -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<int>(ref.mReferenceBlocked) << "'" << std::endl;
|
||||
std::cout << " Deleted: " << deleted << std::endl;
|
||||
|
|
|
@ -8,10 +8,14 @@ set(ESSIMPORTER_FILES
|
|||
importacdt.cpp
|
||||
importinventory.cpp
|
||||
importklst.cpp
|
||||
importcntc.cpp
|
||||
importercontext.cpp
|
||||
converter.cpp
|
||||
convertacdt.cpp
|
||||
convertnpcc.cpp
|
||||
convertinventory.cpp
|
||||
convertcrec.cpp
|
||||
convertcntc.cpp
|
||||
)
|
||||
|
||||
add_executable(openmw-essimporter
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace ESSImport
|
|||
cStats.mAttributes[i].mMod = acdt.mAttributes[i][0];
|
||||
cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0];
|
||||
}
|
||||
cStats.mGoldPool = acdt.mGoldPool;
|
||||
cStats.mTalkedTo = acdt.mFlags & TalkedToPlayer;
|
||||
}
|
||||
|
||||
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats)
|
||||
|
@ -37,6 +39,8 @@ namespace ESSImport
|
|||
npcStats.mSkills[i].mRegular.mCurrent = actorData.mSkills[i][1];
|
||||
npcStats.mSkills[i].mRegular.mBase = actorData.mSkills[i][0];
|
||||
}
|
||||
|
||||
npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
13
apps/essimporter/convertcntc.cpp
Normal file
13
apps/essimporter/convertcntc.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "convertcntc.hpp"
|
||||
|
||||
#include "convertinventory.hpp"
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertCNTC(const CNTC &cntc, ESM::ContainerState &state)
|
||||
{
|
||||
convertInventory(cntc.mInventory, state.mInventory);
|
||||
}
|
||||
|
||||
}
|
15
apps/essimporter/convertcntc.hpp
Normal file
15
apps/essimporter/convertcntc.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef OPENMW_ESSIMPORT_CONVERTCNTC_H
|
||||
#define OPENMW_ESSIMPORT_CONVERTCNTC_H
|
||||
|
||||
#include "importcntc.hpp"
|
||||
|
||||
#include <components/esm/containerstate.hpp>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertCNTC(const CNTC& cntc, ESM::ContainerState& state);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
13
apps/essimporter/convertcrec.cpp
Normal file
13
apps/essimporter/convertcrec.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "convertcrec.hpp"
|
||||
|
||||
#include "convertinventory.hpp"
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertCREC(const CREC &crec, ESM::CreatureState &state)
|
||||
{
|
||||
convertInventory(crec.mInventory, state.mInventory);
|
||||
}
|
||||
|
||||
}
|
15
apps/essimporter/convertcrec.hpp
Normal file
15
apps/essimporter/convertcrec.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef OPENMW_ESSIMPORT_CONVERTCREC_H
|
||||
#define OPENMW_ESSIMPORT_CONVERTCREC_H
|
||||
|
||||
#include "importcrec.hpp"
|
||||
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertCREC(const CREC& crec, ESM::CreatureState& state);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,8 +1,14 @@
|
|||
#include "converter.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <OgreImage.h>
|
||||
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
#include <components/esm/containerstate.hpp>
|
||||
|
||||
#include "convertcrec.hpp"
|
||||
#include "convertcntc.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -15,6 +21,24 @@ namespace
|
|||
screenshot.save(out);
|
||||
}
|
||||
|
||||
|
||||
void convertCellRef(const ESSImport::CellRef& cellref, ESM::ObjectState& objstate)
|
||||
{
|
||||
objstate.mEnabled = cellref.mEnabled;
|
||||
objstate.mPosition = cellref.mPos;
|
||||
objstate.mRef.mRefNum = cellref.mRefNum;
|
||||
}
|
||||
|
||||
bool isIndexedRefId(const std::string& indexedRefId)
|
||||
{
|
||||
if (indexedRefId.size() <= 8)
|
||||
return false;
|
||||
|
||||
std::string index = indexedRefId.substr(indexedRefId.size()-8);
|
||||
if(index.find_first_not_of("0123456789ABCDEF") == std::string::npos )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ESSImport
|
||||
|
@ -114,8 +138,9 @@ namespace ESSImport
|
|||
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;
|
||||
//std::cout << "deleted ref " << ref.mIndexedRefId << std::endl;
|
||||
esm.skipHSub();
|
||||
}
|
||||
cellrefs.push_back(ref);
|
||||
|
@ -153,59 +178,58 @@ namespace ESSImport
|
|||
|
||||
newcell.mRefs = cellrefs;
|
||||
|
||||
// FIXME: map by ID for exterior cells
|
||||
mCells[id] = newcell;
|
||||
|
||||
if (cell.isExterior())
|
||||
mExtCells[std::make_pair(cell.mData.mX, cell.mData.mY)] = newcell;
|
||||
else
|
||||
mIntCells[id] = newcell;
|
||||
}
|
||||
|
||||
void ConvertCell::write(ESM::ESMWriter &esm)
|
||||
void ConvertCell::writeCell(const Cell &cell, ESM::ESMWriter& esm)
|
||||
{
|
||||
for (std::map<std::string, Cell>::const_iterator it = mCells.begin(); it != mCells.end(); ++it)
|
||||
ESM::Cell esmcell = cell.mCell;
|
||||
esm.startRecord(ESM::REC_CSTA);
|
||||
ESM::CellState csta;
|
||||
csta.mHasFogOfWar = 0;
|
||||
csta.mId = esmcell.getCellId();
|
||||
csta.mId.save(esm);
|
||||
// TODO csta.mLastRespawn;
|
||||
// shouldn't be needed if we respawn on global schedule like in original MW
|
||||
csta.mWaterLevel = esmcell.mWater;
|
||||
csta.save(esm);
|
||||
|
||||
for (std::vector<CellRef>::const_iterator refIt = cell.mRefs.begin(); refIt != cell.mRefs.end(); ++refIt)
|
||||
{
|
||||
const ESM::Cell& cell = it->second.mCell;
|
||||
esm.startRecord(ESM::REC_CSTA);
|
||||
ESM::CellState csta;
|
||||
csta.mHasFogOfWar = 0;
|
||||
csta.mId = cell.getCellId();
|
||||
csta.mId.save(esm);
|
||||
// TODO csta.mLastRespawn;
|
||||
// shouldn't be needed if we respawn on global schedule like in original MW
|
||||
csta.mWaterLevel = cell.mWater;
|
||||
csta.save(esm);
|
||||
const CellRef& cellref = *refIt;
|
||||
ESM::CellRef out;
|
||||
out.blank();
|
||||
|
||||
for (std::vector<CellRef>::const_iterator refIt = it->second.mRefs.begin(); refIt != it->second.mRefs.end(); ++refIt)
|
||||
if (!isIndexedRefId(cellref.mIndexedRefId))
|
||||
{
|
||||
const CellRef& cellref = *refIt;
|
||||
ESM::CellRef out;
|
||||
out.blank();
|
||||
// non-indexed RefNum, i.e. no CREC/NPCC/CNTC record associated with it
|
||||
// this could be any type of object really (even creatures/npcs too)
|
||||
out.mRefID = cellref.mIndexedRefId;
|
||||
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
|
||||
|
||||
if (cellref.mIndexedRefId.size() < 8)
|
||||
{
|
||||
std::cerr << "CellRef with no index?" << std::endl;
|
||||
continue;
|
||||
}
|
||||
ESM::ObjectState objstate;
|
||||
objstate.blank();
|
||||
objstate.mRef = out;
|
||||
objstate.mRef.mRefID = idLower;
|
||||
objstate.mHasCustomState = false;
|
||||
convertCellRef(cellref, objstate);
|
||||
esm.writeHNT ("OBJE", 0);
|
||||
objstate.save(esm);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8);
|
||||
stream << std::hex << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8);
|
||||
int refIndex;
|
||||
stream >> refIndex;
|
||||
|
||||
out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8);
|
||||
|
||||
std::map<std::pair<int, std::string>, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find(
|
||||
std::make_pair(refIndex, out.mRefID));
|
||||
if (crecIt != mContext->mCreatureChanges.end())
|
||||
{
|
||||
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;
|
||||
// FIXME: change save format to not require object type, instead look up it up using the RefId
|
||||
esm.writeHNT ("OBJE", ESM::REC_CREA);
|
||||
objstate.save(esm);
|
||||
continue;
|
||||
}
|
||||
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
|
||||
|
||||
std::map<std::pair<int, std::string>, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find(
|
||||
std::make_pair(refIndex, out.mRefID));
|
||||
|
@ -213,23 +237,69 @@ namespace ESSImport
|
|||
{
|
||||
ESM::NpcState objstate;
|
||||
objstate.blank();
|
||||
objstate.mRef = out;
|
||||
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);
|
||||
objstate.mEnabled = cellref.mEnabled;
|
||||
objstate.mPosition = cellref.mPos;
|
||||
objstate.mRef = out;
|
||||
objstate.mRef.mRefNum = cellref.mRefNum;
|
||||
convertNPCC(npccIt->second, objstate);
|
||||
convertCellRef(cellref, objstate);
|
||||
esm.writeHNT ("OBJE", ESM::REC_NPC_);
|
||||
objstate.save(esm);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cerr << "Can't find type for " << refIndex << " " << out.mRefID << std::endl;
|
||||
}
|
||||
std::map<std::pair<int, std::string>, CNTC>::const_iterator cntcIt = mContext->mContainerChanges.find(
|
||||
std::make_pair(refIndex, out.mRefID));
|
||||
if (cntcIt != mContext->mContainerChanges.end())
|
||||
{
|
||||
ESM::ContainerState objstate;
|
||||
objstate.blank();
|
||||
objstate.mRef = out;
|
||||
objstate.mRef.mRefID = idLower;
|
||||
convertCNTC(cntcIt->second, objstate);
|
||||
convertCellRef(cellref, objstate);
|
||||
esm.writeHNT ("OBJE", ESM::REC_CONT);
|
||||
objstate.save(esm);
|
||||
continue;
|
||||
}
|
||||
|
||||
esm.endRecord(ESM::REC_CSTA);
|
||||
std::map<std::pair<int, std::string>, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find(
|
||||
std::make_pair(refIndex, out.mRefID));
|
||||
if (crecIt != mContext->mCreatureChanges.end())
|
||||
{
|
||||
ESM::CreatureState objstate;
|
||||
objstate.blank();
|
||||
objstate.mRef = out;
|
||||
objstate.mRef.mRefID = idLower;
|
||||
convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats);
|
||||
// probably need more micromanagement here so we don't overwrite values
|
||||
// from the ESM with default values
|
||||
convertCREC(crecIt->second, objstate);
|
||||
convertCellRef(cellref, objstate);
|
||||
esm.writeHNT ("OBJE", ESM::REC_CREA);
|
||||
objstate.save(esm);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::stringstream error;
|
||||
error << "Can't find type for " << cellref.mIndexedRefId << std::endl;
|
||||
throw std::runtime_error(error.str());
|
||||
}
|
||||
}
|
||||
|
||||
esm.endRecord(ESM::REC_CSTA);
|
||||
}
|
||||
|
||||
void ConvertCell::write(ESM::ESMWriter &esm)
|
||||
{
|
||||
for (std::map<std::string, Cell>::const_iterator it = mIntCells.begin(); it != mIntCells.end(); ++it)
|
||||
writeCell(it->second, esm);
|
||||
|
||||
for (std::map<std::pair<int, int>, Cell>::const_iterator it = mExtCells.begin(); it != mExtCells.end(); ++it)
|
||||
writeCell(it->second, esm);
|
||||
|
||||
for (std::vector<ESM::CustomMarker>::const_iterator it = mMarkers.begin(); it != mMarkers.end(); ++it)
|
||||
{
|
||||
esm.startRecord(ESM::REC_MARK);
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
#include <components/esm/loadclas.hpp>
|
||||
#include <components/esm/loadglob.hpp>
|
||||
#include <components/esm/cellstate.hpp>
|
||||
#include <components/esm/loadfact.hpp>
|
||||
#include <components/esm/dialoguestate.hpp>
|
||||
#include <components/esm/custommarkerstate.hpp>
|
||||
|
||||
#include "importcrec.hpp"
|
||||
#include "importcntc.hpp"
|
||||
|
||||
#include "importercontext.hpp"
|
||||
#include "importcellref.hpp"
|
||||
|
@ -94,7 +97,8 @@ public:
|
|||
mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel;
|
||||
mContext->mPlayerBase = npc;
|
||||
std::map<const int, float> empty;
|
||||
// FIXME: not working?
|
||||
// FIXME: player start spells, racial spells and birthsign spells aren't listed here,
|
||||
// need to fix openmw to account for this
|
||||
for (std::vector<std::string>::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it)
|
||||
mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty;
|
||||
}
|
||||
|
@ -165,7 +169,10 @@ public:
|
|||
convertNPCC(npcc, mContext->mPlayer.mObject);
|
||||
}
|
||||
else
|
||||
mContext->mNpcChanges.insert(std::make_pair(std::make_pair(npcc.mIndex,id), npcc));
|
||||
{
|
||||
int index = npcc.mNPDT.mIndex;
|
||||
mContext->mNpcChanges.insert(std::make_pair(std::make_pair(index,id), npcc)).second;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -205,7 +212,27 @@ public:
|
|||
faction.mReputation = it->mReputation;
|
||||
mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction;
|
||||
}
|
||||
for (int i=0; i<8; ++i)
|
||||
mContext->mPlayer.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i];
|
||||
mContext->mPlayer.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();
|
||||
it != pcdt.mKnownDialogueTopics.end(); ++it)
|
||||
{
|
||||
mContext->mDialogueState.mKnownTopics.push_back(Misc::StringUtils::lowerCase(*it));
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class ConvertCNTC : public Converter
|
||||
{
|
||||
virtual void read(ESM::ESMReader &esm)
|
||||
{
|
||||
std::string id = esm.getHNString("NAME");
|
||||
CNTC cntc;
|
||||
cntc.load(esm);
|
||||
mContext->mContainerChanges.insert(std::make_pair(std::make_pair(cntc.mIndex,id), cntc));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -217,7 +244,6 @@ public:
|
|||
std::string id = esm.getHNString("NAME");
|
||||
CREC crec;
|
||||
crec.load(esm);
|
||||
|
||||
mContext->mCreatureChanges.insert(std::make_pair(std::make_pair(crec.mIndex,id), crec));
|
||||
}
|
||||
};
|
||||
|
@ -242,9 +268,12 @@ private:
|
|||
std::vector<unsigned int> mFogOfWar;
|
||||
};
|
||||
|
||||
std::map<std::string, Cell> mCells;
|
||||
std::map<std::string, Cell> mIntCells;
|
||||
std::map<std::pair<int, int>, Cell> mExtCells;
|
||||
|
||||
std::vector<ESM::CustomMarker> mMarkers;
|
||||
|
||||
void writeCell(const Cell& cell, ESM::ESMWriter &esm);
|
||||
};
|
||||
|
||||
class ConvertKLST : public Converter
|
||||
|
@ -274,6 +303,48 @@ private:
|
|||
std::map<std::string, int> mKillCounter;
|
||||
};
|
||||
|
||||
class ConvertFACT : public Converter
|
||||
{
|
||||
public:
|
||||
virtual void read(ESM::ESMReader& esm)
|
||||
{
|
||||
std::string id = esm.getHNString("NAME");
|
||||
ESM::Faction faction;
|
||||
faction.load(esm);
|
||||
|
||||
Misc::StringUtils::toLower(id);
|
||||
for (std::map<std::string, int>::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it)
|
||||
{
|
||||
std::string faction2 = Misc::StringUtils::lowerCase(it->first);
|
||||
mContext->mDialogueState.mChangedFactionReaction[id].insert(std::make_pair(faction2, it->second));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Stolen items
|
||||
class ConvertSTLN : public Converter
|
||||
{
|
||||
public:
|
||||
virtual void read(ESM::ESMReader &esm)
|
||||
{
|
||||
std::string itemid = esm.getHNString("NAME");
|
||||
|
||||
while (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));
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::multimap<std::string, std::string> mStolenItems;
|
||||
std::multimap<std::string, std::string> mFactionStolenItems;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
23
apps/essimporter/convertinventory.cpp
Normal file
23
apps/essimporter/convertinventory.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "convertinventory.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertInventory(const Inventory &inventory, ESM::InventoryState &state)
|
||||
{
|
||||
for (std::vector<Inventory::InventoryItem>::const_iterator it = inventory.mItems.begin();
|
||||
it != inventory.mItems.end(); ++it)
|
||||
{
|
||||
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
|
||||
state.mItems.push_back(std::make_pair(objstate, it->mRelativeEquipmentSlot));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
15
apps/essimporter/convertinventory.hpp
Normal file
15
apps/essimporter/convertinventory.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef OPENMW_ESSIMPORT_CONVERTINVENTORY_H
|
||||
#define OPENMW_ESSIMPORT_CONVERTINVENTORY_H
|
||||
|
||||
#include "importinventory.hpp"
|
||||
|
||||
#include <components/esm/inventorystate.hpp>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertInventory (const Inventory& inventory, ESM::InventoryState& state);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,10 +1,15 @@
|
|||
#include "convertnpcc.hpp"
|
||||
|
||||
#include "convertinventory.hpp"
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertNPCC(const NPCC &npcc, ESM::NpcState &npcState)
|
||||
{
|
||||
npcState.mNpcStats.mDisposition = npcc.mNPDT.mDisposition;
|
||||
npcState.mNpcStats.mReputation = npcc.mNPDT.mReputation;
|
||||
|
||||
convertInventory(npcc.mInventory, npcState.mInventory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace ESSImport
|
|||
ESM::CellRef bla;
|
||||
bla.ESM::CellRef::loadData(esm);
|
||||
|
||||
// FIXME: actually should be required for all actors?, but ActorData is currently in base CellRef
|
||||
// FIXME: not all actors have this, add flag
|
||||
esm.getHNOT(mACDT, "ACDT");
|
||||
|
||||
ACSC acsc;
|
||||
|
@ -76,6 +76,7 @@ namespace ESSImport
|
|||
esm.skipHSub(); // 4 byte, 0
|
||||
}
|
||||
|
||||
// FIXME: not all actors have this, add flag
|
||||
if (esm.isNextSub("CHRD")) // npc only
|
||||
esm.getHExact(mSkills, 27*2*sizeof(int));
|
||||
|
||||
|
|
|
@ -11,16 +11,31 @@ namespace ESM
|
|||
namespace ESSImport
|
||||
{
|
||||
|
||||
enum ACDTFlags
|
||||
{
|
||||
TalkedToPlayer = 0x4
|
||||
};
|
||||
|
||||
/// Actor data, shared by (at least) REFR and CellRef
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct ACDT
|
||||
{
|
||||
unsigned char mUnknown1[40];
|
||||
// Note, not stored at *all*:
|
||||
// - Level changes are lost on reload, except for the player (there it's in the NPC record).
|
||||
unsigned char mUnknown[12];
|
||||
unsigned char mFlags; // ACDTFlags
|
||||
unsigned char mUnknown1[3];
|
||||
float mBreathMeter; // Seconds left before drowning
|
||||
unsigned char mUnknown2[20];
|
||||
float mDynamic[3][2];
|
||||
unsigned char mUnknown2[16];
|
||||
unsigned char mUnknown3[16];
|
||||
float mAttributes[8][2];
|
||||
unsigned char mUnknown3[120];
|
||||
unsigned char mUnknown4[112];
|
||||
unsigned int mGoldPool;
|
||||
unsigned char mUnknown5[4];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct ActorData
|
||||
{
|
||||
|
|
|
@ -18,8 +18,13 @@ namespace ESSImport
|
|||
mIndexedRefId = esm.getHNString("NAME");
|
||||
|
||||
if (esm.isNextSub("LVCR"))
|
||||
esm.skipHSub();
|
||||
|
||||
{
|
||||
// occurs on leveled creature spawner references
|
||||
// probably some identifier for the the creature that has been spawned?
|
||||
unsigned char lvcr;
|
||||
esm.getHT(lvcr);
|
||||
//std::cout << "LVCR: " << (int)lvcr << std::endl;
|
||||
}
|
||||
mActorData.load(esm);
|
||||
|
||||
mEnabled = true;
|
||||
|
|
16
apps/essimporter/importcntc.cpp
Normal file
16
apps/essimporter/importcntc.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "importcntc.hpp"
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void CNTC::load(ESM::ESMReader &esm)
|
||||
{
|
||||
mIndex = 0;
|
||||
esm.getHNT(mIndex, "INDX");
|
||||
|
||||
mInventory.load(esm);
|
||||
}
|
||||
|
||||
}
|
25
apps/essimporter/importcntc.hpp
Normal file
25
apps/essimporter/importcntc.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef OPENMW_ESSIMPORT_IMPORTCNTC_H
|
||||
#define OPENMW_ESSIMPORT_IMPORTCNTC_H
|
||||
|
||||
#include "importinventory.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
}
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
/// Changed container contents
|
||||
struct CNTC
|
||||
{
|
||||
int mIndex;
|
||||
|
||||
Inventory mInventory;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
|
@ -104,6 +104,11 @@ namespace ESSImport
|
|||
blacklist.insert(std::make_pair("GLOB", "FLTV")); // gamehour
|
||||
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
|
||||
|
||||
// this changes way too often, name suggests some renderer internal data?
|
||||
blacklist.insert(std::make_pair("CELL", "ND3D"));
|
||||
blacklist.insert(std::make_pair("REFR", "ND3D"));
|
||||
|
||||
File file1;
|
||||
read(mEssFile, file1);
|
||||
|
@ -181,6 +186,8 @@ namespace ESSImport
|
|||
Ogre::LogManager logman;
|
||||
Ogre::Root root;
|
||||
|
||||
// TODO: set up encoding on ESMReader based on openmw.cfg / --encoding switch
|
||||
|
||||
ESM::ESMReader esm;
|
||||
esm.open(mEssFile);
|
||||
|
||||
|
@ -193,6 +200,7 @@ namespace ESSImport
|
|||
const unsigned int recPCDT = ESM::FourCC<'P','C','D','T'>::value;
|
||||
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;
|
||||
|
||||
std::map<unsigned int, boost::shared_ptr<Converter> > converters;
|
||||
converters[ESM::REC_GLOB] = boost::shared_ptr<Converter>(new ConvertGlobal());
|
||||
|
@ -200,10 +208,11 @@ namespace ESSImport
|
|||
converters[ESM::REC_NPC_] = boost::shared_ptr<Converter>(new ConvertNPC());
|
||||
converters[ESM::REC_NPCC] = boost::shared_ptr<Converter>(new ConvertNPCC());
|
||||
converters[ESM::REC_CREC] = boost::shared_ptr<Converter>(new ConvertCREC());
|
||||
converters[recREFR] = boost::shared_ptr<Converter>(new ConvertREFR());
|
||||
converters[recPCDT] = boost::shared_ptr<Converter>(new ConvertPCDT());
|
||||
converters[recFMAP] = boost::shared_ptr<Converter>(new ConvertFMAP());
|
||||
converters[recKLST] = boost::shared_ptr<Converter>(new ConvertKLST());
|
||||
converters[recREFR ] = boost::shared_ptr<Converter>(new ConvertREFR());
|
||||
converters[recPCDT ] = boost::shared_ptr<Converter>(new ConvertPCDT());
|
||||
converters[recFMAP ] = boost::shared_ptr<Converter>(new ConvertFMAP());
|
||||
converters[recKLST ] = boost::shared_ptr<Converter>(new ConvertKLST());
|
||||
converters[recSTLN ] = boost::shared_ptr<Converter>(new ConvertSTLN());
|
||||
converters[ESM::REC_CELL] = boost::shared_ptr<Converter>(new ConvertCell());
|
||||
converters[ESM::REC_ALCH] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::Potion>());
|
||||
converters[ESM::REC_CLAS] = boost::shared_ptr<Converter>(new ConvertClass());
|
||||
|
@ -215,6 +224,8 @@ namespace ESSImport
|
|||
converters[ESM::REC_WEAP] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::Weapon>());
|
||||
converters[ESM::REC_LEVC] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::CreatureLevList>());
|
||||
converters[ESM::REC_LEVI] = boost::shared_ptr<Converter>(new DefaultConverter<ESM::ItemLevList>());
|
||||
converters[ESM::REC_CNTC] = boost::shared_ptr<Converter>(new ConvertCNTC());
|
||||
converters[ESM::REC_FACT] = boost::shared_ptr<Converter>(new ConvertFACT());
|
||||
|
||||
std::set<unsigned int> unknownRecords;
|
||||
|
||||
|
@ -321,6 +332,10 @@ namespace ESSImport
|
|||
}
|
||||
context.mPlayer.save(writer);
|
||||
writer.endRecord(ESM::REC_PLAY);
|
||||
|
||||
writer.startRecord (ESM::REC_DIAS);
|
||||
context.mDialogueState.save(writer);
|
||||
writer.endRecord(ESM::REC_DIAS);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
#include <components/esm/player.hpp>
|
||||
#include <components/esm/dialoguestate.hpp>
|
||||
|
||||
#include "importnpcc.hpp"
|
||||
#include "importcrec.hpp"
|
||||
#include "importcntc.hpp"
|
||||
#include "importplayer.hpp"
|
||||
|
||||
|
||||
|
@ -24,12 +26,15 @@ namespace ESSImport
|
|||
ESM::NPC mPlayerBase;
|
||||
std::string mCustomPlayerClassName;
|
||||
|
||||
ESM::DialogueState mDialogueState;
|
||||
|
||||
int mDay, mMonth, mYear;
|
||||
float mHour;
|
||||
|
||||
// key <refIndex, refId>
|
||||
std::map<std::pair<int, std::string>, CREC> mCreatureChanges;
|
||||
std::map<std::pair<int, std::string>, NPCC> mNpcChanges;
|
||||
std::map<std::pair<int, std::string>, CNTC> mContainerChanges;
|
||||
|
||||
Context()
|
||||
{
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#include "importinventory.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
#include <components/esm/loadcont.hpp>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
|
@ -9,37 +13,66 @@ namespace ESSImport
|
|||
{
|
||||
while (esm.isNextSub("NPCO"))
|
||||
{
|
||||
ESM::ContItem contItem;
|
||||
esm.getHT(contItem);
|
||||
|
||||
InventoryItem item;
|
||||
item.mId = esm.getHString();
|
||||
item.mId = contItem.mItem.toString();
|
||||
item.mCount = contItem.mCount;
|
||||
item.mRelativeEquipmentSlot = -1;
|
||||
|
||||
if (esm.isNextSub("XIDX"))
|
||||
esm.skipHSub();
|
||||
|
||||
std::string script = esm.getHNOString("SCRI");
|
||||
// script variables?
|
||||
// unsure if before or after ESM::CellRef
|
||||
if (!script.empty())
|
||||
// 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?
|
||||
// I guess we should double check the stacking logic in OpenMW
|
||||
for (int i=0;i<std::abs(item.mCount);++i)
|
||||
{
|
||||
if (esm.isNextSub("SLCS"))
|
||||
esm.skipHSub();
|
||||
if (esm.isNextSub("SLSD")) // Short Data?
|
||||
esm.skipHSub();
|
||||
if (esm.isNextSub("SLFD")) // Float Data?
|
||||
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();
|
||||
}
|
||||
|
||||
// for XSOL and XCHG seen so far, but probably others too
|
||||
item.ESM::CellRef::loadData(esm);
|
||||
|
||||
int charge=-1;
|
||||
esm.getHNOT(charge, "XHLT");
|
||||
item.mChargeInt = charge;
|
||||
}
|
||||
|
||||
// for XSOL and XCHG seen so far, but probably others too
|
||||
item.ESM::CellRef::loadData(esm);
|
||||
|
||||
item.mCondition = -1;
|
||||
esm.getHNOT(item.mCondition, "XHLT");
|
||||
mItems.push_back(item);
|
||||
}
|
||||
|
||||
// equipped items
|
||||
while (esm.isNextSub("WIDX"))
|
||||
{
|
||||
// equipping?
|
||||
esm.skipHSub();
|
||||
// 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
|
||||
int slotIndex;
|
||||
esm.getT(slotIndex);
|
||||
|
||||
mItems[itemIndex].mRelativeEquipmentSlot = slotIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ namespace ESSImport
|
|||
struct InventoryItem : public ESM::CellRef
|
||||
{
|
||||
std::string mId;
|
||||
int mCondition;
|
||||
int mCount;
|
||||
int mRelativeEquipmentSlot;
|
||||
};
|
||||
std::vector<InventoryItem> mItems;
|
||||
|
||||
|
|
|
@ -7,9 +7,6 @@ namespace ESSImport
|
|||
|
||||
void NPCC::load(ESM::ESMReader &esm)
|
||||
{
|
||||
mIndex = 0;
|
||||
esm.getHNOT(mIndex, "INDX");
|
||||
|
||||
esm.getHNT(mNPDT, "NPDT");
|
||||
|
||||
if (esm.isNextSub("AI_E"))
|
||||
|
|
|
@ -19,15 +19,15 @@ namespace ESSImport
|
|||
{
|
||||
struct NPDT
|
||||
{
|
||||
unsigned char unknown[2];
|
||||
unsigned char mDisposition;
|
||||
unsigned char unknown;
|
||||
unsigned char mReputation;
|
||||
unsigned char unknown2[5];
|
||||
unsigned char unknown2;
|
||||
int mIndex;
|
||||
} mNPDT;
|
||||
|
||||
Inventory mInventory;
|
||||
|
||||
int mIndex;
|
||||
|
||||
void load(ESM::ESMReader &esm);
|
||||
};
|
||||
|
||||
|
|
|
@ -20,12 +20,11 @@ namespace ESSImport
|
|||
{
|
||||
while (esm.isNextSub("DNAM"))
|
||||
{
|
||||
// TODO: deal with encoding?
|
||||
mKnownDialogueTopics.push_back(esm.getHString());
|
||||
}
|
||||
|
||||
if (esm.isNextSub("PNAM"))
|
||||
esm.skipHSub();
|
||||
esm.getHNT(mPNAM, "PNAM");
|
||||
|
||||
if (esm.isNextSub("SNAM"))
|
||||
esm.skipHSub();
|
||||
if (esm.isNextSub("NAM9"))
|
||||
|
|
|
@ -38,6 +38,8 @@ struct PCDT
|
|||
|
||||
std::vector<std::string> mKnownDialogueTopics;
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct FNAM
|
||||
{
|
||||
unsigned char mRank;
|
||||
|
@ -47,7 +49,18 @@ struct PCDT
|
|||
unsigned char mUnknown2[3];
|
||||
ESM::NAME32 mFactionName;
|
||||
};
|
||||
struct PNAM
|
||||
{
|
||||
unsigned char mUnknown1[4];
|
||||
unsigned char mLevelProgress;
|
||||
unsigned char mUnknown2[111];
|
||||
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
||||
unsigned char mUnknown3[88];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<FNAM> mFactions;
|
||||
PNAM mPNAM;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
|
|
@ -1053,13 +1053,13 @@ namespace CSMWorld
|
|||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return record.get().mCharge;
|
||||
return record.get().mChargeInt;
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
record2.mCharge = data.toInt();
|
||||
record2.mChargeInt = data.toInt();
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ namespace MWBase
|
|||
/// Changes faction1's opinion of faction2 by \a diff.
|
||||
virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0;
|
||||
|
||||
virtual void setFactionReaction (const std::string& faction1, const std::string& faction2, int absolute) = 0;
|
||||
|
||||
/// @return faction1's opinion of faction2
|
||||
virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const = 0;
|
||||
|
||||
|
|
|
@ -816,6 +816,9 @@ namespace MWClass
|
|||
void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
if (!state.mHasCustomState)
|
||||
return;
|
||||
|
||||
const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state);
|
||||
|
||||
ensureCustomData(ptr);
|
||||
|
@ -844,7 +847,6 @@ namespace MWClass
|
|||
|
||||
customData.mContainerStore->readState (state2.mInventory);
|
||||
customData.mCreatureStats.readState (state2.mCreatureStats);
|
||||
|
||||
}
|
||||
|
||||
void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
|
@ -852,6 +854,12 @@ namespace MWClass
|
|||
{
|
||||
ESM::CreatureState& state2 = dynamic_cast<ESM::CreatureState&> (state);
|
||||
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
state.mHasCustomState = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
CreatureCustomData& customData = dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "light.hpp"
|
||||
|
||||
#include <components/esm/loadligh.hpp>
|
||||
#include <components/esm/lightstate.hpp>
|
||||
#include <components/esm/objectstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -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<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||
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<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
timeRemaining = duration;
|
||||
ptr.getCellRef().setChargeFloat(duration);
|
||||
}
|
||||
|
||||
float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ensureCustomData(ptr);
|
||||
|
||||
return dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||
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<ESM::Light>().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,26 +254,6 @@ namespace MWClass
|
|||
return std::make_pair(1,"");
|
||||
}
|
||||
|
||||
void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::LightState& state2 = dynamic_cast<const ESM::LightState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime = state2.mTime;
|
||||
}
|
||||
|
||||
void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::LightState& state2 = dynamic_cast<ESM::LightState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
state2.mTime = dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
}
|
||||
|
||||
std::string Light::getSound(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
return ptr.get<ESM::Light>()->mBase->mSound;
|
||||
|
|
|
@ -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<int, std::string> 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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1275,6 +1275,9 @@ namespace MWClass
|
|||
void Npc::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
if (!state.mHasCustomState)
|
||||
return;
|
||||
|
||||
const ESM::NpcState& state2 = dynamic_cast<const ESM::NpcState&> (state);
|
||||
|
||||
ensureCustomData(ptr);
|
||||
|
@ -1302,6 +1305,12 @@ namespace MWClass
|
|||
{
|
||||
ESM::NpcState& state2 = dynamic_cast<ESM::NpcState&> (state);
|
||||
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
state.mHasCustomState = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
NpcCustomData& customData = dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData());
|
||||
|
|
|
@ -640,7 +640,7 @@ namespace MWDialogue
|
|||
if (iter->second)
|
||||
state.mKnownTopics.push_back (iter->first);
|
||||
|
||||
state.mModFactionReaction = mModFactionReaction;
|
||||
state.mChangedFactionReaction = mChangedFactionReaction;
|
||||
|
||||
writer.startRecord (ESM::REC_DIAS);
|
||||
state.save (writer);
|
||||
|
@ -661,7 +661,7 @@ namespace MWDialogue
|
|||
if (store.get<ESM::Dialogue>().search (*iter))
|
||||
mKnownTopics.insert (std::make_pair (*iter, true));
|
||||
|
||||
mModFactionReaction = state.mModFactionReaction;
|
||||
mChangedFactionReaction = state.mChangedFactionReaction;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -674,10 +674,23 @@ namespace MWDialogue
|
|||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(fact1);
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(fact2);
|
||||
|
||||
std::map<std::string, int>& map = mModFactionReaction[fact1];
|
||||
if (map.find(fact2) == map.end())
|
||||
map[fact2] = 0;
|
||||
map[fact2] += diff;
|
||||
int newValue = getFactionReaction(faction1, faction2) + diff;
|
||||
|
||||
std::map<std::string, int>& map = mChangedFactionReaction[fact1];
|
||||
map[fact2] = newValue;
|
||||
}
|
||||
|
||||
void DialogueManager::setFactionReaction(const std::string &faction1, const std::string &faction2, int absolute)
|
||||
{
|
||||
std::string fact1 = Misc::StringUtils::lowerCase(faction1);
|
||||
std::string fact2 = Misc::StringUtils::lowerCase(faction2);
|
||||
|
||||
// Make sure the factions exist
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(fact1);
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(fact2);
|
||||
|
||||
std::map<std::string, int>& map = mChangedFactionReaction[fact1];
|
||||
map[fact2] = absolute;
|
||||
}
|
||||
|
||||
int DialogueManager::getFactionReaction(const std::string &faction1, const std::string &faction2) const
|
||||
|
@ -685,10 +698,9 @@ namespace MWDialogue
|
|||
std::string fact1 = Misc::StringUtils::lowerCase(faction1);
|
||||
std::string fact2 = Misc::StringUtils::lowerCase(faction2);
|
||||
|
||||
ModFactionReactionMap::const_iterator map = mModFactionReaction.find(fact1);
|
||||
int diff = 0;
|
||||
if (map != mModFactionReaction.end() && map->second.find(fact2) != map->second.end())
|
||||
diff = map->second.at(fact2);
|
||||
ModFactionReactionMap::const_iterator map = mChangedFactionReaction.find(fact1);
|
||||
if (map != mChangedFactionReaction.end() && map->second.find(fact2) != map->second.end())
|
||||
return map->second.at(fact2);
|
||||
|
||||
const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(fact1);
|
||||
|
||||
|
@ -696,9 +708,9 @@ namespace MWDialogue
|
|||
for (; it != faction->mReactions.end(); ++it)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(it->first, fact2))
|
||||
return it->second + diff;
|
||||
return it->second;
|
||||
}
|
||||
return diff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DialogueManager::clearInfoActor(const MWWorld::Ptr &actor) const
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace MWDialogue
|
|||
|
||||
// Modified faction reactions. <Faction1, <Faction2, Difference> >
|
||||
typedef std::map<std::string, std::map<std::string, int> > ModFactionReactionMap;
|
||||
ModFactionReactionMap mModFactionReaction;
|
||||
ModFactionReactionMap mChangedFactionReaction;
|
||||
|
||||
std::list<std::string> mActorKnownTopics;
|
||||
|
||||
|
@ -97,6 +97,8 @@ namespace MWDialogue
|
|||
/// Changes faction1's opinion of faction2 by \a diff.
|
||||
virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff);
|
||||
|
||||
virtual void setFactionReaction (const std::string& faction1, const std::string& faction2, int absolute);
|
||||
|
||||
/// @return faction1's opinion of faction2
|
||||
virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const;
|
||||
|
||||
|
|
|
@ -22,27 +22,27 @@ namespace MWMechanics
|
|||
|
||||
class NpcStats : public CreatureStats
|
||||
{
|
||||
int mDisposition;
|
||||
SkillValue mSkill[ESM::Skill::Length];
|
||||
SkillValue mWerewolfSkill[ESM::Skill::Length];
|
||||
int mReputation;
|
||||
int mCrimeId;
|
||||
|
||||
int mProfit;
|
||||
|
||||
// ----- used by the player only, maybe should be moved at some point -------
|
||||
int mBounty;
|
||||
int mWerewolfKills;
|
||||
/// NPCs other than the player can only have one faction. But for the sake of consistency
|
||||
/// we use the same data structure for the PC and the NPCs.
|
||||
/// \note the faction key must be in lowercase
|
||||
std::map<std::string, int> mFactionRank;
|
||||
|
||||
int mDisposition;
|
||||
SkillValue mSkill[ESM::Skill::Length];
|
||||
SkillValue mWerewolfSkill[ESM::Skill::Length];
|
||||
int mBounty;
|
||||
std::set<std::string> mExpelled;
|
||||
std::map<std::string, int> mFactionReputation;
|
||||
int mReputation;
|
||||
int mCrimeId;
|
||||
int mWerewolfKills;
|
||||
int mProfit;
|
||||
|
||||
int mLevelProgress; // 0-10
|
||||
|
||||
std::vector<int> mSkillIncreases; // number of skill increases for each attribute
|
||||
|
||||
std::set<std::string> mUsedIds;
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Countdown to getting damage while underwater
|
||||
float mTimeToStartDrowning;
|
||||
|
|
|
@ -236,6 +236,25 @@ namespace MWScript
|
|||
}
|
||||
};
|
||||
|
||||
class OpSetFactionReaction : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
std::string faction1 = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
std::string faction2 = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
int newValue = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
MWBase::Environment::get().getDialogueManager()->setFactionReaction(faction1, faction2, newValue);
|
||||
}
|
||||
};
|
||||
|
||||
template <class R>
|
||||
class OpClearInfoActor : public Interpreter::Opcode0
|
||||
{
|
||||
|
@ -268,6 +287,7 @@ namespace MWScript
|
|||
interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFaction, new OpSameFaction<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFactionExplicit, new OpSameFaction<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Dialogue::opcodeModFactionReaction, new OpModFactionReaction);
|
||||
interpreter.installSegment5 (Compiler::Dialogue::opcodeSetFactionReaction, new OpSetFactionReaction);
|
||||
interpreter.installSegment5 (Compiler::Dialogue::opcodeGetFactionReaction, new OpGetFactionReaction);
|
||||
interpreter.installSegment5 (Compiler::Dialogue::opcodeClearInfoActor, new OpClearInfoActor<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Dialogue::opcodeClearInfoActorExplicit, new OpClearInfoActor<ExplicitRef>);
|
||||
|
|
|
@ -442,5 +442,6 @@ op 0x20002fb: AddToLevCreature
|
|||
op 0x20002fc: RemoveFromLevCreature
|
||||
op 0x20002fd: AddToLevItem
|
||||
op 0x20002fe: RemoveFromLevItem
|
||||
op 0x20002ff: SetFactionReaction
|
||||
|
||||
opcodes 0x20002ff-0x3ffffff unused
|
||||
opcodes 0x2000300-0x3ffffff unused
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <components/esm/cellid.hpp>
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/objectstate.hpp>
|
||||
#include <components/esm/lightstate.hpp>
|
||||
#include <components/esm/containerstate.hpp>
|
||||
#include <components/esm/npcstate.hpp>
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
|
@ -86,7 +85,9 @@ namespace
|
|||
RecordType state;
|
||||
iter->save (state);
|
||||
|
||||
// recordId currently unused
|
||||
writer.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId);
|
||||
|
||||
state.save (writer);
|
||||
}
|
||||
}
|
||||
|
@ -94,12 +95,13 @@ namespace
|
|||
|
||||
template<typename RecordType, typename T>
|
||||
void readReferenceCollection (ESM::ESMReader& reader,
|
||||
MWWorld::CellRefList<T>& collection, const std::map<int, int>& contentFileMap)
|
||||
MWWorld::CellRefList<T>& collection, const ESM::CellRef& cref, const std::map<int, int>& contentFileMap)
|
||||
{
|
||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
RecordType state;
|
||||
state.load (reader);
|
||||
state.mRef = cref;
|
||||
state.load(reader);
|
||||
|
||||
// If the reference came from a content file, make sure this content file is loaded
|
||||
if (state.mRef.mRefNum.hasContentFile())
|
||||
|
@ -464,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<ESM::CellRef&>(*it);
|
||||
const ESM::CellRef &ref = *it;
|
||||
|
||||
mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID));
|
||||
}
|
||||
|
@ -624,7 +626,7 @@ namespace MWWorld
|
|||
writeReferenceCollection<ESM::ObjectState> (writer, mIngreds);
|
||||
writeReferenceCollection<ESM::CreatureLevListState> (writer, mCreatureLists);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mItemLists);
|
||||
writeReferenceCollection<ESM::LightState> (writer, mLights);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mLights);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mLockpicks);
|
||||
writeReferenceCollection<ESM::ObjectState> (writer, mMiscItems);
|
||||
writeReferenceCollection<ESM::NpcState> (writer, mNpcs);
|
||||
|
@ -641,109 +643,121 @@ namespace MWWorld
|
|||
|
||||
while (reader.isNextSub ("OBJE"))
|
||||
{
|
||||
unsigned int id = 0;
|
||||
reader.getHT (id);
|
||||
unsigned int unused;
|
||||
reader.getHT (unused);
|
||||
|
||||
switch (id)
|
||||
// load the RefID first so we know what type of object it is
|
||||
ESM::CellRef cref;
|
||||
cref.loadId(reader, true);
|
||||
|
||||
int type = MWBase::Environment::get().getWorld()->getStore().find(cref.mRefID);
|
||||
if (type == 0)
|
||||
{
|
||||
std::cerr << "Dropping reference to '" << cref.mRefID << "' (object no longer exists)" << std::endl;
|
||||
reader.skipHSubUntil("OBJE");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ESM::REC_ACTI:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mActivators, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mActivators, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_ALCH:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mPotions, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mPotions, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_APPA:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mAppas, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mAppas, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_ARMO:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mArmors, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mArmors, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_BOOK:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mBooks, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mBooks, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_CLOT:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mClothes, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mClothes, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_CONT:
|
||||
|
||||
readReferenceCollection<ESM::ContainerState> (reader, mContainers, contentFileMap);
|
||||
readReferenceCollection<ESM::ContainerState> (reader, mContainers, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_CREA:
|
||||
|
||||
readReferenceCollection<ESM::CreatureState> (reader, mCreatures, contentFileMap);
|
||||
readReferenceCollection<ESM::CreatureState> (reader, mCreatures, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_DOOR:
|
||||
|
||||
readReferenceCollection<ESM::DoorState> (reader, mDoors, contentFileMap);
|
||||
readReferenceCollection<ESM::DoorState> (reader, mDoors, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_INGR:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mIngreds, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mIngreds, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_LEVC:
|
||||
|
||||
readReferenceCollection<ESM::CreatureLevListState> (reader, mCreatureLists, contentFileMap);
|
||||
readReferenceCollection<ESM::CreatureLevListState> (reader, mCreatureLists, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_LEVI:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mItemLists, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mItemLists, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_LIGH:
|
||||
|
||||
readReferenceCollection<ESM::LightState> (reader, mLights, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mLights, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_LOCK:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mLockpicks, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mLockpicks, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_MISC:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mMiscItems, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mMiscItems, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_NPC_:
|
||||
|
||||
readReferenceCollection<ESM::NpcState> (reader, mNpcs, contentFileMap);
|
||||
readReferenceCollection<ESM::NpcState> (reader, mNpcs, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_PROB:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mProbes, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mProbes, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_REPA:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mRepairs, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mRepairs, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_STAT:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mStatics, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mStatics, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
case ESM::REC_WEAP:
|
||||
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mWeapons, contentFileMap);
|
||||
readReferenceCollection<ESM::ObjectState> (reader, mWeapons, cref, contentFileMap);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -85,28 +85,29 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef<T>& ref, ESM::Object
|
|||
ref.save (state);
|
||||
}
|
||||
|
||||
/// \todo make this method const once const-correct ContainerStoreIterators are available
|
||||
template<typename T>
|
||||
void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection,
|
||||
std::vector<std::pair<ESM::ObjectState, std::pair<unsigned int, int> > >& states, bool equipable) const
|
||||
void MWWorld::ContainerStore::storeStates (CellRefList<T>& collection,
|
||||
std::vector<std::pair<ESM::ObjectState, int> >& states, bool equipable)
|
||||
{
|
||||
for (typename CellRefList<T>::List::const_iterator iter (collection.mList.begin());
|
||||
for (typename CellRefList<T>::List::iterator iter (collection.mList.begin());
|
||||
iter!=collection.mList.end(); ++iter)
|
||||
{
|
||||
if (iter->mData.getCount() == 0)
|
||||
continue;
|
||||
ESM::ObjectState state;
|
||||
storeState (*iter, state);
|
||||
int slot = equipable ? getSlot (*iter) : -1;
|
||||
states.push_back (std::make_pair (state, std::make_pair (T::sRecordId, slot)));
|
||||
int slot = equipable ? getRelativeSlot (MWWorld::ContainerStoreIterator(this, iter)) : -1;
|
||||
states.push_back (std::make_pair (state, slot));
|
||||
}
|
||||
}
|
||||
|
||||
int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const
|
||||
int MWWorld::ContainerStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {}
|
||||
void MWWorld::ContainerStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {}
|
||||
|
||||
const std::string MWWorld::ContainerStore::sGoldId = "gold_001";
|
||||
|
||||
|
@ -641,7 +642,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();
|
||||
|
||||
|
@ -656,55 +657,45 @@ void MWWorld::ContainerStore::writeState (ESM::InventoryState& state) const
|
|||
storeStates (probes, state.mItems, true);
|
||||
storeStates (repairs, state.mItems);
|
||||
storeStates (weapons, state.mItems, true);
|
||||
|
||||
state.mLights.clear();
|
||||
storeStates (lights, state.mItems, true);
|
||||
|
||||
state.mLevelledItemMap = mLevelledItemMap;
|
||||
|
||||
for (MWWorld::CellRefList<ESM::Light>::List::const_iterator iter (lights.mList.begin());
|
||||
iter!=lights.mList.end(); ++iter)
|
||||
{
|
||||
ESM::LightState objectState;
|
||||
storeState (*iter, objectState);
|
||||
state.mLights.push_back (std::make_pair (objectState, getSlot (*iter)));
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::readState (const ESM::InventoryState& state)
|
||||
{
|
||||
clear();
|
||||
|
||||
for (std::vector<std::pair<ESM::ObjectState, std::pair<unsigned int, int> > >::const_iterator
|
||||
for (std::vector<std::pair<ESM::ObjectState, int> >::const_iterator
|
||||
iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter)
|
||||
{
|
||||
int slot = iter->second.second;
|
||||
int slot = iter->second;
|
||||
|
||||
switch (iter->second.first)
|
||||
const ESM::ObjectState& state = iter->first;
|
||||
|
||||
int type = MWBase::Environment::get().getWorld()->getStore().find(state.mRef.mRefID);
|
||||
|
||||
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_ARMO: setRelativeSlot (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_CLOT: setRelativeSlot (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_LOCK: setRelativeSlot (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_PROB: setRelativeSlot (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_WEAP: setRelativeSlot (getState (weapons, iter->first), slot); break;
|
||||
case ESM::REC_LIGH: setRelativeSlot (getState (lights, iter->first), slot); break;
|
||||
|
||||
default:
|
||||
|
||||
std::cerr << "invalid item type in inventory state" << std::endl;
|
||||
std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<std::pair<ESM::LightState, int> >::const_iterator iter (state.mLights.begin());
|
||||
iter!=state.mLights.end(); ++iter)
|
||||
{
|
||||
int slot = iter->second;
|
||||
setSlot (getState (lights, iter->first), slot);
|
||||
}
|
||||
|
||||
mLevelledItemMap = state.mLevelledItemMap;
|
||||
}
|
||||
|
|
|
@ -84,15 +84,16 @@ namespace MWWorld
|
|||
template<typename T>
|
||||
void storeState (const LiveCellRef<T>& ref, ESM::ObjectState& state) const;
|
||||
|
||||
/// \todo make this method const once const-correct ContainerStoreIterators are available
|
||||
template<typename T>
|
||||
void storeStates (const CellRefList<T>& collection,
|
||||
std::vector<std::pair<ESM::ObjectState, std::pair<unsigned int, int> > >& states,
|
||||
bool equipable = false) const;
|
||||
void storeStates (CellRefList<T>& collection,
|
||||
std::vector<std::pair<ESM::ObjectState, int> >& states,
|
||||
bool equipable = false);
|
||||
|
||||
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const;
|
||||
virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter) 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 setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int slot);
|
||||
///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1.
|
||||
|
||||
public:
|
||||
|
@ -171,7 +172,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);
|
||||
|
||||
|
|
|
@ -49,19 +49,40 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_)
|
|||
slots_.push_back (end());
|
||||
}
|
||||
|
||||
int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const
|
||||
int MWWorld::InventoryStore::getRelativeSlot (const MWWorld::ContainerStoreIterator& iter)
|
||||
{
|
||||
for (int i = 0; i<static_cast<int> (mSlots.size()); ++i)
|
||||
if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref)
|
||||
return i;
|
||||
if (mSlots[i].getType()!=-1 && mSlots[i] == iter)
|
||||
{
|
||||
// linear complexity, but allowedSlots is most of the time just 1 anyway
|
||||
std::vector<int> allowedSlots = iter->getClass().getEquipmentSlots(*iter).first;
|
||||
std::vector<int>::iterator found = std::find(allowedSlots.begin(),allowedSlots.end(),i);
|
||||
if (found == allowedSlots.end())
|
||||
return -1;
|
||||
else
|
||||
return std::distance(allowedSlots.begin(), found);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot)
|
||||
void MWWorld::InventoryStore::setRelativeSlot (const MWWorld::ContainerStoreIterator& iter, int relativeSlot)
|
||||
{
|
||||
if (iter!=end() && slot>=0 && slot<Slots)
|
||||
mSlots[slot] = iter;
|
||||
if (relativeSlot < 0 || iter == end())
|
||||
return;
|
||||
|
||||
std::pair<std::vector<int>, 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 +724,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);
|
||||
|
||||
|
|
|
@ -113,10 +113,10 @@ namespace MWWorld
|
|||
|
||||
void fireEquipmentChangedEvent();
|
||||
|
||||
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const;
|
||||
virtual int getRelativeSlot (const MWWorld::ContainerStoreIterator& iter);
|
||||
///< 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 setRelativeSlot (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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<OEngine::Physic::PhysicActor *> (physactor)->setOnGround(true);
|
||||
physactor->setOnGround(true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -57,11 +57,11 @@ add_component_dir (to_utf8
|
|||
|
||||
add_component_dir (esm
|
||||
attr defs esmcommon esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell
|
||||
loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst
|
||||
loadclas loadclot loadcont loadcrea loaddial loaddoor loadench loadfact loadglob loadgmst
|
||||
loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc
|
||||
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
|
||||
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
|
||||
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate
|
||||
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate
|
||||
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile
|
||||
aisequence magiceffects util custommarkerstate
|
||||
)
|
||||
|
|
|
@ -192,6 +192,7 @@ namespace Compiler
|
|||
extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction,
|
||||
opcodeSameFactionExplicit);
|
||||
extensions.registerInstruction("modfactionreaction", "ccl", opcodeModFactionReaction);
|
||||
extensions.registerInstruction("setfactionreaction", "ccl", opcodeSetFactionReaction);
|
||||
extensions.registerFunction("getfactionreaction", 'l', "ccX", opcodeGetFactionReaction);
|
||||
extensions.registerInstruction("clearinfoactor", "", opcodeClearInfoActor, opcodeClearInfoActorExplicit);
|
||||
}
|
||||
|
|
|
@ -167,6 +167,7 @@ namespace Compiler
|
|||
const int opcodeSameFaction = 0x20001b5;
|
||||
const int opcodeSameFactionExplicit = 0x20001b6;
|
||||
const int opcodeModFactionReaction = 0x2000242;
|
||||
const int opcodeSetFactionReaction = 0x20002ff;
|
||||
const int opcodeGetFactionReaction = 0x2000243;
|
||||
const int opcodeClearInfoActor = 0x2000245;
|
||||
const int opcodeClearInfoActorExplicit = 0x2000246;
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
#include "esmwriter.hpp"
|
||||
|
||||
void ESM::CellRef::load (ESMReader& esm, bool wideRefNum)
|
||||
{
|
||||
loadId(esm, wideRefNum);
|
||||
loadData(esm);
|
||||
}
|
||||
|
||||
void ESM::CellRef::loadId(ESMReader &esm, bool wideRefNum)
|
||||
{
|
||||
// According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that
|
||||
// the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system.
|
||||
|
@ -19,8 +25,6 @@ void ESM::CellRef::load (ESMReader& esm, bool wideRefNum)
|
|||
esm.getHNT (mRefNum.mIndex, "FRMR");
|
||||
|
||||
mRefID = esm.getHNString ("NAME");
|
||||
|
||||
loadData(esm);
|
||||
}
|
||||
|
||||
void ESM::CellRef::loadData(ESMReader &esm)
|
||||
|
@ -42,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");
|
||||
|
||||
|
@ -102,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);
|
||||
|
@ -142,8 +146,8 @@ void ESM::CellRef::blank()
|
|||
mSoul.clear();
|
||||
mFaction.clear();
|
||||
mFactionRank = -2;
|
||||
mCharge = 0;
|
||||
mEnchantmentCharge = 0;
|
||||
mChargeInt = -1;
|
||||
mEnchantmentCharge = -1;
|
||||
mGoldValue = 0;
|
||||
mDestCell.clear();
|
||||
mLockLevel = 0;
|
||||
|
|
|
@ -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;
|
||||
|
@ -89,8 +93,11 @@ namespace ESM
|
|||
// Position and rotation of this object within the cell
|
||||
Position mPos;
|
||||
|
||||
/// Calls loadId and loadData
|
||||
void load (ESMReader& esm, bool wideRefNum = false);
|
||||
|
||||
void loadId (ESMReader& esm, bool wideRefNum = false);
|
||||
|
||||
/// Implicitly called by load
|
||||
void loadData (ESMReader& esm);
|
||||
|
||||
|
|
|
@ -5,18 +5,24 @@ void ESM::CreatureState::load (ESMReader &esm)
|
|||
{
|
||||
ObjectState::load (esm);
|
||||
|
||||
mInventory.load (esm);
|
||||
if (mHasCustomState)
|
||||
{
|
||||
mInventory.load (esm);
|
||||
|
||||
mCreatureStats.load (esm);
|
||||
mCreatureStats.load (esm);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const
|
||||
{
|
||||
ObjectState::save (esm, inInventory);
|
||||
|
||||
mInventory.save (esm);
|
||||
if (mHasCustomState)
|
||||
{
|
||||
mInventory.save (esm);
|
||||
|
||||
mCreatureStats.save (esm);
|
||||
mCreatureStats.save (esm);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM::CreatureState::blank()
|
||||
|
|
|
@ -230,7 +230,7 @@ void ESM::CreatureStats::blank()
|
|||
mTradeTime.mHour = 0;
|
||||
mTradeTime.mDay = 0;
|
||||
mGoldPool = 0;
|
||||
mActorId = 0;
|
||||
mActorId = -1;
|
||||
mHasAiSettings = false;
|
||||
mDead = false;
|
||||
mDied = false;
|
||||
|
|
|
@ -13,13 +13,20 @@ void ESM::DialogueState::load (ESMReader &esm)
|
|||
{
|
||||
std::string faction = esm.getHString();
|
||||
|
||||
while (esm.isNextSub ("REAC"))
|
||||
while (esm.isNextSub("REA2"))
|
||||
{
|
||||
std::string faction2 = esm.getHString();
|
||||
int reaction;
|
||||
esm.getHNT(reaction, "INTV");
|
||||
mChangedFactionReaction[faction][faction2] = reaction;
|
||||
}
|
||||
|
||||
mModFactionReaction[faction][faction2] = reaction;
|
||||
// no longer used
|
||||
while (esm.isNextSub ("REAC"))
|
||||
{
|
||||
esm.skipHSub();
|
||||
esm.getSubHeader();
|
||||
esm.skipHSub();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,15 +39,15 @@ void ESM::DialogueState::save (ESMWriter &esm) const
|
|||
esm.writeHNString ("TOPI", *iter);
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::map<std::string, int> >::const_iterator iter = mModFactionReaction.begin();
|
||||
iter != mModFactionReaction.end(); ++iter)
|
||||
for (std::map<std::string, std::map<std::string, int> >::const_iterator iter = mChangedFactionReaction.begin();
|
||||
iter != mChangedFactionReaction.end(); ++iter)
|
||||
{
|
||||
esm.writeHNString ("FACT", iter->first);
|
||||
|
||||
for (std::map<std::string, int>::const_iterator reactIter = iter->second.begin();
|
||||
reactIter != iter->second.end(); ++reactIter)
|
||||
{
|
||||
esm.writeHNString ("REAC", reactIter->first);
|
||||
esm.writeHNString ("REA2", reactIter->first);
|
||||
esm.writeHNT ("INTV", reactIter->second);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@ namespace ESM
|
|||
|
||||
struct DialogueState
|
||||
{
|
||||
// must be lower case topic IDs
|
||||
std::vector<std::string> mKnownTopics;
|
||||
|
||||
std::map<std::string, std::map<std::string, int> > mModFactionReaction;
|
||||
// must be lower case faction IDs
|
||||
std::map<std::string, std::map<std::string, int> > mChangedFactionReaction;
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
|
|
|
@ -134,7 +134,11 @@ void ESMReader::getHExact(void*p, int size)
|
|||
{
|
||||
getSubHeader();
|
||||
if (size != static_cast<int> (mCtx.leftSub))
|
||||
fail("getHExact() size mismatch");
|
||||
{
|
||||
std::stringstream error;
|
||||
error << "getHExact(): size mismatch (requested " << size << ", got " << mCtx.leftSub << ")";
|
||||
fail(error.str());
|
||||
}
|
||||
getExact(p, size);
|
||||
}
|
||||
|
||||
|
@ -210,6 +214,17 @@ void ESMReader::skipHSubSize(int size)
|
|||
fail("skipHSubSize() mismatch");
|
||||
}
|
||||
|
||||
void ESMReader::skipHSubUntil(const char *name)
|
||||
{
|
||||
while (hasMoreSubs() && !isNextSub(name))
|
||||
{
|
||||
mCtx.subCached = false;
|
||||
skipHSub();
|
||||
}
|
||||
if (hasMoreSubs())
|
||||
mCtx.subCached = true;
|
||||
}
|
||||
|
||||
void ESMReader::getSubHeader()
|
||||
{
|
||||
if (mCtx.leftRec < 4)
|
||||
|
|
|
@ -137,7 +137,11 @@ public:
|
|||
{
|
||||
getSubHeader();
|
||||
if (mCtx.leftSub != sizeof(X))
|
||||
fail("getHT(): subrecord size mismatch");
|
||||
{
|
||||
std::stringstream error;
|
||||
error << "getHT(): subrecord size mismatch (requested " << sizeof(X) << ", got " << mCtx.leftSub << ")";
|
||||
fail(error.str());
|
||||
}
|
||||
getT(x);
|
||||
}
|
||||
|
||||
|
@ -195,6 +199,9 @@ public:
|
|||
// Skip sub record and check its size
|
||||
void skipHSubSize(int size);
|
||||
|
||||
// Skip all subrecords until the given subrecord or no more subrecords remaining
|
||||
void skipHSubUntil(const char* name);
|
||||
|
||||
/* Sub-record header. This updates leftRec beyond the current
|
||||
sub-record as well. leftSub contains size of current sub-record.
|
||||
*/
|
||||
|
|
|
@ -11,12 +11,14 @@ namespace
|
|||
slot = -1;
|
||||
esm.getHNOT (slot, "SLOT");
|
||||
|
||||
state.mRef.loadId(esm, true);
|
||||
state.load (esm);
|
||||
}
|
||||
|
||||
void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, unsigned int type, int slot)
|
||||
void write (ESM::ESMWriter &esm, const ESM::ObjectState& state, int slot)
|
||||
{
|
||||
esm.writeHNT ("IOBJ", type);
|
||||
int unused = 0;
|
||||
esm.writeHNT ("IOBJ", unused);
|
||||
|
||||
if (slot!=-1)
|
||||
esm.writeHNT ("SLOT", slot);
|
||||
|
@ -29,27 +31,15 @@ void ESM::InventoryState::load (ESMReader &esm)
|
|||
{
|
||||
while (esm.isNextSub ("IOBJ"))
|
||||
{
|
||||
unsigned int id = 0;
|
||||
esm.getHT (id);
|
||||
int unused; // no longer used
|
||||
esm.getHT(unused);
|
||||
|
||||
if (id==ESM::REC_LIGH)
|
||||
{
|
||||
LightState state;
|
||||
int slot;
|
||||
read (esm, state, slot);
|
||||
if (state.mCount == 0)
|
||||
continue;
|
||||
mLights.push_back (std::make_pair (state, slot));
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectState state;
|
||||
int slot;
|
||||
read (esm, state, slot);
|
||||
if (state.mCount == 0)
|
||||
continue;
|
||||
mItems.push_back (std::make_pair (state, std::make_pair (id, slot)));
|
||||
}
|
||||
ObjectState state;
|
||||
int slot;
|
||||
read (esm, state, slot);
|
||||
if (state.mCount == 0)
|
||||
continue;
|
||||
mItems.push_back (std::make_pair (state, slot));
|
||||
}
|
||||
|
||||
while (esm.isNextSub("LEVM"))
|
||||
|
@ -78,12 +68,8 @@ void ESM::InventoryState::load (ESMReader &esm)
|
|||
|
||||
void ESM::InventoryState::save (ESMWriter &esm) const
|
||||
{
|
||||
for (std::vector<std::pair<ObjectState, std::pair<unsigned int, int> > >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter)
|
||||
write (esm, iter->first, iter->second.first, iter->second.second);
|
||||
|
||||
for (std::vector<std::pair<LightState, int> >::const_iterator iter (mLights.begin());
|
||||
iter!=mLights.end(); ++iter)
|
||||
write (esm, iter->first, ESM::REC_LIGH, iter->second);
|
||||
for (std::vector<std::pair<ObjectState, int> >::const_iterator iter (mItems.begin()); iter!=mItems.end(); ++iter)
|
||||
write (esm, iter->first, iter->second);
|
||||
|
||||
for (std::map<std::string, int>::const_iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <map>
|
||||
|
||||
#include "objectstate.hpp"
|
||||
#include "lightstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
@ -16,11 +15,8 @@ namespace ESM
|
|||
/// \brief State for inventories and containers
|
||||
struct InventoryState
|
||||
{
|
||||
// anything but lights (type, slot)
|
||||
std::vector<std::pair<ObjectState, std::pair<unsigned int, int> > > mItems;
|
||||
|
||||
// lights (slot)
|
||||
std::vector<std::pair<LightState, int> > mLights;
|
||||
/// <ObjectState, relative equipment slot>
|
||||
std::vector<std::pair<ObjectState, int> > mItems;
|
||||
|
||||
std::map<std::string, int> mLevelledItemMap;
|
||||
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
#include "lightstate.hpp"
|
||||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
void ESM::LightState::load (ESMReader &esm)
|
||||
{
|
||||
ObjectState::load (esm);
|
||||
|
||||
mTime = 0;
|
||||
esm.getHNOT (mTime, "LTIM");
|
||||
}
|
||||
|
||||
void ESM::LightState::save (ESMWriter &esm, bool inInventory) const
|
||||
{
|
||||
ObjectState::save (esm, inInventory);
|
||||
|
||||
if (mTime)
|
||||
esm.writeHNT ("LTIM", mTime);
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef OPENMW_ESM_LIGHTSTATE_H
|
||||
#define OPENMW_ESM_LIGHTSTATE_H
|
||||
|
||||
#include "objectstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
// format 0, saved games only
|
||||
|
||||
struct LightState : public ObjectState
|
||||
{
|
||||
float mTime;
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,49 +0,0 @@
|
|||
#ifndef OPENMW_ESM_CREC_H
|
||||
#define OPENMW_ESM_CREC_H
|
||||
|
||||
#include <string>
|
||||
|
||||
// TODO create implementation files and remove this one
|
||||
#include "esmreader.hpp"
|
||||
|
||||
namespace ESM {
|
||||
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
/* These two are only used in save games. They are not decoded yet.
|
||||
*/
|
||||
|
||||
/// Changes a creature
|
||||
struct LoadCREC
|
||||
{
|
||||
static unsigned int sRecordId;
|
||||
|
||||
std::string mId;
|
||||
|
||||
void load(ESMReader &esm)
|
||||
{
|
||||
esm.skipRecord();
|
||||
}
|
||||
|
||||
void save(ESMWriter &esm) const
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// Changes an item list / container
|
||||
struct LoadCNTC
|
||||
{
|
||||
std::string mId;
|
||||
|
||||
void load(ESMReader &esm)
|
||||
{
|
||||
esm.skipRecord();
|
||||
}
|
||||
|
||||
void save(ESMWriter &esm) const
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
|
@ -5,22 +5,28 @@ void ESM::NpcState::load (ESMReader &esm)
|
|||
{
|
||||
ObjectState::load (esm);
|
||||
|
||||
mInventory.load (esm);
|
||||
if (mHasCustomState)
|
||||
{
|
||||
mInventory.load (esm);
|
||||
|
||||
mNpcStats.load (esm);
|
||||
mNpcStats.load (esm);
|
||||
|
||||
mCreatureStats.load (esm);
|
||||
mCreatureStats.load (esm);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const
|
||||
{
|
||||
ObjectState::save (esm, inInventory);
|
||||
|
||||
mInventory.save (esm);
|
||||
if (mHasCustomState)
|
||||
{
|
||||
mInventory.save (esm);
|
||||
|
||||
mNpcStats.save (esm);
|
||||
mNpcStats.save (esm);
|
||||
|
||||
mCreatureStats.save (esm);
|
||||
mCreatureStats.save (esm);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM::NpcState::blank()
|
||||
|
@ -28,4 +34,5 @@ void ESM::NpcState::blank()
|
|||
ObjectState::blank();
|
||||
mNpcStats.blank();
|
||||
mCreatureStats.blank();
|
||||
mHasCustomState = true;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
void ESM::ObjectState::load (ESMReader &esm)
|
||||
{
|
||||
mRef.load (esm, true);
|
||||
mRef.loadData(esm);
|
||||
|
||||
mHasLocals = 0;
|
||||
esm.getHNOT (mHasLocals, "HLOC");
|
||||
|
@ -23,6 +23,14 @@ void ESM::ObjectState::load (ESMReader &esm)
|
|||
esm.getHNOT (mPosition, "POS_", 24);
|
||||
|
||||
esm.getHNOT (mLocalRotation, "LROT", 12);
|
||||
|
||||
// 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;
|
||||
esm.getHNOT (mHasCustomState, "HCUS");
|
||||
}
|
||||
|
||||
void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const
|
||||
|
@ -46,6 +54,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const
|
|||
esm.writeHNT ("POS_", mPosition, 24);
|
||||
esm.writeHNT ("LROT", mLocalRotation, 12);
|
||||
}
|
||||
|
||||
if (!mHasCustomState)
|
||||
esm.writeHNT ("HCUS", false);
|
||||
}
|
||||
|
||||
void ESM::ObjectState::blank()
|
||||
|
@ -60,6 +71,7 @@ void ESM::ObjectState::blank()
|
|||
mPosition.rot[i] = 0;
|
||||
mLocalRotation[i] = 0;
|
||||
}
|
||||
mHasCustomState = true;
|
||||
}
|
||||
|
||||
ESM::ObjectState::~ObjectState() {}
|
||||
|
|
|
@ -26,7 +26,15 @@ namespace ESM
|
|||
ESM::Position mPosition;
|
||||
float mLocalRotation[3];
|
||||
|
||||
// Is there any class-specific state following the ObjectState
|
||||
bool mHasCustomState;
|
||||
|
||||
ObjectState() : mHasCustomState(true)
|
||||
{}
|
||||
|
||||
/// @note Does not load the CellRef ID, it should already be loaded before calling this method
|
||||
virtual void load (ESMReader &esm);
|
||||
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
|
||||
/// Initialize to default state
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
void ESM::Player::load (ESMReader &esm)
|
||||
{
|
||||
mObject.mRef.loadId(esm, true);
|
||||
mObject.load (esm);
|
||||
|
||||
mCellId.load (esm);
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "loadclot.hpp"
|
||||
#include "loadcont.hpp"
|
||||
#include "loadcrea.hpp"
|
||||
#include "loadcrec.hpp"
|
||||
#include "loadinfo.hpp"
|
||||
#include "loaddial.hpp"
|
||||
#include "loaddoor.hpp"
|
||||
|
|
|
@ -402,8 +402,8 @@ namespace ESMTerrain
|
|||
int endX = startX + 1;
|
||||
int endY = startY + 1;
|
||||
|
||||
assert(endX < ESM::Land::LAND_SIZE);
|
||||
assert(endY < ESM::Land::LAND_SIZE);
|
||||
endX = std::min(endX, ESM::Land::LAND_SIZE-1);
|
||||
endY = std::min(endY, ESM::Land::LAND_SIZE-1);
|
||||
|
||||
// now get points in terrain space (effectively rounding them to boundaries)
|
||||
float startXTS = startX * invFactor;
|
||||
|
|
Loading…
Reference in a new issue