Merge remote-tracking branch 'scrawl/master'

openmw-35
Marc Zinnschlag 10 years ago
commit b44fc1904b

@ -51,6 +51,8 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binarie
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre plugins (autodetected by default)")
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
# Apps and tools
@ -323,8 +325,10 @@ if (APPLE AND OPENMW_OSX_DEPLOYMENT)
# make it empty so plugin loading code can check this and try to find plugins inside app bundle
add_definitions(-DOGRE_PLUGIN_DIR="")
else()
if (NOT DEFINED ${OGRE_PLUGIN_DIR})
if (CUSTOM_OGRE_PLUGIN_DIR STREQUAL "")
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
else()
set(OGRE_PLUGIN_DIR ${CUSTOM_OGRE_PLUGIN_DIR})
endif()
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")

@ -27,8 +27,8 @@ struct Arguments
void replaceAll(std::string& str, const std::string& needle, const std::string& substitute)
{
int pos = str.find(needle);
while(pos != -1)
size_t pos = str.find(needle);
while(pos != std::string::npos)
{
str.replace(pos, needle.size(), substitute);
pos = str.find(needle);
@ -138,8 +138,8 @@ bool parseOptions (int argc, char** argv, Arguments &info)
else if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
info.outdir = variables["input-file"].as< std::vector<std::string> >()[1];
info.longformat = variables.count("long");
info.fullpath = variables.count("full-path");
info.longformat = variables.count("long") != 0;
info.fullpath = variables.count("full-path") != 0;
return true;
}

@ -22,7 +22,7 @@ struct ESMData
{
std::string author;
std::string description;
int version;
unsigned int version;
std::vector<ESM::Header::MasterData> masters;
std::deque<EsmTool::RecordBase *> mRecords;
@ -48,9 +48,9 @@ const std::set<int> ESMData::sLabeledRec =
// Based on the legacy struct
struct Arguments
{
unsigned int raw_given;
unsigned int quiet_given;
unsigned int loadcells_given;
bool raw_given;
bool quiet_given;
bool loadcells_given;
bool plain_given;
std::string mode;
@ -177,10 +177,10 @@ bool parseOptions (int argc, char** argv, Arguments &info)
if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
info.outname = variables["input-file"].as< std::vector<std::string> >()[1];
info.raw_given = variables.count ("raw");
info.quiet_given = variables.count ("quiet");
info.loadcells_given = variables.count ("loadcells");
info.plain_given = (variables.count("plain") > 0);
info.raw_given = variables.count ("raw") != 0;
info.quiet_given = variables.count ("quiet") != 0;
info.loadcells_given = variables.count ("loadcells") != 0;
info.plain_given = variables.count("plain") != 0;
// Font encoding settings
info.encoding = variables["encoding"].as<std::string>();
@ -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;
@ -430,7 +430,7 @@ int clone(Arguments& info)
return 1;
}
int recordCount = info.data.mRecords.size();
size_t recordCount = info.data.mRecords.size();
int digitCount = 1; // For a nicer output
if (recordCount > 9) ++digitCount;
@ -501,9 +501,9 @@ int clone(Arguments& info)
if (!info.data.mCellRefs[ptr].empty()) {
typedef std::deque<ESM::CellRef> RefList;
RefList &refs = info.data.mCellRefs[ptr];
for (RefList::iterator it = refs.begin(); it != refs.end(); ++it)
for (RefList::iterator refIt = refs.begin(); refIt != refs.end(); ++refIt)
{
it->save(esm);
refIt->save(esm);
}
}
}
@ -511,7 +511,7 @@ int clone(Arguments& info)
esm.endRecord(name.toString());
saved++;
int perc = (saved / (float)recordCount)*100;
int perc = (int)((saved / (float)recordCount)*100);
if (perc % 10 == 0)
{
std::cerr << "\r" << perc << "%";

@ -13,14 +13,13 @@
#include <components/esm/loadweap.hpp>
#include <components/esm/aipackage.hpp>
#include <iostream>
#include <boost/format.hpp>
std::string bodyPartLabel(int idx)
{
if (idx >= 0 && idx <= 26)
{
const char *bodyPartLabels[] = {
static const char *bodyPartLabels[] = {
"Head",
"Hair",
"Neck",
@ -59,7 +58,7 @@ std::string meshPartLabel(int idx)
{
if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail)
{
const char *meshPartLabels[] = {
static const char *meshPartLabels[] = {
"Head",
"Hair",
"Neck",
@ -86,7 +85,7 @@ std::string meshTypeLabel(int idx)
{
if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor)
{
const char *meshTypeLabels[] = {
static const char *meshTypeLabels[] = {
"Skin",
"Clothing",
"Armor"
@ -101,7 +100,7 @@ std::string clothingTypeLabel(int idx)
{
if (idx >= 0 && idx <= 9)
{
const char *clothingTypeLabels[] = {
static const char *clothingTypeLabels[] = {
"Pants",
"Shoes",
"Shirt",
@ -123,7 +122,7 @@ std::string armorTypeLabel(int idx)
{
if (idx >= 0 && idx <= 10)
{
const char *armorTypeLabels[] = {
static const char *armorTypeLabels[] = {
"Helmet",
"Cuirass",
"Left Pauldron",
@ -146,7 +145,7 @@ std::string dialogTypeLabel(int idx)
{
if (idx >= 0 && idx <= 4)
{
const char *dialogTypeLabels[] = {
static const char *dialogTypeLabels[] = {
"Topic",
"Voice",
"Greeting",
@ -165,7 +164,7 @@ std::string questStatusLabel(int idx)
{
if (idx >= 0 && idx <= 4)
{
const char *questStatusLabels[] = {
static const char *questStatusLabels[] = {
"None",
"Name",
"Finished",
@ -182,7 +181,7 @@ std::string creatureTypeLabel(int idx)
{
if (idx >= 0 && idx <= 3)
{
const char *creatureTypeLabels[] = {
static const char *creatureTypeLabels[] = {
"Creature",
"Daedra",
"Undead",
@ -198,7 +197,7 @@ std::string soundTypeLabel(int idx)
{
if (idx >= 0 && idx <= 7)
{
const char *soundTypeLabels[] = {
static const char *soundTypeLabels[] = {
"Left Foot",
"Right Foot",
"Swim Left",
@ -218,7 +217,7 @@ std::string weaponTypeLabel(int idx)
{
if (idx >= 0 && idx <= 13)
{
const char *weaponTypeLabels[] = {
static const char *weaponTypeLabels[] = {
"Short Blade One Hand",
"Long Blade One Hand",
"Long Blade Two Hand",

@ -25,7 +25,7 @@ void printAIPackage(ESM::AIPackage p)
{
std::cout << " Travel Coordinates: (" << p.mTravel.mX << ","
<< p.mTravel.mY << "," << p.mTravel.mZ << ")" << std::endl;
std::cout << " Travel Unknown: " << (int)p.mTravel.mUnk << std::endl;
std::cout << " Travel Unknown: " << p.mTravel.mUnk << std::endl;
}
else if (p.mType == ESM::AI_Follow || p.mType == ESM::AI_Escort)
{
@ -33,12 +33,12 @@ void printAIPackage(ESM::AIPackage p)
<< p.mTarget.mY << "," << p.mTarget.mZ << ")" << std::endl;
std::cout << " Duration: " << p.mTarget.mDuration << std::endl;
std::cout << " Target ID: " << p.mTarget.mId.toString() << std::endl;
std::cout << " Unknown: " << (int)p.mTarget.mUnk << std::endl;
std::cout << " Unknown: " << p.mTarget.mUnk << std::endl;
}
else if (p.mType == ESM::AI_Activate)
{
std::cout << " Name: " << p.mActivate.mName.toString() << std::endl;
std::cout << " Activate Unknown: " << (int)p.mActivate.mUnk << std::endl;
std::cout << " Activate Unknown: " << p.mActivate.mUnk << std::endl;
}
else {
std::cout << " BadPackage: " << boost::format("0x%08x") % p.mType << std::endl;
@ -89,6 +89,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss)
case 'A': if (indicator == 'R') type_str = "Not Race"; break;
case 'B': if (indicator == 'L') type_str = "Not Cell"; break;
case 'C': if (indicator == 's') type_str = "Not Local"; break;
default: break;
}
// Append the variable name to the function string if any.
@ -110,6 +111,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss)
case '3': oper_str = ">="; break;
case '4': oper_str = "< "; break;
case '5': oper_str = "<="; break;
default: break;
}
std::ostringstream stream;
@ -430,7 +432,7 @@ void Record<ESM::Apparatus>::print()
std::cout << " Icon: " << mData.mIcon << std::endl;
std::cout << " Script: " << mData.mScript << std::endl;
std::cout << " Type: " << apparatusTypeLabel(mData.mData.mType)
<< " (" << (int)mData.mData.mType << ")" << std::endl;
<< " (" << mData.mData.mType << ")" << std::endl;
std::cout << " Weight: " << mData.mData.mWeight << std::endl;
std::cout << " Value: " << mData.mData.mValue << std::endl;
std::cout << " Quality: " << mData.mData.mQuality << std::endl;
@ -816,7 +818,7 @@ void Record<ESM::Land>::print()
// Seems like this should done with reference counting in the
// loader to me. But I'm not really knowledgable about this
// record type yet. --Cory
bool wasLoaded = mData.mDataLoaded;
bool wasLoaded = (mData.mDataLoaded != 0);
if (mData.mDataTypes) mData.loadData(mData.mDataTypes);
if (mData.mDataLoaded)
{
@ -999,7 +1001,7 @@ void Record<ESM::NPC>::print()
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl;
std::cout << " Unknown3: "
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl;
std::cout << " Gold: " << (int)mData.mNpdt12.mGold << std::endl;
std::cout << " Gold: " << mData.mNpdt12.mGold << std::endl;
}
else {
std::cout << " Level: " << mData.mNpdt52.mLevel << std::endl;
@ -1021,7 +1023,7 @@ void Record<ESM::NPC>::print()
std::cout << " Skills:" << std::endl;
for (int i = 0; i != ESM::Skill::Length; i++)
std::cout << " " << skillLabel(i) << ": "
<< (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl;
<< (int)(mData.mNpdt52.mSkills[i]) << std::endl;
std::cout << " Health: " << mData.mNpdt52.mHealth << std::endl;
std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl;
@ -1123,9 +1125,9 @@ void Record<ESM::Race>::print()
std::cout << (male ? " Male:" : " Female:") << std::endl;
for (int i=0; i<8; ++i)
std::cout << " " << sAttributeNames[i] << ": "
<< mData.mData.mAttributeValues[i].getValue (male) << std::endl;
for (int j=0; j<8; ++j)
std::cout << " " << sAttributeNames[j] << ": "
<< mData.mData.mAttributeValues[j].getValue (male) << std::endl;
std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl;
std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl;

@ -19,7 +19,7 @@ namespace EsmTool
{
protected:
std::string mId;
int mFlags;
uint32_t mFlags;
ESM::NAME mType;
bool mPrintPlain;
@ -40,11 +40,11 @@ namespace EsmTool
mId = id;
}
int getFlags() const {
uint32_t getFlags() const {
return mFlags;
}
void setFlags(int flags) {
void setFlags(uint32_t flags) {
mFlags = flags;
}
@ -52,10 +52,6 @@ namespace EsmTool
return mType;
}
bool getPrintPlain() const {
return mPrintPlain;
}
void setPrintPlain(bool plain) {
mPrintPlain = plain;
}

@ -9,6 +9,13 @@ set(ESSIMPORTER_FILES
importinventory.cpp
importklst.cpp
importcntc.cpp
importgame.cpp
importinfo.cpp
importdial.cpp
importques.cpp
importjour.cpp
importscri.cpp
importscpt.cpp
importercontext.cpp
converter.cpp
convertacdt.cpp
@ -16,6 +23,7 @@ set(ESSIMPORTER_FILES
convertinventory.cpp
convertcrec.cpp
convertcntc.cpp
convertscri.cpp
)
add_executable(openmw-essimporter

@ -9,6 +9,7 @@
#include "convertcrec.hpp"
#include "convertcntc.hpp"
#include "convertscri.hpp"
namespace
{
@ -27,6 +28,10 @@ namespace
objstate.mEnabled = cellref.mEnabled;
objstate.mPosition = cellref.mPos;
objstate.mRef.mRefNum = cellref.mRefNum;
if (cellref.mDeleted)
objstate.mCount = 0;
convertSCRI(cellref.mSCRI, objstate.mLocals);
objstate.mHasLocals = !objstate.mLocals.mVariables.empty();
}
bool isIndexedRefId(const std::string& indexedRefId)
@ -34,6 +39,10 @@ namespace
if (indexedRefId.size() <= 8)
return false;
if (indexedRefId.find_first_not_of("0123456789") == std::string::npos)
return false; // entirely numeric refid, this is a reference to
// a dynamically created record e.g. player-enchanted weapon
std::string index = indexedRefId.substr(indexedRefId.size()-8);
if(index.find_first_not_of("0123456789ABCDEF") == std::string::npos )
return true;
@ -70,6 +79,12 @@ namespace ESSImport
cell.mName = id;
cell.load(esm, false);
// I wonder what 0x40 does?
if (cell.isExterior() && cell.mData.mFlags & 0x20)
{
mContext->mGlobalMapState.mMarkers.insert(std::make_pair(cell.mData.mX, cell.mData.mY));
}
// note if the player is in a nameless exterior cell, we will assign the cellId later based on player position
if (id == mContext->mPlayerCellName)
{
@ -136,13 +151,6 @@ namespace ESSImport
{
CellRef ref;
ref.load (esm);
if (esm.isNextSub("DELE"))
{
// TODO
// strangely this can be e.g. 52 instead of just 1,
//std::cout << "deleted ref " << ref.mIndexedRefId << std::endl;
esm.skipHSub();
}
cellrefs.push_back(ref);
}
@ -201,8 +209,7 @@ namespace ESSImport
for (std::vector<CellRef>::const_iterator refIt = cell.mRefs.begin(); refIt != cell.mRefs.end(); ++refIt)
{
const CellRef& cellref = *refIt;
ESM::CellRef out;
out.blank();
ESM::CellRef out (cellref);
if (!isIndexedRefId(cellref.mIndexedRefId))
{
@ -241,8 +248,8 @@ namespace ESSImport
objstate.mRef.mRefID = idLower;
// probably need more micromanagement here so we don't overwrite values
// from the ESM with default values
convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats);
convertNpcData(cellref.mActorData, objstate.mNpcStats);
convertACDT(cellref.mACDT, objstate.mCreatureStats);
convertNpcData(cellref, objstate.mNpcStats);
convertNPCC(npccIt->second, objstate);
convertCellRef(cellref, objstate);
esm.writeHNT ("OBJE", ESM::REC_NPC_);
@ -273,7 +280,7 @@ namespace ESSImport
objstate.blank();
objstate.mRef = out;
objstate.mRef.mRefID = idLower;
convertACDT(cellref.mActorData.mACDT, objstate.mCreatureStats);
convertACDT(cellref.mACDT, objstate.mCreatureStats);
// probably need more micromanagement here so we don't overwrite values
// from the ESM with default values
convertCREC(crecIt->second, objstate);
@ -306,6 +313,10 @@ namespace ESSImport
it->save(esm);
esm.endRecord(ESM::REC_MARK);
}
esm.startRecord(ESM::REC_GMAP);
mContext->mGlobalMapState.save(esm);
esm.endRecord(ESM::REC_GMAP);
}
}

@ -12,6 +12,7 @@
#include <components/esm/loadfact.hpp>
#include <components/esm/dialoguestate.hpp>
#include <components/esm/custommarkerstate.hpp>
#include <components/esm/loadcrea.hpp>
#include "importcrec.hpp"
#include "importcntc.hpp"
@ -19,6 +20,12 @@
#include "importercontext.hpp"
#include "importcellref.hpp"
#include "importklst.hpp"
#include "importgame.hpp"
#include "importinfo.hpp"
#include "importdial.hpp"
#include "importques.hpp"
#include "importjour.hpp"
#include "importscpt.hpp"
#include "convertacdt.hpp"
#include "convertnpcc.hpp"
@ -86,25 +93,53 @@ class ConvertNPC : public Converter
public:
virtual void read(ESM::ESMReader &esm)
{
// this is always the player
ESM::NPC npc;
std::string id = esm.getHNString("NAME");
npc.load(esm);
if (id != "player") // seems to occur sometimes, with "chargen X" names
std::cerr << "non-player NPC record: " << id << std::endl;
if (id != "player")
{
// TODO:
// this should handle changes to the NPC struct, but since there is no index here
// it will apply to ALL instances of the class. seems to be the reason for the
// "feature" in MW where changing AI settings of one guard will change it for all guards of that refID.
}
else
{
mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel;
mContext->mPlayerBase = npc;
std::map<const int, float> empty;
// FIXME: player start spells, racial spells and birthsign spells aren't listed here,
// FIXME: player start spells and birthsign spells aren't listed here,
// need to fix openmw to account for this
for (std::vector<std::string>::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it)
mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty;
// Clear the list now that we've written it, this prevents issues cropping up with
// ensureCustomData() in OpenMW tripping over no longer existing spells, where an error would be fatal.
mContext->mPlayerBase.mSpells.mList.clear();
// Same with inventory. Actually it's strange this would contain something, since there's already an
// inventory list in NPCC. There seems to be a fair amount of redundancy in this format.
mContext->mPlayerBase.mInventory.mList.clear();
}
}
};
class ConvertCREA : public Converter
{
public:
virtual void read(ESM::ESMReader &esm)
{
// See comment in ConvertNPC
ESM::Creature creature;
std::string id = esm.getHNString("NAME");
creature.load(esm);
}
};
// Do we need ConvertCONT?
// I've seen a CONT record in a certain save file, but the container contents in it
// were identical to a corresponding CNTC record. See previous comment about redundancy...
class ConvertGlobal : public DefaultConverter<ESM::Global>
{
public:
@ -191,7 +226,28 @@ public:
ESM::NpcStats& npcStats = mContext->mPlayer.mObject.mNpcStats;
convertNpcData(refr.mActorData, npcStats);
mSelectedSpell = refr.mActorData.mSelectedSpell;
if (!refr.mActorData.mSelectedEnchantItem.empty())
{
ESM::InventoryState& invState = mContext->mPlayer.mObject.mInventory;
for (unsigned int i=0; i<invState.mItems.size(); ++i)
{
// FIXME: in case of conflict (multiple items with this refID) use the already equipped one?
if (Misc::StringUtils::ciEqual(invState.mItems[i].mRef.mRefID, refr.mActorData.mSelectedEnchantItem))
invState.mSelectedEnchantItem = i;
}
}
}
virtual void write(ESM::ESMWriter& esm)
{
esm.startRecord(ESM::REC_ASPL);
esm.writeHNString("ID__", mSelectedSpell);
esm.endRecord(ESM::REC_ASPL);
}
private:
std::string mSelectedSpell;
};
class ConvertPCDT : public Converter
@ -329,15 +385,18 @@ public:
{
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"))
while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM"))
{
std::string factionid = esm.getHString();
mFactionStolenItems.insert(std::make_pair(itemid, factionid));
if (esm.retSubName().toString() == "FNAM")
{
std::string factionid = esm.getHString();
mFactionStolenItems.insert(std::make_pair(itemid, factionid));
}
else
{
std::string ownerid = esm.getHString();
mStolenItems.insert(std::make_pair(itemid, ownerid));
}
}
}
private:
@ -345,6 +404,75 @@ private:
std::multimap<std::string, std::string> mFactionStolenItems;
};
/// Seen responses for a dialogue topic?
/// Each DIAL record is followed by a number of INFO records, I believe, just like in ESMs
/// Dialogue conversion problems (probably have to adjust OpenMW format) -
/// - Journal is stored in one continuous HTML markup rather than each entry separately with associated info ID.
/// - Seen dialogue responses only store the INFO id, rather than the fulltext.
/// - Quest stages only store the INFO id, rather than the journal entry fulltext.
class ConvertINFO : public Converter
{
public:
virtual void read(ESM::ESMReader& esm)
{
INFO info;
info.load(esm);
}
};
class ConvertDIAL : public Converter
{
public:
virtual void read(ESM::ESMReader& esm)
{
std::string id = esm.getHNString("NAME");
DIAL dial;
dial.load(esm);
}
};
class ConvertQUES : public Converter
{
public:
virtual void read(ESM::ESMReader& esm)
{
std::string id = esm.getHNString("NAME");
QUES quest;
quest.load(esm);
}
};
class ConvertJOUR : public Converter
{
public:
virtual void read(ESM::ESMReader& esm)
{
JOUR journal;
journal.load(esm);
}
};
class ConvertGAME : public Converter
{
public:
virtual void read(ESM::ESMReader &esm)
{
GAME game;
game.load(esm);
}
};
/// Running global script
class ConvertSCPT : public Converter
{
public:
virtual void read(ESM::ESMReader &esm)
{
SCPT script;
script.load(esm);
}
};
}
#endif

@ -7,16 +7,23 @@ namespace ESSImport
void convertInventory(const Inventory &inventory, ESM::InventoryState &state)
{
int index = 0;
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
objstate.mRef.mCharge = it->mCondition;
state.mItems.push_back(std::make_pair(objstate, -1));
state.mItems.push_back(objstate);
if (it->mRelativeEquipmentSlot != -1)
// Note we should really write the absolute slot here, which we do not know about
// Not a big deal, OpenMW will auto-correct to a valid slot, the only problem is when
// an item could be equipped in two different slots (e.g. equipped two rings)
state.mEquipmentSlots[index] = it->mRelativeEquipmentSlot;
++index;
}
}

@ -0,0 +1,32 @@
#include "convertscri.hpp"
#include <iostream>
namespace
{
template <typename T, ESM::VarType VariantType>
void storeVariables(const std::vector<T>& variables, ESM::Locals& locals, const std::string& scriptname)
{
for (typename std::vector<T>::const_iterator it = variables.begin(); it != variables.end(); ++it)
{
ESM::Variant val(*it);
val.setType(VariantType);
locals.mVariables.push_back(std::make_pair(std::string(), val));
}
}
}
namespace ESSImport
{
void convertSCRI(const SCRI &scri, ESM::Locals &locals)
{
// order *is* important, as we do not have variable names available in this format
storeVariables<short, ESM::VT_Short> (scri.mShorts, locals, scri.mScript);
storeVariables<int, ESM::VT_Int> (scri.mLongs, locals, scri.mScript);
storeVariables<float, ESM::VT_Float> (scri.mFloats, locals, scri.mScript);
}
}

@ -0,0 +1,16 @@
#ifndef OPENMW_ESSIMPORT_CONVERTSCRI_H
#define OPENMW_ESSIMPORT_CONVERTSCRI_H
#include "importscri.hpp"
#include <components/esm/locals.hpp>
namespace ESSImport
{
/// Convert script variable assignments
void convertSCRI (const SCRI& scri, ESM::Locals& locals);
}
#endif

@ -9,18 +9,16 @@ namespace ESSImport
void ActorData::load(ESM::ESMReader &esm)
{
// unsure at which point between NAME and ESM::CellRef
if (esm.isNextSub("MNAM"))
esm.skipHSub();
if (esm.isNextSub("ACTN"))
esm.skipHSub();
if (esm.isNextSub("STPR"))
esm.skipHSub();
ESM::CellRef bla;
bla.ESM::CellRef::loadData(esm);
if (esm.isNextSub("MNAM"))
esm.skipHSub();
ESM::CellRef::loadData(esm);
// FIXME: not all actors have this, add flag
esm.getHNOT(mACDT, "ACDT");
@ -62,15 +60,18 @@ namespace ESSImport
if (esm.isNextSub("PWPS"))
esm.skipHSub();
// unsure at which point between LSTN and CHRD
if (esm.isNextSub("APUD"))
esm.skipHSub(); // 40 bytes, starts with string "ancestor guardian". maybe spellcasting in progress?
if (esm.isNextSub("WNAM"))
{
esm.skipHSub(); // seen values: "ancestor guardian", "bound dagger_en". Summoned creature / bound weapons?
std::string id = esm.getHString();
if (esm.isNextSub("XNAM"))
{
// "demon tanto", probably the ID of spell/item that created the bound weapon/crature?
esm.skipHSub();
}
mSelectedEnchantItem = esm.getHString();
else
mSelectedSpell = id;
if (esm.isNextSub("YNAM"))
esm.skipHSub(); // 4 byte, 0
@ -83,18 +84,7 @@ namespace ESSImport
if (esm.isNextSub("CRED")) // creature only
esm.getHExact(mCombatStats, 3*2*sizeof(int));
mScript = esm.getHNOString("SCRI");
// script variables?
if (!mScript.empty())
{
if (esm.isNextSub("SLCS"))
esm.skipHSub();
if (esm.isNextSub("SLSD")) // Short Data?
esm.skipHSub();
if (esm.isNextSub("SLFD")) // Float Data?
esm.skipHSub();
}
mSCRI.load(esm);
if (esm.isNextSub("ND3D"))
esm.skipHSub();

@ -3,6 +3,10 @@
#include <string>
#include <components/esm/cellref.hpp>
#include "importscri.hpp"
namespace ESM
{
struct ESMReader;
@ -37,7 +41,7 @@ namespace ESSImport
};
#pragma pack(pop)
struct ActorData
struct ActorData : public ESM::CellRef
{
ACDT mACDT;
@ -48,7 +52,10 @@ namespace ESSImport
// to change them ingame
int mCombatStats[3][2];
std::string mScript;
std::string mSelectedSpell;
std::string mSelectedEnchantItem;
SCRI mSCRI;
void load(ESM::ESMReader& esm);
};

@ -7,6 +7,8 @@ namespace ESSImport
void CellRef::load(ESM::ESMReader &esm)
{
blank();
// (FRMR subrecord name is already read by the loop in ConvertCell)
esm.getHT(mRefNum.mIndex); // FRMR
@ -17,25 +19,32 @@ namespace ESSImport
mIndexedRefId = esm.getHNString("NAME");
ActorData::load(esm);
if (esm.isNextSub("LVCR"))
{
// occurs on leveled creature spawner references
// probably some identifier for the the creature that has been spawned?
// probably some identifier for the creature that has been spawned?
unsigned char lvcr;
esm.getHT(lvcr);
//std::cout << "LVCR: " << (int)lvcr << std::endl;
}
mActorData.load(esm);
mEnabled = true;
esm.getHNOT(mEnabled, "ZNAM");
// should occur for all references but not levelled creature spawners
esm.getHNOT(mPos, "DATA", 24);
// i've seen DATA record TWICE on a creature record - and with the exact same content too! weird
// DATA should occur for all references, except leveled creature spawners
// I've seen DATA *twice* on a creature record, and with the exact same content too! weird
// alarmvoi0000.ess
esm.getHNOT(mPos, "DATA", 24);
esm.getHNOT(mPos, "DATA", 24);
mDeleted = 0;
if (esm.isNextSub("DELE"))
{
unsigned int deleted;
esm.getHT(deleted);
mDeleted = (deleted >> 24) & 0x2; // the other 3 bytes seem to be uninitialized garbage
}
if (esm.isNextSub("MVRF"))
{

@ -15,20 +15,16 @@ namespace ESM
namespace ESSImport
{
// Not sure if we can share any code with ESM::CellRef here
struct CellRef
struct CellRef : public ActorData
{
std::string mIndexedRefId;
ESM::RefNum mRefNum;
ActorData mActorData;
ESM::Position mPos;
std::string mScript;
bool mEnabled;
bool mDeleted;
void load(ESM::ESMReader& esm);
};

@ -14,6 +14,11 @@ namespace ESSImport
float scale;
esm.getHNOT(scale, "XSCL");
// FIXME: use AiPackageList, need to fix getSubName()
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|| esm.isNextSub("AI_A"))
esm.skipHSub();
mInventory.load(esm);
}

@ -0,0 +1,23 @@
#include "importdial.hpp"
#include <components/esm/esmreader.hpp>
namespace ESSImport
{
void DIAL::load(ESM::ESMReader &esm)
{
// See ESM::Dialogue::Type enum, not sure why we would need this here though
int type = 0;
esm.getHNOT(type, "DATA");
// Deleted dialogue in a savefile. No clue what this means...
int deleted = 0;
esm.getHNOT(deleted, "DELE");
mIndex = 0;
// *should* always occur except when the dialogue is deleted, but leaving it optional just in case...
esm.getHNOT(mIndex, "XIDX");
}
}

@ -0,0 +1,20 @@
#ifndef OPENMW_ESSIMPORT_IMPORTDIAL_H
#define OPENMW_ESSIMPORT_IMPORTDIAL_H
namespace ESM
{
struct ESMReader;
}
namespace ESSImport
{
struct DIAL
{
int mIndex; // Journal index
void load(ESM::ESMReader& esm);
};
}
#endif

@ -105,6 +105,7 @@ namespace ESSImport
blacklist.insert(std::make_pair("REFR", "DATA")); // player position
blacklist.insert(std::make_pair("CELL", "NAM8")); // fog of war
blacklist.insert(std::make_pair("GAME", "GMDT")); // weather data, current time always changes
blacklist.insert(std::make_pair("CELL", "DELE")); // first 3 bytes are uninitialized
// this changes way too often, name suggests some renderer internal data?
blacklist.insert(std::make_pair("CELL", "ND3D"));
@ -122,7 +123,7 @@ namespace ESSImport
if (i >= file2.mRecords.size())
{
std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset;
std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl;
return;
}
@ -141,7 +142,7 @@ namespace ESSImport
if (j >= rec2.mSubrecords.size())
{
std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset;
std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl;
return;
}
@ -201,11 +202,14 @@ namespace ESSImport
const unsigned int recFMAP = ESM::FourCC<'F','M','A','P'>::value;
const unsigned int recKLST = ESM::FourCC<'K','L','S','T'>::value;
const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value;
const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value;
const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value;
std::map<unsigned int, boost::shared_ptr<Converter> > converters;
converters[ESM::REC_GLOB] = boost::shared_ptr<Converter>(new ConvertGlobal());
converters[ESM::REC_BOOK] = boost::shared_ptr<Converter>(new ConvertBook());
converters[ESM::REC_NPC_] = boost::shared_ptr<Converter>(new ConvertNPC());
converters[ESM::REC_CREA] = boost::shared_ptr<Converter>(new ConvertCREA());
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());
@ -213,6 +217,7 @@ namespace ESSImport
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[recGAME ] = boost::shared_ptr<Converter>(new ConvertGAME());
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());
@ -226,6 +231,17 @@ namespace ESSImport
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());
converters[ESM::REC_INFO] = boost::shared_ptr<Converter>(new ConvertINFO());
converters[ESM::REC_DIAL] = boost::shared_ptr<Converter>(new ConvertDIAL());
converters[ESM::REC_QUES] = boost::shared_ptr<Converter>(new ConvertQUES());
converters[recJOUR ] = boost::shared_ptr<Converter>(new ConvertJOUR());
converters[ESM::REC_SCPT] = boost::shared_ptr<Converter>(new ConvertSCPT());
// TODO:
// - REGN (weather in certain regions?)
// - VFXM
// - SPLM (active spell effects)
// - PROJ (magic projectiles in air)
std::set<unsigned int> unknownRecords;
@ -248,7 +264,7 @@ namespace ESSImport
else
{
if (unknownRecords.insert(n.val).second)
std::cerr << "unknown record " << n.toString() << std::endl;
std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
esm.skipRecord();
}

@ -6,6 +6,7 @@
#include <components/esm/loadnpc.hpp>
#include <components/esm/player.hpp>
#include <components/esm/dialoguestate.hpp>
#include <components/esm/globalmap.hpp>
#include "importnpcc.hpp"
#include "importcrec.hpp"
@ -28,6 +29,8 @@ namespace ESSImport
ESM::DialogueState mDialogueState;
ESM::GlobalMap mGlobalMapState;
int mDay, mMonth, mYear;
float mHour;
@ -48,6 +51,11 @@ namespace ESSImport
mPlayer.mCurrentCrimeId = 0; // TODO
mPlayer.mObject.blank();
mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame
mGlobalMapState.mBounds.mMinX = 0;
mGlobalMapState.mBounds.mMaxX = 0;
mGlobalMapState.mBounds.mMinY = 0;
mGlobalMapState.mBounds.mMaxY = 0;
}
};

@ -0,0 +1,13 @@
#include "importgame.hpp"
#include <components/esm/esmreader.hpp>
namespace ESSImport
{
void GAME::load(ESM::ESMReader &esm)
{
esm.getHNT(mGMDT, "GMDT");
}
}

@ -0,0 +1,33 @@
#ifndef OPENMW_ESSIMPORT_GAME_H
#define OPENMW_ESSIMPORT_GAME_H
namespace ESM
{
class ESMReader;
}
namespace ESSImport
{
/// Weather data
struct GAME
{
struct GMDT
{
char mCellName[64];
int mFogColour;
float mFogDensity;
int mCurrentWeather, mNextWeather;
int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage
float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition
int masserPhase, secundaPhase; // top 3 bytes may be garbage
};
GMDT mGMDT;
void load(ESM::ESMReader& esm);
};
}
#endif

@ -0,0 +1,14 @@
#include "importinfo.hpp"
#include <components/esm/esmreader.hpp>
namespace ESSImport
{
void INFO::load(ESM::ESMReader &esm)
{
mInfo = esm.getHNString("INAM");
mActorRefId = esm.getHNString("ACDT");
}
}

@ -0,0 +1,24 @@
#ifndef OPENMW_ESSIMPORT_IMPORTINFO_H
#define OPENMW_ESSIMPORT_IMPORTINFO_H
#include <string>
namespace ESM
{
struct ESMReader;
}
namespace ESSImport
{
struct INFO
{
std::string mInfo;
std::string mActorRefId;
void load(ESM::ESMReader& esm);
};
}
#endif

@ -1,5 +1,7 @@
#include "importinventory.hpp"
#include <stdexcept>
#include <components/esm/esmreader.hpp>
#include <components/esm/loadcont.hpp>
@ -17,6 +19,7 @@ namespace ESSImport
InventoryItem item;
item.mId = contItem.mItem.toString();
item.mCount = contItem.mCount;
item.mRelativeEquipmentSlot = -1;
// seems that a stack of items can have a set of subrecords for each item? rings0000.ess
// doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place?
@ -26,25 +29,14 @@ namespace ESSImport
if (esm.isNextSub("XIDX")) // index in the stack?
esm.skipHSub();
std::string script = esm.getHNOString("SCRI");
// script variables?
// unsure if before or after ESM::CellRef
if (!script.empty())
{
if (esm.isNextSub("SLCS"))
esm.skipHSub();
if (esm.isNextSub("SLSD")) // Short Data?
esm.skipHSub();
if (esm.isNextSub("SLFD")) // Float Data?
esm.skipHSub();
}
item.mSCRI.load(esm);
// for XSOL and XCHG seen so far, but probably others too
item.ESM::CellRef::loadData(esm);
item.mCondition = -1;
// FIXME: for Lights, this is actually a float
esm.getHNOT(item.mCondition, "XHLT");
int charge=-1;
esm.getHNOT(charge, "XHLT");
item.mChargeInt = charge;
}
mItems.push_back(item);
@ -55,14 +47,21 @@ namespace ESSImport
{
// note: same item can be equipped 2 items (e.g. 2 rings)
// and will be *stacked* in the NPCO list, unlike openmw!
// this is currently not handled properly.
esm.getSubHeader();
int itemIndex; // index of the item in the NPCO list
esm.getT(itemIndex);
if (itemIndex < 0 || itemIndex >= int(mItems.size()))
esm.fail("equipment item index out of range");
// appears to be a relative index for only the *possible* slots this item can be equipped in,
// i.e. 0 most of the time, unlike openmw slot enum index
// i.e. 0 most of the time
int slotIndex;
esm.getT(slotIndex);
mItems[itemIndex].mRelativeEquipmentSlot = slotIndex;
}
}

@ -5,6 +5,7 @@
#include <string>
#include <components/esm/cellref.hpp>
#include "importscri.hpp"
namespace ESM
{
@ -20,7 +21,8 @@ namespace ESSImport
{
std::string mId;
int mCount;
int mCondition;
int mRelativeEquipmentSlot;
SCRI mSCRI;
};
std::vector<InventoryItem> mItems;

@ -0,0 +1,13 @@
#include "importjour.hpp"
#include <components/esm/esmreader.hpp>
namespace ESSImport
{
void JOUR::load(ESM::ESMReader &esm)
{
mText = esm.getHNString("NAME");
}
}

@ -0,0 +1,25 @@
#ifndef OPENMW_ESSIMPORT_IMPORTJOUR_H
#define OPENMW_ESSIMPORT_IMPORTJOUR_H
#include <string>
namespace ESM
{
struct ESMReader;
}
namespace ESSImport
{
/// Journal
struct JOUR
{
// The entire journal, in HTML
std::string mText;
void load(ESM::ESMReader& esm);
};
}
#endif

@ -9,11 +9,9 @@ namespace ESSImport
{
esm.getHNT(mNPDT, "NPDT");
if (esm.isNextSub("AI_E"))
esm.skipHSub();
if (esm.isNextSub("AI_T"))
esm.skipHSub();
if (esm.isNextSub("AI_F"))
// FIXME: use AiPackageList, need to fix getSubName()
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|| esm.isNextSub("AI_A"))
esm.skipHSub();
mInventory.load(esm);

@ -23,6 +23,10 @@ namespace ESSImport
mKnownDialogueTopics.push_back(esm.getHString());
}
if (esm.isNextSub("MNAM"))
esm.skipHSub(); // If this field is here it seems to specify the interior cell the player is in,
// but it's not always here, so it's kinda useless
esm.getHNT(mPNAM, "PNAM");
if (esm.isNextSub("SNAM"))
@ -59,8 +63,11 @@ namespace ESSImport
mFactions.push_back(fnam);
}
if (esm.isNextSub("AADT"))
esm.skipHSub(); // 44 bytes, no clue
if (esm.isNextSub("KNAM"))
esm.skipHSub();
esm.skipHSub(); // assigned Quick Keys, I think
if (esm.isNextSub("WERE"))
{
@ -69,6 +76,10 @@ namespace ESSImport
esm.getSubHeader();
esm.skip(152);
}
// unsure if before or after WERE
if (esm.isNextSub("ANIS"))
esm.skipHSub();
}
}

@ -0,0 +1,14 @@
#include "importques.hpp"
#include <components/esm/esmreader.hpp>
namespace ESSImport
{
void QUES::load(ESM::ESMReader &esm)
{
while (esm.isNextSub("DATA"))
mInfo.push_back(esm.getHString());
}
}

@ -0,0 +1,28 @@
#ifndef OPENMW_ESSIMPORT_IMPORTQUES_H
#define OPENMW_ESSIMPORT_IMPORTQUES_H
#include <string>
#include <vector>
namespace ESM
{
struct ESMReader;
}
namespace ESSImport
{
/// State for a quest
/// Presumably this record only exists when Tribunal is installed,
/// since pre-Tribunal there weren't any quest names in the data files.
struct QUES
{
std::string mName; // NAME, should be assigned from outside as usual
std::vector<std::string> mInfo; // list of journal entries for the quest
void load(ESM::ESMReader& esm);
};
}
#endif

@ -0,0 +1,20 @@
#include "importscpt.hpp"
#include <components/esm/esmreader.hpp>
namespace ESSImport
{
void SCPT::load(ESM::ESMReader &esm)
{
esm.getHNT(mSCHD, "SCHD");
mSCRI.load(esm);
mRNAM = -1;
esm.getHNOT(mRNAM, "RNAM");
}
}

@ -0,0 +1,32 @@
#ifndef OPENMW_ESSIMPORT_IMPORTSCPT_H
#define OPENMW_ESSIMPORT_IMPORTSCPT_H
#include "importscri.hpp"
#include <components/esm/loadscpt.hpp>
namespace ESM
{
class ESMReader;
}
namespace ESSImport
{
// A running global script
// TODO: test how targeted scripts are saved
struct SCPT
{
ESM::Script::SCHD mSCHD;
// values of local variables
SCRI mSCRI;
int mRNAM; // unknown, seems to be -1 for some scripts, some huge integer for others
void load(ESM::ESMReader& esm);
};
}
#endif

@ -0,0 +1,55 @@
#include "importscri.hpp"
#include <components/esm/esmreader.hpp>
namespace ESSImport
{
void SCRI::load(ESM::ESMReader &esm)
{
mScript = esm.getHNOString("SCRI");
int numShorts = 0, numLongs = 0, numFloats = 0;
if (esm.isNextSub("SLCS"))
{
esm.getSubHeader();
esm.getT(numShorts);
esm.getT(numLongs);
esm.getT(numFloats);
}
if (esm.isNextSub("SLSD"))
{
esm.getSubHeader();
for (int i=0; i<numShorts; ++i)
{
short val;
esm.getT(val);
mShorts.push_back(val);
}
}
// I haven't seen Longs in a save file yet, but SLLD would make sense for the name
// TODO: test this
if (esm.isNextSub("SLLD"))
{
esm.getSubHeader();
for (int i=0; i<numLongs; ++i)
{
int val;
esm.getT(val);
mLongs.push_back(val);
}
}
if (esm.isNextSub("SLFD"))
{
esm.getSubHeader();
for (int i=0; i<numFloats; ++i)
{
float val;
esm.getT(val);
mFloats.push_back(val);
}
}
}
}

@ -0,0 +1,30 @@
#ifndef OPENMW_ESSIMPORT_IMPORTSCRI_H
#define OPENMW_ESSIMPORT_IMPORTSCRI_H
#include <components/esm/variant.hpp>
#include <vector>
namespace ESM
{
class ESMReader;
}
namespace ESSImport
{
/// Local variable assigments for a running script
struct SCRI
{
std::string mScript;
std::vector<short> mShorts;
std::vector<int> mLongs;
std::vector<float> mFloats;
void load(ESM::ESMReader& esm);
};
}
#endif

@ -12,7 +12,7 @@ namespace bfs = boost::filesystem;
int main(int argc, const char** argv)
int main(int argc, char** argv)
{
try
{
@ -50,7 +50,15 @@ int main(int argc, const char** argv)
if (vm.count("compare"))
importer.compare();
else
{
const std::string& ext = ".omwsave";
if (boost::filesystem::exists(boost::filesystem::path(outputFile))
&& (outputFile.size() < ext.size() || outputFile.substr(outputFile.size()-ext.size()) != ext))
{
throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?");
}
importer.run();
}
}
catch (std::exception& e)
{

@ -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);
}

@ -69,7 +69,7 @@ namespace MWBase
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0;
/// Changes faction1's opinion of faction2 by \a diff.
virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0;

@ -92,7 +92,7 @@ namespace MWBase
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0;
};
}

@ -193,7 +193,7 @@ namespace MWBase
virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0;
virtual void clear() = 0;

@ -310,7 +310,7 @@ namespace MWBase
virtual void clear() = 0;
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
virtual void readRecord (ESM::ESMReader& reader, uint32_t type) = 0;
virtual int countSavedGameRecords() const = 0;
/// Does the current stack of GUI-windows permit saving?

@ -108,7 +108,7 @@ namespace MWBase
virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
virtual void readRecord (ESM::ESMReader& reader, uint32_t type,
const std::map<int, int>& contentFileMap) = 0;
virtual MWWorld::CellStore *getExterior (int x, int y) = 0;

@ -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,22 +254,6 @@ namespace MWClass
return std::make_pair(1,"");
}
void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
const
{
ensureCustomData (ptr);
dynamic_cast<LightCustomData&> (*ptr.getRefData().getCustomData()).mTime = state.mTime;
}
void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
const
{
ensureCustomData (ptr);
state.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;
};
}

@ -647,7 +647,7 @@ namespace MWDialogue
writer.endRecord (ESM::REC_DIAS);
}
void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type)
void DialogueManager::readRecord (ESM::ESMReader& reader, uint32_t type)
{
if (type==ESM::REC_DIAS)
{

@ -92,7 +92,7 @@ namespace MWDialogue
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
virtual void readRecord (ESM::ESMReader& reader, uint32_t type);
/// Changes faction1's opinion of faction2 by \a diff.
virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff);

@ -227,9 +227,9 @@ namespace MWDialogue
}
}
void Journal::readRecord (ESM::ESMReader& reader, int32_t type)
void Journal::readRecord (ESM::ESMReader& reader, uint32_t type)
{
if (type==ESM::REC_JOUR)
if (type==ESM::REC_JOUR || type==ESM::REC_JOUR_LEGACY)
{
ESM::JournalEntry record;
record.load (reader);

@ -71,7 +71,7 @@ namespace MWDialogue
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
virtual void readRecord (ESM::ESMReader& reader, uint32_t type);
};
}

@ -886,7 +886,7 @@ namespace MWGui
writer.endRecord(ESM::REC_GMAP);
}
void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type)
void MapWindow::readRecord(ESM::ESMReader &reader, uint32_t type)
{
if (type == ESM::REC_GMAP)
{

@ -177,7 +177,7 @@ namespace MWGui
void clear();
void write (ESM::ESMWriter& writer, Loading::Listener& progress);
void readRecord (ESM::ESMReader& reader, int32_t type);
void readRecord (ESM::ESMReader& reader, uint32_t type);
private:
void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);

@ -431,7 +431,7 @@ namespace MWGui
writer.endRecord(ESM::REC_KEYS);
}
void QuickKeysMenu::readRecord(ESM::ESMReader &reader, int32_t type)
void QuickKeysMenu::readRecord(ESM::ESMReader &reader, uint32_t type)
{
if (type != ESM::REC_KEYS)
return;

@ -47,7 +47,7 @@ namespace MWGui
void write (ESM::ESMWriter& writer);
void readRecord (ESM::ESMReader& reader, int32_t type);
void readRecord (ESM::ESMReader& reader, uint32_t type);
void clear();

@ -1620,7 +1620,7 @@ namespace MWGui
}
}
void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type)
void WindowManager::readRecord(ESM::ESMReader &reader, uint32_t type)
{
if (type == ESM::REC_GMAP)
mMap->readRecord(reader, type);

@ -306,7 +306,7 @@ namespace MWGui
virtual void clear();
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress);
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
virtual void readRecord (ESM::ESMReader& reader, uint32_t type);
virtual int countSavedGameRecords() const;
/// Does the current stack of GUI-windows permit saving?

@ -1468,7 +1468,7 @@ namespace MWMechanics
writer.endRecord(ESM::REC_DCOU);
}
void Actors::readRecord (ESM::ESMReader& reader, int32_t type)
void Actors::readRecord (ESM::ESMReader& reader, uint32_t type)
{
if (type == ESM::REC_DCOU)
{

@ -128,7 +128,7 @@ namespace MWMechanics
void write (ESM::ESMWriter& writer, Loading::Listener& listener) const;
void readRecord (ESM::ESMReader& reader, int32_t type);
void readRecord (ESM::ESMReader& reader, uint32_t type);
void clear(); // Clear death counter

@ -1360,7 +1360,7 @@ namespace MWMechanics
mActors.write(writer, listener);
}
void MechanicsManager::readRecord(ESM::ESMReader &reader, int32_t type)
void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type)
{
mActors.readRecord(reader, type);
}

@ -158,7 +158,7 @@ namespace MWMechanics
virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const;
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
virtual void readRecord (ESM::ESMReader& reader, uint32_t type);
virtual void clear();

@ -472,9 +472,7 @@ namespace MWMechanics
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
// Re-casting a summon effect will remove the creature from previous castings of that effect.
if (effectIt->mEffectID >= ESM::MagicEffect::SummonScamp
&& effectIt->mEffectID <= ESM::MagicEffect::SummonStormAtronach
&& !target.isEmpty() && target.getClass().isActor())
if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor())
{
CreatureStats& targetStats = target.getClass().getCreatureStats(target);
std::map<CreatureStats::SummonKey, int>::iterator found = targetStats.getSummonedCreatureMap().find(std::make_pair(effectIt->mEffectID, mId));
@ -956,4 +954,13 @@ namespace MWMechanics
return static_cast<int>((result < 1) ? 1 : result);
}
bool isSummoningEffect(int effectId)
{
return ((effectId >= ESM::MagicEffect::SummonScamp
&& effectId <= ESM::MagicEffect::SummonStormAtronach)
|| effectId == ESM::MagicEffect::SummonCenturionSphere
|| (effectId >= ESM::MagicEffect::SummonFabricant
&& effectId <= ESM::MagicEffect::SummonCreature05));
}
}

@ -22,6 +22,8 @@ namespace MWMechanics
ESM::Skill::SkillEnum spellSchoolToSkill(int school);
bool isSummoningEffect(int effectId);
/**
* @param spell spell to cast
* @param actor calculate spell success chance for this actor (depends on actor's skills)

@ -312,21 +312,17 @@ namespace MWMechanics
void Spells::readState(const ESM::SpellState &state)
{
mSpells = state.mSpells;
mSelectedSpell = state.mSelectedSpell;
// Discard spells that are no longer available due to changed content files
for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();)
for (TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it)
{
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(iter->first);
if (!spell)
// Discard spells that are no longer available due to changed content files
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(it->first);
if (spell)
{
if (iter->first == mSelectedSpell)
mSelectedSpell = "";
mSpells.erase(iter++);
mSpells[it->first] = it->second;
if (it->first == state.mSelectedSpell)
mSelectedSpell = it->first;
}
else
++iter;
}
// No need to discard spells here (doesn't really matter if non existent ids are kept)

@ -5,6 +5,8 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/manualref.hpp"
@ -51,8 +53,7 @@ namespace MWMechanics
void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime)
{
if (key.mId >= ESM::MagicEffect::SummonScamp
&& key.mId <= ESM::MagicEffect::SummonStormAtronach && magnitude > 0)
if (isSummoningEffect(key.mId) && magnitude > 0)
{
mActiveEffects.insert(std::make_pair(key.mId, sourceId));
}

@ -263,17 +263,27 @@ void NpcAnimation::updateNpcBase()
}
else
{
if (isVampire)
mHeadModel = "";
if (isVampire) // FIXME: fall back to regular head when getVampireHead fails?
mHeadModel = getVampireHead(mNpc->mRace, mNpc->mFlags & ESM::NPC::Female);
else if (!mNpc->mHead.empty())
mHeadModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHead)->mModel;
else
mHeadModel = "";
{
const ESM::BodyPart* bp = store.get<ESM::BodyPart>().search(mNpc->mHead);
if (bp)
mHeadModel = "meshes\\" + bp->mModel;
else
std::cerr << "Failed to load body part '" << mNpc->mHead << "'" << std::endl;
}
mHairModel = "";
if (!mNpc->mHair.empty())
mHairModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHair)->mModel;
else
mHairModel = "";
{
const ESM::BodyPart* bp = store.get<ESM::BodyPart>().search(mNpc->mHair);
if (bp)
mHairModel = "meshes\\" + bp->mModel;
else
std::cerr << "Failed to load body part '" << mNpc->mHair << "'" << std::endl;
}
}
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
@ -801,6 +811,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm))
bodypart = NULL;
}
else if (!bodypart)
std::cerr << "Failed to find body part '" << part->mFemale << "'" << std::endl;
}
if(!bodypart && !part->mMale.empty())
{
@ -814,6 +826,8 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm))
bodypart = NULL;
}
else if (!bodypart)
std::cerr << "Failed to find body part '" << part->mMale << "'" << std::endl;
}
if(bodypart)

@ -443,5 +443,6 @@ op 0x20002fc: RemoveFromLevCreature
op 0x20002fd: AddToLevItem
op 0x20002fe: RemoveFromLevItem
op 0x20002ff: SetFactionReaction
op 0x2000300: EnableLevelupMenu
opcodes 0x2000300-0x3ffffff unused
opcodes 0x2000301-0x3ffffff unused

@ -145,7 +145,7 @@ namespace MWScript
}
}
bool GlobalScripts::readRecord (ESM::ESMReader& reader, int32_t type)
bool GlobalScripts::readRecord (ESM::ESMReader& reader, uint32_t type)
{
if (type==ESM::REC_GSCR)
{

@ -62,7 +62,7 @@ namespace MWScript
void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
bool readRecord (ESM::ESMReader& reader, int32_t type);
bool readRecord (ESM::ESMReader& reader, uint32_t type);
///< Records for variables that do not exist are dropped silently.
///
/// \return Known type?

@ -231,6 +231,8 @@ namespace MWScript
new OpShowDialogue (MWGui::GM_Race));
interpreter.installSegment5 (Compiler::Gui::opcodeEnableStatsReviewMenu,
new OpShowDialogue (MWGui::GM_Review));
interpreter.installSegment5 (Compiler::Gui::opcodeEnableLevelupMenu,
new OpShowDialogue (MWGui::GM_Levelup));
interpreter.installSegment5 (Compiler::Gui::opcodeEnableInventoryMenu,
new OpEnableWindow (MWGui::GW_Inventory));

@ -10,6 +10,8 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/scriptmanager.hpp"
#include <iostream>
namespace MWScript
{
void Locals::configure (const ESM::Script& script)
@ -124,27 +126,60 @@ namespace MWScript
const Compiler::Locals& declarations =
MWBase::Environment::get().getScriptManager()->getLocals(script);
for (std::vector<std::pair<std::string, ESM::Variant> >::const_iterator iter
= locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter)
int index = 0, numshorts = 0, numlongs = 0;
for (unsigned int v=0; v<locals.mVariables.size();++v)
{
char type = declarations.getType (iter->first);
char index = declarations.getIndex (iter->first);
ESM::VarType type = locals.mVariables[v].second.getType();
if (type == ESM::VT_Short)
++numshorts;
else if (type == ESM::VT_Int)
++numlongs;
}
try
for (std::vector<std::pair<std::string, ESM::Variant> >::const_iterator iter
= locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter,++index)
{
if (iter->first.empty())
{
switch (type)
// no variable names available (this will happen for legacy, i.e. ESS-imported savegames only)
try
{
case 's': mShorts.at (index) = iter->second.getInteger(); break;
case 'l': mLongs.at (index) = iter->second.getInteger(); break;
case 'f': mFloats.at (index) = iter->second.getFloat(); break;
// silently ignore locals that don't exist anymore
if (index >= numshorts+numlongs)
mFloats.at(index - (numshorts+numlongs)) = iter->second.getFloat();
else if (index >= numshorts)
mLongs.at(index - numshorts) = iter->second.getInteger();
else
mShorts.at(index) = iter->second.getInteger();
}
catch (std::exception& e)
{
std::cerr << "Failed to read local variable state for script '"
<< script << "' (legacy format): " << e.what()
<< "\nNum shorts: " << numshorts << " / " << mShorts.size()
<< " Num longs: " << numlongs << " / " << mLongs.size() << std::endl;
}
}
catch (...)
else
{
// ignore type changes
/// \todo write to log
char type = declarations.getType (iter->first);
char index = declarations.getIndex (iter->first);
try
{
switch (type)
{
case 's': mShorts.at (index) = iter->second.getInteger(); break;
case 'l': mLongs.at (index) = iter->second.getInteger(); break;
case 'f': mFloats.at (index) = iter->second.getFloat(); break;
// silently ignore locals that don't exist anymore
}
}
catch (...)
{
// ignore type changes
/// \todo write to log
}
}
}
}

@ -368,6 +368,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
break;
case ESM::REC_JOUR:
case ESM::REC_JOUR_LEGACY:
case ESM::REC_QUES:
MWBase::Environment::get().getJournal()->readRecord (reader, n.val);

@ -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;

@ -299,7 +299,7 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress)
}
}
bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type,
bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
const std::map<int, int>& contentFileMap)
{
if (type==ESM::REC_CSTA)

@ -76,7 +76,7 @@ namespace MWWorld
void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
bool readRecord (ESM::ESMReader& reader, int32_t type,
bool readRecord (ESM::ESMReader& reader, uint32_t type,
const std::map<int, int>& contentFileMap);
};
}

@ -466,7 +466,7 @@ namespace MWWorld
// List moved references, from separately tracked list.
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
{
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it);
const ESM::CellRef &ref = *it;
mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID));
}

@ -79,6 +79,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState (CellRefList<T
return ContainerStoreIterator (this, --collection.mList.end());
}
void MWWorld::ContainerStore::storeEquipmentState(const MWWorld::LiveCellRefBase &ref, int index, ESM::InventoryState &inventory) const
{
}
void MWWorld::ContainerStore::readEquipmentState(const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState &inventory)
{
}
template<typename T>
void MWWorld::ContainerStore::storeState (const LiveCellRef<T>& ref, ESM::ObjectState& state) const
{
@ -86,8 +94,8 @@ void MWWorld::ContainerStore::storeState (const LiveCellRef<T>& ref, ESM::Object
}
template<typename T>
void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection,
std::vector<std::pair<ESM::ObjectState, int> >& states, bool equipable) const
void MWWorld::ContainerStore::storeStates (CellRefList<T>& collection,
ESM::InventoryState& inventory, int& index, bool equipable) const
{
for (typename CellRefList<T>::List::const_iterator iter (collection.mList.begin());
iter!=collection.mList.end(); ++iter)
@ -96,18 +104,13 @@ void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection,
continue;
ESM::ObjectState state;
storeState (*iter, state);
int slot = equipable ? getSlot (*iter) : -1;
states.push_back (std::make_pair (state, slot));
if (equipable)
storeEquipmentState(*iter, index, inventory);
inventory.mItems.push_back (state);
++index;
}
}
int MWWorld::ContainerStore::getSlot (const MWWorld::LiveCellRefBase& ref) const
{
return -1;
}
void MWWorld::ContainerStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot) {}
const std::string MWWorld::ContainerStore::sGoldId = "gold_001";
MWWorld::ContainerStore::ContainerStore() : mCachedWeight (0), mWeightUpToDate (false) {}
@ -641,62 +644,66 @@ 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();
storeStates (potions, state.mItems);
storeStates (appas, state.mItems);
storeStates (armors, state.mItems, true);
storeStates (books, state.mItems);
storeStates (clothes, state.mItems, true);
storeStates (ingreds, state.mItems);
storeStates (lockpicks, state.mItems, true);
storeStates (miscItems, state.mItems);
storeStates (probes, state.mItems, true);
storeStates (repairs, state.mItems);
storeStates (weapons, state.mItems, true);
storeStates (lights, state.mItems, true);
int index = 0;
storeStates (potions, state, index);
storeStates (appas, state, index);
storeStates (armors, state, index, true);
storeStates (books, state, index, true); // not equipable as such, but for selectedEnchantItem
storeStates (clothes, state, index, true);
storeStates (ingreds, state, index);
storeStates (lockpicks, state, index, true);
storeStates (miscItems, state, index);
storeStates (probes, state, index, true);
storeStates (repairs, state, index);
storeStates (weapons, state, index, true);
storeStates (lights, state, index, true);
state.mLevelledItemMap = mLevelledItemMap;
}
void MWWorld::ContainerStore::readState (const ESM::InventoryState& state)
void MWWorld::ContainerStore::readState (const ESM::InventoryState& inventory)
{
clear();
for (std::vector<std::pair<ESM::ObjectState, int> >::const_iterator
iter (state.mItems.begin()); iter!=state.mItems.end(); ++iter)
int index = 0;
for (std::vector<ESM::ObjectState>::const_iterator
iter (inventory.mItems.begin()); iter!=inventory.mItems.end(); ++iter)
{
int slot = iter->second;
const ESM::ObjectState& state = iter->first;
const ESM::ObjectState& state = *iter;
int type = MWBase::Environment::get().getWorld()->getStore().find(state.mRef.mRefID);
int thisIndex = index++;
switch (type)
{
case ESM::REC_ALCH: getState (potions, iter->first); break;
case ESM::REC_APPA: getState (appas, iter->first); break;
case ESM::REC_ARMO: setSlot (getState (armors, iter->first), slot); break;
case ESM::REC_BOOK: getState (books, iter->first); break;
case ESM::REC_CLOT: setSlot (getState (clothes, iter->first), slot); break;
case ESM::REC_INGR: getState (ingreds, iter->first); break;
case ESM::REC_LOCK: setSlot (getState (lockpicks, iter->first), slot); break;
case ESM::REC_MISC: getState (miscItems, iter->first); break;
case ESM::REC_PROB: setSlot (getState (probes, iter->first), slot); break;
case ESM::REC_REPA: getState (repairs, iter->first); break;
case ESM::REC_WEAP: setSlot (getState (weapons, iter->first), slot); break;
case ESM::REC_LIGH: setSlot (getState (lights, iter->first), slot); break;
case ESM::REC_ALCH: getState (potions, state); break;
case ESM::REC_APPA: getState (appas, state); break;
case ESM::REC_ARMO: readEquipmentState (getState (armors, state), thisIndex, inventory); break;
case ESM::REC_BOOK: readEquipmentState (getState (books, state), thisIndex, inventory); break; // not equipable as such, but for selectedEnchantItem
case ESM::REC_CLOT: readEquipmentState (getState (clothes, state), thisIndex, inventory); break;
case ESM::REC_INGR: getState (ingreds, state); break;
case ESM::REC_LOCK: readEquipmentState (getState (lockpicks, state), thisIndex, inventory); break;
case ESM::REC_MISC: getState (miscItems, state); break;
case ESM::REC_PROB: readEquipmentState (getState (probes, state), thisIndex, inventory); break;
case ESM::REC_REPA: getState (repairs, state); break;
case ESM::REC_WEAP: readEquipmentState (getState (weapons, state), thisIndex, inventory); break;
case ESM::REC_LIGH: readEquipmentState (getState (lights, state), thisIndex, inventory); break;
case 0:
std::cerr << "Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl;
break;
default:
std::cerr << "invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl;
std::cerr << "Invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl;
break;
}
}
mLevelledItemMap = state.mLevelledItemMap;
mLevelledItemMap = inventory.mLevelledItemMap;
}

@ -85,16 +85,13 @@ namespace MWWorld
void storeState (const LiveCellRef<T>& ref, ESM::ObjectState& state) const;
template<typename T>
void storeStates (const CellRefList<T>& collection,
std::vector<std::pair<ESM::ObjectState, int> >& states,
void storeStates (CellRefList<T>& collection,
ESM::InventoryState& inventory, int& index,
bool equipable = false) const;
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const;
///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot).
virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot);
///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1.
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory);
public:
ContainerStore();
@ -171,7 +168,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);

@ -175,7 +175,7 @@ void ESMStore::setUp()
mCreatureLists.write (writer, progress);
}
bool ESMStore::readRecord (ESM::ESMReader& reader, int32_t type)
bool ESMStore::readRecord (ESM::ESMReader& reader, uint32_t type)
{
switch (type)
{

@ -233,7 +233,7 @@ namespace MWWorld
void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
bool readRecord (ESM::ESMReader& reader, int32_t type);
bool readRecord (ESM::ESMReader& reader, uint32_t type);
///< \return Known type?
};

@ -88,7 +88,7 @@ namespace MWWorld
}
}
bool Globals::readRecord (ESM::ESMReader& reader, int32_t type)
bool Globals::readRecord (ESM::ESMReader& reader, uint32_t type)
{
if (type==ESM::REC_GLOB)
{

@ -53,7 +53,7 @@ namespace MWWorld
void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
bool readRecord (ESM::ESMReader& reader, int32_t type);
bool readRecord (ESM::ESMReader& reader, uint32_t type);
///< Records for variables that do not exist are dropped silently.
///
/// \return Known type?

@ -49,19 +49,47 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots_)
slots_.push_back (end());
}
int MWWorld::InventoryStore::getSlot (const MWWorld::LiveCellRefBase& ref) const
void MWWorld::InventoryStore::storeEquipmentState(const MWWorld::LiveCellRefBase &ref, int index, ESM::InventoryState &inventory) const
{
for (int i = 0; i<static_cast<int> (mSlots.size()); ++i)
if (mSlots[i].getType()!=-1 && mSlots[i]->getBase()==&ref)
return i;
{
inventory.mEquipmentSlots[index] = i;
}
return -1;
if (mSelectedEnchantItem.getType()!=-1 && mSelectedEnchantItem->getBase() == &ref)
inventory.mSelectedEnchantItem = index;
}
void MWWorld::InventoryStore::setSlot (const MWWorld::ContainerStoreIterator& iter, int slot)
void MWWorld::InventoryStore::readEquipmentState(const MWWorld::ContainerStoreIterator &iter, int index, const ESM::InventoryState &inventory)
{
if (iter!=end() && slot>=0 && slot<Slots)
mSlots[slot] = iter;
if (index == inventory.mSelectedEnchantItem)
mSelectedEnchantItem = iter;
std::map<int, int>::const_iterator found = inventory.mEquipmentSlots.find(index);
if (found != inventory.mEquipmentSlots.end())
{
if (found->second < 0 || found->second >= MWWorld::InventoryStore::Slots)
throw std::runtime_error("Invalid slot index in inventory state");
// make sure the item can actually be equipped in this slot
int slot = found->second;
std::pair<std::vector<int>, bool> allowedSlots = iter->getClass().getEquipmentSlots(*iter);
if (!allowedSlots.first.size())
return;
if (std::find(allowedSlots.first.begin(), allowedSlots.first.end(), slot) == allowedSlots.first.end())
slot = allowedSlots.first.front();
// unstack if required
if (!allowedSlots.second && iter->getRefData().getCount() > 1)
{
MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, 1);
iter->getRefData().setCount(iter->getRefData().getCount()-1);
mSlots[slot] = newIter;
}
else
mSlots[slot] = iter;
}
}
MWWorld::InventoryStore::InventoryStore()
@ -703,7 +731,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,11 +113,8 @@ namespace MWWorld
void fireEquipmentChangedEvent();
virtual int getSlot (const MWWorld::LiveCellRefBase& ref) const;
///< Return inventory slot that \a ref is in or -1 (if \a ref is not in a slot).
virtual void setSlot (const MWWorld::ContainerStoreIterator& iter, int slot);
///< Set slot for \a iter. Ignored if \a iter is an end iterator or if slot==-1.
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory);
public:
@ -209,7 +206,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;

@ -227,7 +227,7 @@ namespace MWWorld
writer.endRecord (ESM::REC_PLAY);
}
bool Player::readRecord (ESM::ESMReader& reader, int32_t type)
bool Player::readRecord (ESM::ESMReader& reader, uint32_t type)
{
if (type==ESM::REC_PLAY)
{

@ -102,7 +102,7 @@ namespace MWWorld
void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
bool readRecord (ESM::ESMReader& reader, int32_t type);
bool readRecord (ESM::ESMReader& reader, uint32_t type);
int getNewCrimeId(); // get new id for witnesses
void recordCrimeId(); // record the paid crime id when bounty is 0

@ -343,7 +343,7 @@ namespace MWWorld
}
}
bool ProjectileManager::readRecord(ESM::ESMReader &reader, int32_t type)
bool ProjectileManager::readRecord(ESM::ESMReader &reader, uint32_t type)
{
if (type == ESM::REC_PROJ)
{

@ -53,7 +53,7 @@ namespace MWWorld
void clear();
void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
bool readRecord (ESM::ESMReader& reader, int32_t type);
bool readRecord (ESM::ESMReader& reader, uint32_t type);
int countSavedGameRecords() const;
private:

@ -762,7 +762,7 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)
writer.endRecord(ESM::REC_WTHR);
}
bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type)
bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type)
{
if(ESM::REC_WTHR == type)
{
@ -770,14 +770,6 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type)
ESM::WeatherState state;
state.load(reader);
// reset other temporary state, now that we loaded successfully
stopSounds(); // let's hope this never throws
mRegionOverrides.clear();
mRegionMods.clear();
mThunderFlash = 0.0;
mThunderChance = 0.0;
mThunderChanceNeeded = 50.0;
// swap in the loaded values now that we can't fail
mHour = state.mHour;
mWindSpeed = state.mWindSpeed;
@ -794,6 +786,16 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type)
return false;
}
void WeatherManager::clear()
{
stopSounds();
mRegionOverrides.clear();
mRegionMods.clear();
mThunderFlash = 0.0;
mThunderChance = 0.0;
mThunderChanceNeeded = 50.0;
}
void WeatherManager::switchToNextWeather(bool instantly)
{
MWBase::World* world = MWBase::Environment::get().getWorld();

@ -199,7 +199,9 @@ namespace MWWorld
void write(ESM::ESMWriter& writer, Loading::Listener& progress);
bool readRecord(ESM::ESMReader& reader, int32_t type);
bool readRecord(ESM::ESMReader& reader, uint32_t type);
void clear();
private:
float mHour;

@ -265,6 +265,7 @@ namespace MWWorld
void World::clear()
{
mWeatherManager->clear();
mRendering->clear();
mProjectileManager->clear();
@ -345,7 +346,7 @@ namespace MWWorld
writer.endRecord(ESM::REC_CAM_);
}
void World::readRecord (ESM::ESMReader& reader, int32_t type,
void World::readRecord (ESM::ESMReader& reader, uint32_t type,
const std::map<int, int>& contentFileMap)
{
switch (type)
@ -2031,7 +2032,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 +2050,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

@ -170,7 +170,7 @@ namespace MWWorld
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
virtual void readRecord (ESM::ESMReader& reader, uint32_t type,
const std::map<int, int>& contentFileMap);
virtual CellStore *getExterior (int x, int y);

@ -215,7 +215,7 @@ namespace Compiler
extensions.registerInstruction ("enablestatsmenu", "", opcodeEnableStatsMenu);
extensions.registerInstruction ("enablerest", "", opcodeEnableRest);
extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableRest);
extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableLevelupMenu);
extensions.registerInstruction ("showrestmenu", "", opcodeShowRestMenu, opcodeShowRestMenuExplicit);

@ -185,6 +185,7 @@ namespace Compiler
const int opcodeEnableMapMenu = 0x2000015;
const int opcodeEnableStatsMenu = 0x2000016;
const int opcodeEnableRest = 0x2000017;
const int opcodeEnableLevelupMenu = 0x2000300;
const int opcodeShowRestMenu = 0x2000018;
const int opcodeShowRestMenuExplicit = 0x2000234;
const int opcodeGetButtonPressed = 0x2000137;

@ -46,12 +46,12 @@ void ESM::CellRef::loadData(ESMReader &esm)
esm.getHNOT (mFactionRank, "INDX");
mGoldValue = 1;
mCharge = -1;
mChargeInt = -1;
mEnchantmentCharge = -1;
esm.getHNOT (mEnchantmentCharge, "XCHG");
esm.getHNOT (mCharge, "INTV");
esm.getHNOT (mChargeInt, "INTV");
esm.getHNOT (mGoldValue, "NAM9");
@ -106,8 +106,8 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons
if (mEnchantmentCharge != -1)
esm.writeHNT("XCHG", mEnchantmentCharge);
if (mCharge != -1)
esm.writeHNT("INTV", mCharge);
if (mChargeInt != -1)
esm.writeHNT("INTV", mChargeInt);
if (mGoldValue != 1) {
esm.writeHNT("NAM9", mGoldValue);
@ -146,7 +146,7 @@ void ESM::CellRef::blank()
mSoul.clear();
mFaction.clear();
mFactionRank = -2;
mCharge = -1;
mChargeInt = -1;
mEnchantmentCharge = -1;
mGoldValue = 0;
mDestCell.clear();

@ -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;

@ -96,15 +96,17 @@ enum RecNameInts
REC_WEAP = 0x50414557,
// format 0 - saved games
REC_SAVE = 0x45564153,
REC_JOUR = 0x524f55a4,
REC_QUES = 0x53455551,
REC_GSCR = 0x52435347,
REC_PLAY = 0x59414c50,
REC_CSTA = 0x41545343,
REC_GMAP = 0x50414d47,
REC_DIAS = 0x53414944,
REC_WTHR = 0x52485457,
REC_SAVE = FourCC<'S','A','V','E'>::value,
REC_JOUR_LEGACY = FourCC<0xa4,'U','O','R'>::value, // "\xa4UOR", rather than "JOUR", little oversight when magic numbers were
// calculated by hand, needs to be supported for older files now
REC_JOUR = FourCC<'J','O','U','R'>::value,
REC_QUES = FourCC<'Q','U','E','S'>::value,
REC_GSCR = FourCC<'G','S','C','R'>::value,
REC_PLAY = FourCC<'P','L','A','Y'>::value,
REC_CSTA = FourCC<'C','S','T','A'>::value,
REC_GMAP = FourCC<'G','M','A','P'>::value,
REC_DIAS = FourCC<'D','I','A','S'>::value,
REC_WTHR = FourCC<'W','T','H','R'>::value,
REC_KEYS = FourCC<'K','E','Y','S'>::value,
REC_DYNA = FourCC<'D','Y','N','A'>::value,
REC_ASPL = FourCC<'A','S','P','L'>::value,
@ -117,7 +119,7 @@ enum RecNameInts
REC_CAM_ = FourCC<'C','A','M','_'>::value,
// format 1
REC_FILT = 0x544C4946,
REC_FILT = FourCC<'F','I','L','T'>::value,
REC_DBGP = FourCC<'D','B','G','P'>::value ///< only used in project files
};

@ -25,7 +25,7 @@ void ESM::DialogueState::load (ESMReader &esm)
while (esm.isNextSub ("REAC"))
{
esm.skipHSub();
esm.getSubHeader();
esm.getSubName();
esm.skipHSub();
}
}

@ -23,7 +23,7 @@ template <int LEN>
union NAME_T
{
char name[LEN];
int32_t val;
uint32_t val;
bool operator==(const char *str) const
{

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save