mirror of https://github.com/OpenMW/openmw.git
commit
6d38b5ae48
@ -0,0 +1,94 @@
|
||||
#include "esm4reader.hpp"
|
||||
|
||||
ESM::ESM4Reader::ESM4Reader(bool oldHeader)
|
||||
{
|
||||
// TES4 header size is 4 bytes smaller than TES5 header
|
||||
mReader.setRecHeaderSize(oldHeader ? sizeof(ESM4::RecordHeader)-4 : sizeof(ESM4::RecordHeader));
|
||||
}
|
||||
|
||||
ESM::ESM4Reader::~ESM4Reader()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM::ESM4Reader::openTes4File(const std::string &name)
|
||||
{
|
||||
mCtx.filename = name;
|
||||
// WARNING: may throw
|
||||
mCtx.leftFile = mReader.openTes4File(name);
|
||||
mReader.registerForUpdates(this); // for updating mCtx.leftFile
|
||||
|
||||
mReader.getRecordHeader();
|
||||
if (mReader.hdr().record.typeId == ESM4::REC_TES4)
|
||||
{
|
||||
mReader.loadHeader();
|
||||
mCtx.leftFile -= mReader.hdr().record.dataSize;
|
||||
|
||||
// Hack: copy over values to TES3 header for getVer() and getRecordCount() to work
|
||||
mHeader.mData.version = mReader.esmVersion();
|
||||
mHeader.mData.records = mReader.numRecords();
|
||||
|
||||
mReader.buildLStringIndex(); // for localised strings in Skyrim
|
||||
}
|
||||
else
|
||||
fail("Unknown file format");
|
||||
}
|
||||
|
||||
ESM4::ReaderContext ESM::ESM4Reader::getESM4Context()
|
||||
{
|
||||
return mReader.getContext();
|
||||
}
|
||||
|
||||
void ESM::ESM4Reader::restoreESM4Context(const ESM4::ReaderContext& ctx)
|
||||
{
|
||||
// Reopen the file if necessary
|
||||
if (mCtx.filename != ctx.filename)
|
||||
openTes4File(ctx.filename);
|
||||
|
||||
// mCtx.leftFile is the only thing used in the old context. Strictly speaking, updating it
|
||||
// with the correct value is not really necessary since we're not going to load the rest of
|
||||
// the file (most likely to load a CELL or LAND then be done with it).
|
||||
mCtx.leftFile = mReader.getFileSize() - mReader.getFileOffset();
|
||||
|
||||
// restore group stack, load the header, etc.
|
||||
mReader.restoreContext(ctx);
|
||||
}
|
||||
|
||||
void ESM::ESM4Reader::restoreCellChildrenContext(const ESM4::ReaderContext& ctx)
|
||||
{
|
||||
// Reopen the file if necessary
|
||||
if (mCtx.filename != ctx.filename)
|
||||
openTes4File(ctx.filename);
|
||||
|
||||
mReader.restoreContext(ctx); // restore group stack, load the CELL header, etc.
|
||||
if (mReader.hdr().record.typeId != ESM4::REC_CELL) // FIXME: testing only
|
||||
fail("Restore Cell Children failed");
|
||||
mReader.skipRecordData(); // skip the CELL record
|
||||
|
||||
mReader.getRecordHeader(); // load the header for cell child group (hopefully)
|
||||
// this is a hack to load only the cell child group...
|
||||
if (mReader.hdr().group.typeId == ESM4::REC_GRUP && mReader.hdr().group.type == ESM4::Grp_CellChild)
|
||||
{
|
||||
mCtx.leftFile = mReader.hdr().group.groupSize - ctx.recHeaderSize;
|
||||
return;
|
||||
}
|
||||
|
||||
// But some cells may have no child groups...
|
||||
// Suspect "ICMarketDistrict" 7 18 is one, followed by cell record 00165F2C "ICMarketDistrict" 6 17
|
||||
if (mReader.hdr().group.typeId != ESM4::REC_GRUP && mReader.hdr().record.typeId == ESM4::REC_CELL)
|
||||
{
|
||||
mCtx.leftFile = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Maybe the group is completed
|
||||
// See "ICMarketDistrict" 9 15 which is followed by a exterior sub-cell block
|
||||
ESM4::ReaderContext tempCtx = mReader.getContext();
|
||||
if (!tempCtx.groupStack.empty() && tempCtx.groupStack.back().second == 0)
|
||||
{
|
||||
mCtx.leftFile = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
fail("Restore Cell Children failed");
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
#ifndef COMPONENT_ESM_4READER_H
|
||||
#define COMPONENT_ESM_4READER_H
|
||||
|
||||
#include <extern/esm4/tes4.hpp>
|
||||
#include <extern/esm4/reader.hpp>
|
||||
|
||||
#include "esmreader.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
// Wrapper class for integrating into OpenCS
|
||||
class ESM4Reader : public ESMReader, public ESM4::ReaderObserver
|
||||
{
|
||||
ESM4::Reader mReader;
|
||||
|
||||
public:
|
||||
|
||||
ESM4Reader(bool oldHeader = true);
|
||||
virtual ~ESM4Reader();
|
||||
|
||||
ESM4::Reader& reader() { return mReader; }
|
||||
|
||||
// Added for use with OpenMW (loading progress bar)
|
||||
inline size_t getFileSize() { return mReader.getFileSize(); }
|
||||
inline size_t getFileOffset() { return mReader.getFileOffset(); }
|
||||
|
||||
// Added for loading Cell/Land
|
||||
ESM4::ReaderContext getESM4Context();
|
||||
void restoreESM4Context(const ESM4::ReaderContext& ctx);
|
||||
void restoreCellChildrenContext(const ESM4::ReaderContext& ctx);
|
||||
|
||||
void openTes4File(const std::string &name);
|
||||
|
||||
// callback from mReader to ensure hasMoreRecs() can reliably track to EOF
|
||||
inline void update(std::size_t size) { mCtx.leftFile -= size; }
|
||||
};
|
||||
}
|
||||
#endif // COMPONENT_ESM_4READER_H
|
@ -0,0 +1,80 @@
|
||||
#
|
||||
# Copyright (C) 2016-2018 cc9cii
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
#
|
||||
# cc9cii cc9c@iinet.net.au
|
||||
#
|
||||
|
||||
set(ESM4_LIBRARY "esm4")
|
||||
|
||||
set(ESM4_SOURCE_FILES
|
||||
common.cpp
|
||||
tes4.cpp
|
||||
navi.cpp
|
||||
wrld.cpp
|
||||
navm.cpp
|
||||
land.cpp
|
||||
ltex.cpp
|
||||
cell.cpp
|
||||
regn.cpp
|
||||
stat.cpp
|
||||
refr.cpp
|
||||
anio.cpp
|
||||
cont.cpp
|
||||
misc.cpp
|
||||
acti.cpp
|
||||
armo.cpp
|
||||
npc_.cpp
|
||||
flor.cpp
|
||||
gras.cpp
|
||||
tree.cpp
|
||||
ligh.cpp
|
||||
achr.cpp
|
||||
book.cpp
|
||||
furn.cpp
|
||||
soun.cpp
|
||||
weap.cpp
|
||||
door.cpp
|
||||
clot.cpp
|
||||
alch.cpp
|
||||
ammo.cpp
|
||||
appa.cpp
|
||||
ingr.cpp
|
||||
sgst.cpp
|
||||
slgm.cpp
|
||||
keym.cpp
|
||||
hair.cpp
|
||||
eyes.cpp
|
||||
crea.cpp
|
||||
lvlc.cpp
|
||||
lvli.cpp
|
||||
acre.cpp
|
||||
idle.cpp
|
||||
mato.cpp
|
||||
sbsp.cpp
|
||||
race.cpp
|
||||
clas.cpp
|
||||
formid.cpp
|
||||
reader.cpp
|
||||
)
|
||||
|
||||
add_library(${ESM4_LIBRARY} STATIC ${ESM4_SOURCE_FILES})
|
||||
set(ESM4_LIBRARIES ${ESM4_LIBRARY})
|
||||
|
||||
link_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(ESM4_LIBRARIES ${ESM4_LIBRARIES} PARENT_SCOPE)
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "achr.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::ActorCharacter::ActorCharacter() : mFormId(0), mFlags(0), mDisabled(false), mBaseObj(0),
|
||||
mScale(1.f), mOwner(0), mGlobal(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
|
||||
mEsp.parent = 0;
|
||||
mEsp.flags = 0;
|
||||
}
|
||||
|
||||
ESM4::ActorCharacter::~ActorCharacter()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::ActorCharacter::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL: reader.getZString(mFullName); break;
|
||||
case ESM4::SUB_NAME: reader.getFormId(mBaseObj); break;
|
||||
case ESM4::SUB_DATA: reader.get(mPosition); break;
|
||||
case ESM4::SUB_XSCL: reader.get(mScale); break;
|
||||
case ESM4::SUB_XOWN: reader.get(mOwner); break;
|
||||
case ESM4::SUB_XESP:
|
||||
{
|
||||
reader.get(mEsp);
|
||||
reader.adjustFormId(mEsp.parent);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_XRGD: // ragdoll
|
||||
case ESM4::SUB_XHRS: // horse formId
|
||||
case ESM4::SUB_XMRC: // merchant container formId
|
||||
// TES5
|
||||
case ESM4::SUB_XAPD: // activation parent
|
||||
case ESM4::SUB_XAPR: // active parent
|
||||
case ESM4::SUB_XEZN: // encounter zone
|
||||
case ESM4::SUB_XHOR:
|
||||
case ESM4::SUB_XLCM: // leveled creature
|
||||
case ESM4::SUB_XLCN: // location
|
||||
case ESM4::SUB_XLKR: // location route?
|
||||
case ESM4::SUB_XLRT: // location type
|
||||
//
|
||||
case ESM4::SUB_XPRD:
|
||||
case ESM4::SUB_XPPA:
|
||||
case ESM4::SUB_INAM:
|
||||
case ESM4::SUB_PDTO:
|
||||
//
|
||||
case ESM4::SUB_XRGB:
|
||||
case ESM4::SUB_XIS2:
|
||||
case ESM4::SUB_XPCI: // formId
|
||||
case ESM4::SUB_XLOD:
|
||||
case ESM4::SUB_VMAD:
|
||||
case ESM4::SUB_XLRL: // Unofficial Skyrim Patch
|
||||
case ESM4::SUB_XRDS: // FO3
|
||||
case ESM4::SUB_XIBS: // FO3
|
||||
case ESM4::SUB_SCHR: // FO3
|
||||
case ESM4::SUB_TNAM: // FO3
|
||||
case ESM4::SUB_XATO: // FONV
|
||||
{
|
||||
//std::cout << "ACHR " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::ACHR::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::ActorCharacter::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::ActorCharacter::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_ACHR_H
|
||||
#define ESM4_ACHR_H
|
||||
|
||||
#include "common.hpp" // Position
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct ActorCharacter
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
FormId mBaseObj;
|
||||
|
||||
Position mPosition;
|
||||
float mScale; // default 1.f
|
||||
FormId mOwner;
|
||||
FormId mGlobal;
|
||||
|
||||
bool mDisabled;
|
||||
EnableParent mEsp; // TODO may need to check mFlags & 0x800 (initially disabled)
|
||||
|
||||
ActorCharacter();
|
||||
virtual ~ActorCharacter();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_ACHR_H
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "acre.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::ActorCreature::ActorCreature() : mFormId(0), mFlags(0), mDisabled(false), mBaseObj(0), mScale(1.f),
|
||||
mOwner(0), mGlobal(0), mFactionRank(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
|
||||
mEsp.parent = 0;
|
||||
mEsp.flags = 0;
|
||||
}
|
||||
|
||||
ESM4::ActorCreature::~ActorCreature()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::ActorCreature::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_NAME: reader.getFormId(mBaseObj); break;
|
||||
case ESM4::SUB_DATA: reader.get(mPosition); break;
|
||||
case ESM4::SUB_XSCL: reader.get(mScale); break;
|
||||
case ESM4::SUB_XESP:
|
||||
{
|
||||
reader.get(mEsp);
|
||||
reader.adjustFormId(mEsp.parent);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_XOWN: reader.getFormId(mOwner); break;
|
||||
case ESM4::SUB_XGLB: reader.get(mGlobal); break; // FIXME: formId?
|
||||
case ESM4::SUB_XRNK: reader.get(mFactionRank); break;
|
||||
case ESM4::SUB_XRGD: // ragdoll
|
||||
case ESM4::SUB_XLKR: // FO3
|
||||
case ESM4::SUB_XLCM: // FO3
|
||||
case ESM4::SUB_XEZN: // FO3
|
||||
case ESM4::SUB_XRGB: // FO3
|
||||
{
|
||||
//std::cout << "ACRE " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::ACRE::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::ActorCreature::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::ActorCreature::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_ACRE_H
|
||||
#define ESM4_ACRE_H
|
||||
|
||||
#include "common.hpp" // EnableParent
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct ActorCreature
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
FormId mBaseObj;
|
||||
|
||||
Position mPosition;
|
||||
float mScale; // default 1.f
|
||||
FormId mOwner;
|
||||
FormId mGlobal;
|
||||
std::uint32_t mFactionRank;
|
||||
|
||||
bool mDisabled;
|
||||
EnableParent mEsp; // TODO may need to check mFlags & 0x800 (initially disabled)
|
||||
|
||||
ActorCreature();
|
||||
virtual ~ActorCreature();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_ACRE_H
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "acti.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Activator::Activator() : mFormId(0), mFlags(0), mScript(0), mSound(0), mBoundRadius(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
}
|
||||
|
||||
ESM4::Activator::~Activator()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Activator::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("ACTI FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_SNAM: reader.getFormId(mSound); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_MODS:
|
||||
case ESM4::SUB_DEST:
|
||||
case ESM4::SUB_DMDL:
|
||||
case ESM4::SUB_DMDS:
|
||||
case ESM4::SUB_DMDT:
|
||||
case ESM4::SUB_DSTD:
|
||||
case ESM4::SUB_DSTF:
|
||||
case ESM4::SUB_FNAM:
|
||||
case ESM4::SUB_KNAM:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_PNAM:
|
||||
case ESM4::SUB_RNAM:
|
||||
case ESM4::SUB_VMAD:
|
||||
case ESM4::SUB_VNAM:
|
||||
case ESM4::SUB_WNAM:
|
||||
case ESM4::SUB_INAM: // FONV
|
||||
case ESM4::SUB_XATO: // FONV
|
||||
{
|
||||
//std::cout << "ACTI " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::ACTI::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Activator::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Activator::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_ACTI_H
|
||||
#define ESM4_ACTI_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Activator
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
|
||||
FormId mScript;
|
||||
FormId mSound;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
Activator();
|
||||
virtual ~Activator();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_ACTI_H
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "alch.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Potion::Potion() : mFormId(0), mFlags(0), mScript(0), mBoundRadius(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIcon.clear();
|
||||
|
||||
mData.weight = 0.f;
|
||||
|
||||
std::memset(&mEffect, 0, sizeof(ScriptEffect));
|
||||
}
|
||||
|
||||
ESM4::Potion::~Potion()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Potion::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("ALCH FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_DATA: reader.get(mData); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_SCIT:
|
||||
{
|
||||
reader.get(mEffect);
|
||||
reader.adjustFormId(mEffect.formId);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_ENIT:
|
||||
case ESM4::SUB_EFID:
|
||||
case ESM4::SUB_EFIT:
|
||||
case ESM4::SUB_CTDA:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_MODS:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_YNAM:
|
||||
case ESM4::SUB_ZNAM:
|
||||
case ESM4::SUB_ETYP: // FO3
|
||||
case ESM4::SUB_MICO: // FO3
|
||||
{
|
||||
//std::cout << "ALCH " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::ALCH::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Potion::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Potion::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_ALCH_H
|
||||
#define ESM4_ALCH_H
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct Potion
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
float weight;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIcon; // inventory
|
||||
|
||||
FormId mScript;
|
||||
ScriptEffect mEffect;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
Data mData;
|
||||
|
||||
Potion();
|
||||
virtual ~Potion();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_ALCH_H
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "ammo.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Ammo::Ammo() : mFormId(0), mFlags(0), mBoundRadius(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIcon.clear();
|
||||
}
|
||||
|
||||
ESM4::Ammo::~Ammo()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Ammo::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
std::uint32_t esmVer = reader.esmVersion();
|
||||
bool isFONV = esmVer == ESM4::VER_132 || esmVer == ESM4::VER_133 || esmVer == ESM4::VER_134;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("AMMO FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
//if (reader.esmVersion() == ESM4::VER_094 || reader.esmVersion() == ESM4::VER_170)
|
||||
if (subHdr.dataSize == 16) // FO3 has 13 bytes even though VER_094
|
||||
{
|
||||
FormId projectile;
|
||||
reader.get(projectile); // FIXME: add to mData
|
||||
reader.get(mData.flags);
|
||||
reader.get(mData.weight);
|
||||
float damageInFloat;
|
||||
reader.get(damageInFloat); // FIXME: add to mData
|
||||
}
|
||||
else if (isFONV || subHdr.dataSize == 13)
|
||||
{
|
||||
reader.get(mData.speed);
|
||||
std::uint8_t flags;
|
||||
reader.get(flags);
|
||||
mData.flags = flags;
|
||||
static std::uint8_t dummy;
|
||||
reader.get(dummy);
|
||||
reader.get(dummy);
|
||||
reader.get(dummy);
|
||||
reader.get(mData.value);
|
||||
reader.get(mData.clipRounds);
|
||||
}
|
||||
else // TES4
|
||||
{
|
||||
reader.get(mData.speed);
|
||||
reader.get(mData.flags);
|
||||
reader.get(mData.value);
|
||||
reader.get(mData.weight);
|
||||
reader.get(mData.damage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_ANAM: reader.get(mEnchantmentPoints); break;
|
||||
case ESM4::SUB_ENAM: reader.getFormId(mEnchantment); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_YNAM:
|
||||
case ESM4::SUB_ZNAM:
|
||||
case ESM4::SUB_DESC:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_MICO: // FO3
|
||||
case ESM4::SUB_ONAM: // FO3
|
||||
case ESM4::SUB_DAT2: // FONV
|
||||
case ESM4::SUB_QNAM: // FONV
|
||||
case ESM4::SUB_RCIL: // FONV
|
||||
case ESM4::SUB_SCRI: // FONV
|
||||
{
|
||||
//std::cout << "AMMO " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::AMMO::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Ammo::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Ammo::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_AMMO_H
|
||||
#define ESM4_AMMO_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Ammo
|
||||
{
|
||||
struct Data // FIXME: TES5 projectile, damage (float)
|
||||
{
|
||||
float speed;
|
||||
std::uint32_t flags;
|
||||
std::uint32_t value; // gold
|
||||
float weight;
|
||||
std::uint16_t damage;
|
||||
std::uint8_t clipRounds; // only in FO3/FONV
|
||||
|
||||
Data() : speed(0.f), flags(0), value(0), weight(0.f), damage(0), clipRounds(0) {}
|
||||
};
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIcon; // inventory
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
std::uint16_t mEnchantmentPoints;
|
||||
FormId mEnchantment;
|
||||
|
||||
Data mData;
|
||||
|
||||
Ammo();
|
||||
virtual ~Ammo();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_AMMO_H
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "anio.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::AnimObject::AnimObject() : mFormId(0), mFlags(0), mBoundRadius(0.f), mIdleAnim(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mModel.clear();
|
||||
mUnloadEvent.clear();
|
||||
}
|
||||
|
||||
ESM4::AnimObject::~AnimObject()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::AnimObject::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_BNAM: reader.getZString(mUnloadEvent); break;
|
||||
case ESM4::SUB_DATA: reader.getFormId(mIdleAnim); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT: // TES5 only
|
||||
case ESM4::SUB_MODS: // TES5 only
|
||||
{
|
||||
//std::cout << "ANIO " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::ANIO::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::AnimObject::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::AnimObject::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_ANIO_H
|
||||
#define ESM4_ANIO_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct AnimObject
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mModel;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
FormId mIdleAnim; // only in TES4
|
||||
std::string mUnloadEvent; // only in TES5
|
||||
|
||||
AnimObject();
|
||||
virtual ~AnimObject();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_ANIO_H
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "appa.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Apparatus::Apparatus() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIcon.clear();
|
||||
|
||||
mData.type = 0;
|
||||
mData.value = 0;
|
||||
mData.weight = 0.f;
|
||||
mData.quality = 0.f;
|
||||
}
|
||||
|
||||
ESM4::Apparatus::~Apparatus()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Apparatus::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("APPA FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
if (reader.esmVersion() == ESM4::VER_094 || reader.esmVersion() == ESM4::VER_170)
|
||||
{
|
||||
reader.get(mData.value);
|
||||
reader.get(mData.weight);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.get(mData.type);
|
||||
reader.get(mData.value);
|
||||
reader.get(mData.weight);
|
||||
reader.get(mData.quality);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_DESC:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_QUAL:
|
||||
{
|
||||
//std::cout << "APPA " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::APPAPPAoad - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Apparatus::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Apparatus::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_APPA_H
|
||||
#define ESM4_APPA_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Apparatus
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
std::uint8_t type; // 0 = Mortar and Pestle, 1 = Alembic, 2 = Calcinator, 3 = Retort
|
||||
std::uint32_t value; // gold
|
||||
float weight;
|
||||
float quality;
|
||||
};
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIcon; // inventory
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
FormId mScript;
|
||||
|
||||
Data mData;
|
||||
|
||||
Apparatus();
|
||||
virtual ~Apparatus();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_APPA_H
|
@ -0,0 +1,166 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "armo.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Armor::Armor() : mFormId(0), mFlags(0), mBoundRadius(0.f), mArmorFlags(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIconMale.clear();
|
||||
mIconFemale.clear();
|
||||
|
||||
mData.armor = 0;
|
||||
mData.value = 0;
|
||||
mData.health = 0;
|
||||
mData.weight = 0.f;
|
||||
}
|
||||
|
||||
ESM4::Armor::~Armor()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Armor::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
std::uint32_t esmVer = reader.esmVersion();
|
||||
bool isFONV = esmVer == ESM4::VER_132 || esmVer == ESM4::VER_133 || esmVer == ESM4::VER_134;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("ARMO FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
//if (reader.esmVersion() == ESM4::VER_094 || reader.esmVersion() == ESM4::VER_170)
|
||||
if (subHdr.dataSize == 8) // FO3 has 12 bytes even though VER_094
|
||||
{
|
||||
reader.get(mData.value);
|
||||
reader.get(mData.weight);
|
||||
}
|
||||
else if (isFONV || subHdr.dataSize == 12)
|
||||
{
|
||||
reader.get(mData.value);
|
||||
reader.get(mData.health);
|
||||
reader.get(mData.weight);
|
||||
}
|
||||
else
|
||||
reader.get(mData); // TES4
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: // seems only for Dawnguard/Dragonborn?
|
||||
{
|
||||
if (!reader.getZString(mModel))
|
||||
throw std::runtime_error ("ARMO MODL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ICON: reader.getZString(mIconMale); break;
|
||||
case ESM4::SUB_ICO2: reader.getZString(mIconFemale); break;
|
||||
//case ESM4::SUB_BMDT: reader.get(mArmorFlags); break; // see below re. FO3
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_ANAM: reader.get(mEnchantmentPoints); break;
|
||||
case ESM4::SUB_ENAM: reader.getFormId(mEnchantment); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_MOD2:
|
||||
case ESM4::SUB_MOD3:
|
||||
case ESM4::SUB_MOD4:
|
||||
case ESM4::SUB_MO2B:
|
||||
case ESM4::SUB_MO3B:
|
||||
case ESM4::SUB_MO4B:
|
||||
case ESM4::SUB_MO2T:
|
||||
case ESM4::SUB_MO2S:
|
||||
case ESM4::SUB_MO3T:
|
||||
case ESM4::SUB_MO4T:
|
||||
case ESM4::SUB_MO4S:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_BODT:
|
||||
case ESM4::SUB_BOD2:
|
||||
case ESM4::SUB_YNAM:
|
||||
case ESM4::SUB_ZNAM:
|
||||
case ESM4::SUB_RNAM:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_DESC:
|
||||
case ESM4::SUB_TNAM:
|
||||
case ESM4::SUB_DNAM:
|
||||
case ESM4::SUB_BAMT:
|
||||
case ESM4::SUB_BIDS:
|
||||
case ESM4::SUB_ETYP:
|
||||
case ESM4::SUB_BMCT:
|
||||
case ESM4::SUB_MICO:
|
||||
case ESM4::SUB_MIC2:
|
||||
case ESM4::SUB_EAMT:
|
||||
case ESM4::SUB_EITM:
|
||||
case ESM4::SUB_VMAD:
|
||||
case ESM4::SUB_BMDT: // FO3 FIXME might have different format
|
||||
case ESM4::SUB_REPL: // FO3
|
||||
case ESM4::SUB_BIPL: // FO3
|
||||
case ESM4::SUB_MODD: // FO3
|
||||
case ESM4::SUB_MOSD: // FO3
|
||||
case ESM4::SUB_MODS: // FO3
|
||||
case ESM4::SUB_MO3S: // FO3
|
||||
case ESM4::SUB_BNAM: // FONV
|
||||
case ESM4::SUB_SNAM: // FONV
|
||||
{
|
||||
//std::cout << "ARMO " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::ARMO::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Armor::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Armor::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_ARMO_H
|
||||
#define ESM4_ARMO_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Armor
|
||||
{
|
||||
enum Flags
|
||||
{
|
||||
// Biped Object Flags
|
||||
Flag_Head = 0x00000001,
|
||||
Flag_Hair = 0x00000002,
|
||||
Flag_UpperBody = 0x00000004,
|
||||
Flag_LowerBody = 0x00000008,
|
||||
Flag_Hand = 0x00000010,
|
||||
Flag_Foot = 0x00000020,
|
||||
Flag_RightRing = 0x00000040,
|
||||
Flag_LeftRing = 0x00000080,
|
||||
Flag_Amulet = 0x00000100,
|
||||
Flag_Weapon = 0x00000200,
|
||||
Flag_BackWeapon = 0x00000400,
|
||||
Flag_SideWeapon = 0x00000800,
|
||||
Flag_Quiver = 0x00001000,
|
||||
Flag_Shield = 0x00002000,
|
||||
Flag_Torch = 0x00004000,
|
||||
Flag_Tail = 0x00008000,
|
||||
// General Flags
|
||||
Flag_HideRings = 0x00010000,
|
||||
Flag_HideAmulet = 0x00020000,
|
||||
Flag_NonPlayable = 0x00400000,
|
||||
Flag_Unknown = 0xCD000000
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
std::uint16_t armor; // Only in TES4?
|
||||
std::uint32_t value;
|
||||
std::uint32_t health; // not in TES5?
|
||||
float weight;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIconMale;
|
||||
std::string mIconFemale;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
std::uint32_t mArmorFlags;
|
||||
FormId mScript;
|
||||
std::uint16_t mEnchantmentPoints;
|
||||
FormId mEnchantment;
|
||||
|
||||
Data mData;
|
||||
|
||||
Armor();
|
||||
virtual ~Armor();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_ARMO_H
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "book.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Book::Book() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0),
|
||||
mEnchantmentPoints(0), mEnchantment(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mText.clear();
|
||||
mIcon.clear();
|
||||
|
||||
mData.flags = 0;
|
||||
mData.type = 0;
|
||||
mData.bookSkill = 0;
|
||||
mData.value = 0;
|
||||
mData.weight = 0.f;
|
||||
}
|
||||
|
||||
ESM4::Book::~Book()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Book::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
std::uint32_t esmVer = reader.esmVersion();
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("BOOK FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DESC:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
{
|
||||
std::uint32_t formid;
|
||||
reader.get(formid);
|
||||
if (formid)
|
||||
reader.getLocalizedString(formid, mText); // sometimes formid is null
|
||||
}
|
||||
else if (!reader.getZString(mText))
|
||||
throw std::runtime_error ("BOOK DESC data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
reader.get(mData.flags);
|
||||
//if (reader.esmVersion() == ESM4::VER_094 || reader.esmVersion() == ESM4::VER_170)
|
||||
if (subHdr.dataSize == 16) // FO3 has 10 bytes even though VER_094
|
||||
{
|
||||
static std::uint8_t dummy;
|
||||
reader.get(mData.type);
|
||||
reader.get(dummy);
|
||||
reader.get(dummy);
|
||||
reader.get(mData.teaches);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.get(mData.bookSkill);
|
||||
}
|
||||
reader.get(mData.value);
|
||||
reader.get(mData.weight);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_ANAM: reader.get(mEnchantmentPoints); break;
|
||||
case ESM4::SUB_ENAM: reader.getFormId(mEnchantment); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_CNAM:
|
||||
case ESM4::SUB_INAM:
|
||||
case ESM4::SUB_YNAM:
|
||||
case ESM4::SUB_VMAD:
|
||||
{
|
||||
//std::cout << "BOOK " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::BOOK::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Book::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Book::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_BOOK_H
|
||||
#define ESM4_BOOK_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Book
|
||||
{
|
||||
enum Flags
|
||||
{
|
||||
Flag_Scroll = 0x0001,
|
||||
Flag_NoTake = 0x0002
|
||||
};
|
||||
|
||||
enum BookSkill // for TES4 only
|
||||
{
|
||||
BookSkill_None = -1,
|
||||
BookSkill_Armorer = 0,
|
||||
BookSkill_Athletics = 1,
|
||||
BookSkill_Blade = 2,
|
||||
BookSkill_Block = 3,
|
||||
BookSkill_Blunt = 4,
|
||||
BookSkill_HandToHand = 5,
|
||||
BookSkill_HeavyArmor = 6,
|
||||
BookSkill_Alchemy = 7,
|
||||
BookSkill_Alteration = 8,
|
||||
BookSkill_Conjuration = 9,
|
||||
BookSkill_Destruction = 10,
|
||||
BookSkill_Illusion = 11,
|
||||
BookSkill_Mysticism = 12,
|
||||
BookSkill_Restoration = 13,
|
||||
BookSkill_Acrobatics = 14,
|
||||
BookSkill_LightArmor = 15,
|
||||
BookSkill_Marksman = 16,
|
||||
BookSkill_Mercantile = 17,
|
||||
BookSkill_Security = 18,
|
||||
BookSkill_Sneak = 19,
|
||||
BookSkill_Speechcraft = 20
|
||||
};
|
||||
|
||||
struct Data
|
||||
{
|
||||
std::uint8_t flags;
|
||||
std::uint8_t type; // TES5 only
|
||||
std::uint32_t teaches; // TES5 only
|
||||
std::int8_t bookSkill; // not in TES5
|
||||
std::uint32_t value;
|
||||
float weight;
|
||||
};
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
std::string mText;
|
||||
FormId mScript;
|
||||
std::string mIcon;
|
||||
std::uint16_t mEnchantmentPoints;
|
||||
FormId mEnchantment;
|
||||
|
||||
Data mData;
|
||||
|
||||
Book();
|
||||
virtual ~Book();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_BOOK_H
|
@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "cell.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <iostream> // FIXME: debug only
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
#ifdef NDEBUG // FIXME: debuggigng only
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
ESM4::Cell::Cell() : mParent(0), mFormId(0), mFlags(0), mCellFlags(0), mX(0), mY(0), mOwner(0),
|
||||
mGlobal(0), mClimate(0), mWater(0), mWaterHeight(0.f), mPreloaded(false)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
|
||||
mLighting.ambient = 0;
|
||||
mLighting.directional = 0;
|
||||
mLighting.fogNear = 0;
|
||||
mLighting.unknown1 = 0.f;
|
||||
mLighting.unknown2 = 0.f;
|
||||
mLighting.unknown3 = 0;
|
||||
mLighting.unknown4 = 0;
|
||||
mLighting.unknown5 = 0.f;
|
||||
mLighting.unknown6 = 0.f;
|
||||
}
|
||||
|
||||
ESM4::Cell::~Cell()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Cell::init(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
mParent = reader.currWorld();
|
||||
|
||||
reader.clearCellGrid(); // clear until XCLC FIXME: somehow do this automatically?
|
||||
|
||||
// Sometimes cell 0,0 does not have an XCLC sub record (e.g. ToddLand 000009BF)
|
||||
// To workaround this issue put a default value if group is "exterior sub cell" and its
|
||||
// grid from label is "0 0". Note the reversed X/Y order (no matter since they're both 0
|
||||
// anyway).
|
||||
if (reader.grp().type == ESM4::Grp_ExteriorSubCell
|
||||
&& reader.grp().label.grid[1] == 0 && reader.grp().label.grid[0] == 0)
|
||||
{
|
||||
ESM4::CellGrid currCellGrid;
|
||||
currCellGrid.grid.x = 0;
|
||||
currCellGrid.grid.y = 0;
|
||||
reader.setCurrCellGrid(currCellGrid); // side effect: sets mCellGridValid true
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent)
|
||||
//
|
||||
// But, for external cells we may be scanning the whole record since we don't know if there is
|
||||
// going to be an EDID subrecord. And the vast majority of cells are these kinds.
|
||||
//
|
||||
// So perhaps some testing needs to be done to see if scanning and skipping takes
|
||||
// longer/shorter/same as loading the subrecords.
|
||||
bool ESM4::Cell::preload(ESM4::Reader& reader)
|
||||
{
|
||||
if (!mPreloaded)
|
||||
load(reader);
|
||||
|
||||
mPreloaded = true;
|
||||
//return reader.skipNextGroupCellChild(); // true if found cell child group and skipped
|
||||
return true; // FIXME
|
||||
}
|
||||
|
||||
void ESM4::Cell::load(ESM4::Reader& reader)
|
||||
{
|
||||
if (mPreloaded)
|
||||
return;
|
||||
|
||||
// FIXME: we may need to call setCurrCell (and maybe setCurrCellGrid?) again before loading
|
||||
// cell child groups if we are loading them after restoring the context
|
||||
init(reader);
|
||||
reader.setCurrCell(mFormId); // save for LAND (and other children) to access later
|
||||
std::uint32_t esmVer = reader.esmVersion();
|
||||
bool isFONV = esmVer == ESM4::VER_132 || esmVer == ESM4::VER_133 || esmVer == ESM4::VER_134;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID:
|
||||
{
|
||||
if (!reader.getZString(mEditorId))
|
||||
throw std::runtime_error ("CELL EDID data read error");
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
std::cout << padding << "CELL Editor ID: " << mEditorId << std::endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_XCLC:
|
||||
{
|
||||
//(X, Y) grid location of the cell followed by flags. Always in
|
||||
//exterior cells and never in interior cells.
|
||||
//
|
||||
// int32 - X
|
||||
// int32 - Y
|
||||
// uint32 - flags (high bits look random)
|
||||
//
|
||||
// 0x1 - Force Hide Land Quad 1
|
||||
// 0x2 - Force Hide Land Quad 2
|
||||
// 0x4 - Force Hide Land Quad 3
|
||||
// 0x8 - Force Hide Land Quad 4
|
||||
uint32_t flags;
|
||||
reader.get(mX);
|
||||
reader.get(mY);
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
std::cout << padding << "CELL group " << ESM4::printLabel(reader.grp().label, reader.grp().type) << std::endl;
|
||||
std::cout << padding << "CELL formId " << std::hex << reader.hdr().record.id << std::endl;
|
||||
std::cout << padding << "CELL X " << std::dec << mX << ", Y " << mY << std::endl;
|
||||
#endif
|
||||
if (esmVer == ESM4::VER_094 || esmVer == ESM4::VER_170 || isFONV)
|
||||
if (subHdr.dataSize == 12)
|
||||
reader.get(flags); // not in Obvlivion, nor FO3/FONV
|
||||
|
||||
// Remember cell grid for later (loading LAND, NAVM which should be CELL temporary children)
|
||||
// Note that grids only apply for external cells. For interior cells use the cell's formid.
|
||||
ESM4::CellGrid currCell;
|
||||
currCell.grid.x = (int16_t)mX;
|
||||
currCell.grid.y = (int16_t)mY;
|
||||
reader.setCurrCellGrid(currCell);
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("CELL FULL data read error");
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
std::cout << padding << "Name: " << mFullName << std::endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
if (esmVer == ESM4::VER_094 || esmVer == ESM4::VER_170 || isFONV)
|
||||
if (subHdr.dataSize == 2)
|
||||
reader.get(mCellFlags);
|
||||
else
|
||||
{
|
||||
assert(subHdr.dataSize == 1 && "CELL unexpected DATA flag size");
|
||||
reader.get((std::uint8_t&)mCellFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.get((std::uint8_t&)mCellFlags); // 8 bits in Obvlivion
|
||||
}
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
std::cout << padding << "flags: " << std::hex << mCellFlags << std::endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_XCLR:
|
||||
{
|
||||
mRegions.resize(subHdr.dataSize/sizeof(FormId));
|
||||
for (std::vector<FormId>::iterator it = mRegions.begin(); it != mRegions.end(); ++it)
|
||||
{
|
||||
reader.getFormId(*it);
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
std::cout << padding << "region: " << std::hex << *it << std::endl;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_XOWN: reader.getFormId(mOwner); break;
|
||||
case ESM4::SUB_XGLB: reader.getFormId(mGlobal); break; // Oblivion only?
|
||||
case ESM4::SUB_XCCM: reader.getFormId(mClimate); break;
|
||||
case ESM4::SUB_XCWT: reader.getFormId(mWater); break;
|
||||
case ESM4::SUB_XCLW: reader.get(mWaterHeight); break;
|
||||
case ESM4::SUB_XCLL:
|
||||
{
|
||||
// 92 bytes for TES5, 19*4 = 76 bytes for FO3/FONV
|
||||
if (esmVer == ESM4::VER_094 || esmVer == ESM4::VER_170 || isFONV)
|
||||
reader.skipSubRecordData();
|
||||
else
|
||||
{
|
||||
assert(subHdr.dataSize == 36 && "CELL lighting size error");
|
||||
reader.get(mLighting);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_TVDT:
|
||||
case ESM4::SUB_MHDT:
|
||||
case ESM4::SUB_XCGD:
|
||||
case ESM4::SUB_LTMP:
|
||||
case ESM4::SUB_LNAM:
|
||||
case ESM4::SUB_XNAM:
|
||||
case ESM4::SUB_XLCN:
|
||||
case ESM4::SUB_XWCS:
|
||||
case ESM4::SUB_XWCU:
|
||||
case ESM4::SUB_XWCN:
|
||||
case ESM4::SUB_XCAS:
|
||||
case ESM4::SUB_XCIM:
|
||||
case ESM4::SUB_XCMO:
|
||||
case ESM4::SUB_XEZN:
|
||||
case ESM4::SUB_XWEM:
|
||||
case ESM4::SUB_XILL:
|
||||
case ESM4::SUB_XCMT: // Oblivion only?
|
||||
case ESM4::SUB_XRNK: // Oblivion only?
|
||||
case ESM4::SUB_XCET: // FO3
|
||||
case ESM4::SUB_IMPF: // FO3 Zeta
|
||||
{
|
||||
//std::cout << "CELL " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::CELL::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Cell::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
void ESM4::Cell::blank()
|
||||
{
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_CELL_H
|
||||
#define ESM4_CELL_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
struct ReaderContext;
|
||||
struct CellGroup;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
enum CellFlags // TES4 TES5
|
||||
{ // ----------------------- ------------------------------------
|
||||
CELL_Interior = 0x0001, // Can't travel from here Interior
|
||||
CELL_HasWater = 0x0002, // Has water Has Water
|
||||
CELL_NoTravel = 0x0004, // not Can't Travel From Here(Int only)
|
||||
CELL_HideLand = 0x0008, // Force hide land (Ext) No LOD Water
|
||||
// Oblivion interior (Int)
|
||||
CELL_Public = 0x0020, // Public place Public Area
|
||||
CELL_HandChgd = 0x0040, // Hand changed Hand Changed
|
||||
CELL_QuasiExt = 0x0080, // Behave like exterior Show Sky
|
||||
CELL_SkyLight = 0x0100 // Use Sky Lighting
|
||||
};
|
||||
|
||||
// Unlike TES3, multiple cells can have the same exterior co-ordinates.
|
||||
// The cells need to be organised under world spaces.
|
||||
struct Cell
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
// TES4 (guesses only), TES5 are 96 bytes
|
||||
struct Lighting
|
||||
{ // | Aichan Prison values
|
||||
std::uint32_t ambient; // | 16 17 19 00 (RGBA)
|
||||
std::uint32_t directional; // | 00 00 00 00 (RGBA)
|
||||
std::uint32_t fogNear; // | 1D 1B 16 00 (RGBA)
|
||||
float unknown1; // Fog Near | 00 00 00 00 = 0.f
|
||||
float unknown2; // Fog Far | 00 80 3B 45 = 3000.f
|
||||
std::int32_t unknown3; // rotation xy | 00 00 00 00 = 0
|
||||
std::int32_t unknown4; // rotation z | 00 00 00 00 = 0
|
||||
float unknown5; // Fog dir fade | 00 00 80 3F = 1.f
|
||||
float unknown6; // Fog clip dist | 00 80 3B 45 = 3000.f
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mParent; // world formId (for grouping cells), from the loading sequence
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::uint16_t mCellFlags; // TES5 can also be 8 bits
|
||||
|
||||
std::int32_t mX;
|
||||
std::int32_t mY;
|
||||
|
||||
FormId mOwner;
|
||||
FormId mGlobal;
|
||||
FormId mClimate;
|
||||
FormId mWater;
|
||||
float mWaterHeight;
|
||||
|
||||
std::vector<FormId> mRegions;
|
||||
Lighting mLighting;
|
||||
|
||||
CellGroup *mCellGroup;
|
||||
|
||||
Cell();
|
||||
virtual ~Cell();
|
||||
|
||||
void init(ESM4::Reader& reader); // common setup for both preload() and load()
|
||||
|
||||
bool mPreloaded;
|
||||
bool preload(ESM4::Reader& reader);
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_CELL_H
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "clas.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
#ifdef NDEBUG // FIXME: debuggigng only
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
ESM4::Class::Class()
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mDesc.clear();
|
||||
mIcon.clear();
|
||||
}
|
||||
|
||||
ESM4::Class::~Class()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Class::load(ESM4::Reader& reader)
|
||||
{
|
||||
//mFormId = reader.adjustFormId(reader.hdr().record.id); // FIXME: use master adjusted?
|
||||
mFormId = reader.hdr().record.id;
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("CLAS FULL data read error");
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DESC:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
{
|
||||
std::uint32_t formid;
|
||||
reader.get(formid);
|
||||
if (formid)
|
||||
reader.getLocalizedString(formid, mDesc); // sometimes formid is null
|
||||
}
|
||||
else if (!reader.getZString(mDesc))
|
||||
throw std::runtime_error ("CLAS DESC data read error");
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
//std::cout << "CLAS " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::CLAS::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Class::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Class::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_CLAS_H
|
||||
#define ESM4_CLAS_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Class
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
std::uint32_t attr;
|
||||
};
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mDesc;
|
||||
std::string mIcon;
|
||||
Data mData;
|
||||
|
||||
Class();
|
||||
~Class();
|
||||
|
||||
void load(ESM4::Reader& reader);
|
||||
//void save(ESM4::Writer& reader) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_CLAS_H
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "clot.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Clothing::Clothing() : mFormId(0), mFlags(0), mBoundRadius(0.f), mClothingFlags(0),
|
||||
mScript(0), mEnchantmentPoints(0), mEnchantment(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIconMale.clear();
|
||||
mIconFemale.clear();
|
||||
|
||||
mData.value = 0;
|
||||
mData.weight = 0.f;
|
||||
}
|
||||
|
||||
ESM4::Clothing::~Clothing()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Clothing::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL: reader.getZString(mFullName); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_ICON: reader.getZString(mIconMale); break;
|
||||
case ESM4::SUB_ICO2: reader.getZString(mIconFemale); break;
|
||||
case ESM4::SUB_DATA: reader.get(mData); break;
|
||||
case ESM4::SUB_BMDT: reader.get(mClothingFlags); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_ENAM: reader.getFormId(mEnchantment); break;
|
||||
case ESM4::SUB_ANAM: reader.get(mEnchantmentPoints); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_MOD2:
|
||||
case ESM4::SUB_MOD3:
|
||||
case ESM4::SUB_MOD4:
|
||||
case ESM4::SUB_MO2B:
|
||||
case ESM4::SUB_MO3B:
|
||||
case ESM4::SUB_MO4B:
|
||||
case ESM4::SUB_MO2T:
|
||||
case ESM4::SUB_MO3T:
|
||||
case ESM4::SUB_MO4T:
|
||||
{
|
||||
//std::cout << "CLOT " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::CLOT::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Clothing::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Clothing::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_CLOT_H
|
||||
#define ESM4_CLOT_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Clothing
|
||||
{
|
||||
enum Flags
|
||||
{
|
||||
// Biped Object Flags
|
||||
Flag_Head = 0x00000001,
|
||||
Flag_Hair = 0x00000002,
|
||||
Flag_UpperBody = 0x00000004,
|
||||
Flag_LowerBody = 0x00000008,
|
||||
Flag_Hand = 0x00000010,
|
||||
Flag_Foot = 0x00000020,
|
||||
Flag_RightRing = 0x00000040,
|
||||
Flag_LeftRing = 0x00000080,
|
||||
Flag_Amulet = 0x00000100,
|
||||
Flag_Weapon = 0x00000200,
|
||||
Flag_BackWeapon = 0x00000400,
|
||||
Flag_SideWeapon = 0x00000800,
|
||||
Flag_Quiver = 0x00001000,
|
||||
Flag_Shield = 0x00002000,
|
||||
Flag_Torch = 0x00004000,
|
||||
Flag_Tail = 0x00008000,
|
||||
// General Flags
|
||||
Flag_HideRings = 0x00010000,
|
||||
Flag_HideAmulet = 0x00020000,
|
||||
Flag_NonPlayable = 0x00400000,
|
||||
Flag_Unknown = 0xCD000000
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
std::uint32_t value; // gold
|
||||
float weight;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIconMale; // inventory
|
||||
std::string mIconFemale; // inventory
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
std::uint32_t mClothingFlags;
|
||||
FormId mScript;
|
||||
std::uint16_t mEnchantmentPoints;
|
||||
FormId mEnchantment;
|
||||
|
||||
Data mData;
|
||||
|
||||
Clothing();
|
||||
virtual ~Clothing();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_CLOT_H
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "common.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <libs/platform/strings.h>
|
||||
|
||||
#include "formid.hpp"
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
const char *sGroupType[] =
|
||||
{
|
||||
"Record Type", "World Child", "Interior Cell", "Interior Sub Cell", "Exterior Cell",
|
||||
"Exterior Sub Cell", "Cell Child", "Topic Child", "Cell Persistent Child",
|
||||
"Cell Temporary Child", "Cell Visible Dist Child", "Unknown"
|
||||
};
|
||||
|
||||
std::string printLabel(const GroupLabel& label, const std::uint32_t type)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << std::string(sGroupType[std::min(type, (uint32_t)11)]); // avoid out of range
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ESM4::Grp_RecordType:
|
||||
{
|
||||
ss << ": " << std::string((char*)label.recordType, 4);
|
||||
break;
|
||||
}
|
||||
case ESM4::Grp_ExteriorCell:
|
||||
case ESM4::Grp_ExteriorSubCell:
|
||||
{
|
||||
//short x, y;
|
||||
//y = label & 0xff;
|
||||
//x = (label >> 16) & 0xff;
|
||||
ss << ": grid (x, y) " << std::dec << label.grid[1] << ", " << label.grid[0];
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::Grp_InteriorCell:
|
||||
case ESM4::Grp_InteriorSubCell:
|
||||
{
|
||||
ss << ": block 0x" << std::hex << label.value;
|
||||
break;
|
||||
}
|
||||
case ESM4::Grp_WorldChild:
|
||||
case ESM4::Grp_CellChild:
|
||||
case ESM4::Grp_TopicChild:
|
||||
case ESM4::Grp_CellPersistentChild:
|
||||
case ESM4::Grp_CellTemporaryChild:
|
||||
case ESM4::Grp_CellVisibleDistChild:
|
||||
{
|
||||
ss << ": FormId 0x" << formIdToString(label.value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string printName(const std::uint32_t typeId)
|
||||
{
|
||||
unsigned char typeName[4];
|
||||
typeName[0] = typeId & 0xff;
|
||||
typeName[1] = (typeId >> 8) & 0xff;
|
||||
typeName[2] = (typeId >> 16) & 0xff;
|
||||
typeName[3] = (typeId >> 24) & 0xff;
|
||||
|
||||
return std::string((char*)typeName, 4);
|
||||
}
|
||||
|
||||
void gridToString(std::int16_t x, std::int16_t y, std::string& str)
|
||||
{
|
||||
char buf[6+6+2+1]; // longest signed 16 bit number is 6 characters (-32768)
|
||||
int res = snprintf(buf, 6+6+2+1, "#%d %d", x, y);
|
||||
if (res > 0 && res < 6+6+2+1)
|
||||
str.assign(buf);
|
||||
else
|
||||
throw std::runtime_error("possible buffer overflow while converting grid");
|
||||
}
|
||||
}
|
@ -0,0 +1,933 @@
|
||||
/*
|
||||
Copyright (C) 2015-2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
MKTAG macro was adapated from ScummVM.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_COMMON_H
|
||||
#define ESM4_COMMON_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
// From ScummVM's endianness.h but for little endian
|
||||
#define MKTAG(a0,a1,a2,a3) ((std::uint32_t)((a0) | ((a1) << 8) | ((a2) << 16) | ((a3) << 24)))
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
enum ESMVersions
|
||||
{
|
||||
VER_080 = 0x3f4ccccd, // TES4
|
||||
VER_100 = 0x3f800000, // TES4
|
||||
VER_132 = 0x3fa8f5c3, // FONV Courier's Stash, DeadMoney
|
||||
VER_133 = 0x3faa3d71, // FONV HonestHearts
|
||||
VER_134 = 0x3fab851f, // FONV, GunRunnersArsenal, LonesomeRoad, OldWorldBlues
|
||||
VER_094 = 0x3f70a3d7, // TES5/FO3
|
||||
VER_170 = 0x3fd9999a // TES5
|
||||
};
|
||||
|
||||
// Based on http://www.uesp.net/wiki/Tes5Mod:Mod_File_Format
|
||||
enum RecordTypes
|
||||
{
|
||||
REC_AACT = MKTAG('A','A','C','T'), // Action
|
||||
REC_ACHR = MKTAG('A','C','H','R'), // Actor Reference
|
||||
REC_ACTI = MKTAG('A','C','T','I'), // Activator
|
||||
REC_ADDN = MKTAG('A','D','D','N'), // Addon Node
|
||||
REC_ALCH = MKTAG('A','L','C','H'), // Potion
|
||||
REC_AMMO = MKTAG('A','M','M','O'), // Ammo
|
||||
REC_ANIO = MKTAG('A','N','I','O'), // Animated Object
|
||||
REC_APPA = MKTAG('A','P','P','A'), // Apparatus (probably unused)
|
||||
REC_ARMA = MKTAG('A','R','M','A'), // Armature (Model)
|
||||
REC_ARMO = MKTAG('A','R','M','O'), // Armor
|
||||
REC_ARTO = MKTAG('A','R','T','O'), // Art Object
|
||||
REC_ASPC = MKTAG('A','S','P','C'), // Acoustic Space
|
||||
REC_ASTP = MKTAG('A','S','T','P'), // Association Type
|
||||
REC_AVIF = MKTAG('A','V','I','F'), // Actor Values/Perk Tree Graphics
|
||||
REC_BOOK = MKTAG('B','O','O','K'), // Book
|
||||
REC_BPTD = MKTAG('B','P','T','D'), // Body Part Data
|
||||
REC_CAMS = MKTAG('C','A','M','S'), // Camera Shot
|
||||
REC_CELL = MKTAG('C','E','L','L'), // Cell
|
||||
REC_CLAS = MKTAG('C','L','A','S'), // Class
|
||||
REC_CLFM = MKTAG('C','L','F','M'), // Color
|
||||
REC_CLMT = MKTAG('C','L','M','T'), // Climate
|
||||
REC_CLOT = MKTAG('C','L','O','T'), // Clothing
|
||||
REC_COBJ = MKTAG('C','O','B','J'), // Constructible Object (recipes)
|
||||
REC_COLL = MKTAG('C','O','L','L'), // Collision Layer
|
||||
REC_CONT = MKTAG('C','O','N','T'), // Container
|
||||
REC_CPTH = MKTAG('C','P','T','H'), // Camera Path
|
||||
REC_CREA = MKTAG('C','R','E','A'), // Creature
|
||||
REC_CSTY = MKTAG('C','S','T','Y'), // Combat Style
|
||||
REC_DEBR = MKTAG('D','E','B','R'), // Debris
|
||||
REC_DIAL = MKTAG('D','I','A','L'), // Dialog Topic
|
||||
REC_DLBR = MKTAG('D','L','B','R'), // Dialog Branch
|
||||
REC_DLVW = MKTAG('D','L','V','W'), // Dialog View
|
||||
REC_DOBJ = MKTAG('D','O','B','J'), // Default Object Manager
|
||||
REC_DOOR = MKTAG('D','O','O','R'), // Door
|
||||
REC_DUAL = MKTAG('D','U','A','L'), // Dual Cast Data (possibly unused)
|
||||
//REC_ECZN = MKTAG('E','C','Z','N'), // Encounter Zone
|
||||
REC_EFSH = MKTAG('E','F','S','H'), // Effect Shader
|
||||
REC_ENCH = MKTAG('E','N','C','H'), // Enchantment
|
||||
REC_EQUP = MKTAG('E','Q','U','P'), // Equip Slot (flag-type values)
|
||||
REC_EXPL = MKTAG('E','X','P','L'), // Explosion
|
||||
REC_EYES = MKTAG('E','Y','E','S'), // Eyes
|
||||
REC_FACT = MKTAG('F','A','C','T'), // Faction
|
||||
REC_FLOR = MKTAG('F','L','O','R'), // Flora
|
||||
REC_FLST = MKTAG('F','L','S','T'), // Form List (non-leveled list)
|
||||
REC_FSTP = MKTAG('F','S','T','P'), // Footstep
|
||||
REC_FSTS = MKTAG('F','S','T','S'), // Footstep Set
|
||||
REC_FURN = MKTAG('F','U','R','N'), // Furniture
|
||||
REC_GLOB = MKTAG('G','L','O','B'), // Global Variable
|
||||
REC_GMST = MKTAG('G','M','S','T'), // Game Setting
|
||||
REC_GRAS = MKTAG('G','R','A','S'), // Grass
|
||||
REC_GRUP = MKTAG('G','R','U','P'), // Form Group
|
||||
REC_HAIR = MKTAG('H','A','I','R'), // Hair
|
||||
//REC_HAZD = MKTAG('H','A','Z','D'), // Hazard
|
||||
REC_HDPT = MKTAG('H','D','P','T'), // Head Part
|
||||
REC_IDLE = MKTAG('I','D','L','E'), // Idle Animation
|
||||
REC_IDLM = MKTAG('I','D','L','M'), // Idle Marker
|
||||
REC_IMAD = MKTAG('I','M','A','D'), // Image Space Modifier
|
||||
REC_IMGS = MKTAG('I','M','G','S'), // Image Space
|
||||
REC_INFO = MKTAG('I','N','F','O'), // Dialog Topic Info
|
||||
REC_INGR = MKTAG('I','N','G','R'), // Ingredient
|
||||
REC_IPCT = MKTAG('I','P','C','T'), // Impact Data
|
||||
REC_IPDS = MKTAG('I','P','D','S'), // Impact Data Set
|
||||
REC_KEYM = MKTAG('K','E','Y','M'), // Key
|
||||
REC_KYWD = MKTAG('K','Y','W','D'), // Keyword
|
||||
REC_LAND = MKTAG('L','A','N','D'), // Land
|
||||
REC_LCRT = MKTAG('L','C','R','T'), // Location Reference Type
|
||||
REC_LCTN = MKTAG('L','C','T','N'), // Location
|
||||
REC_LGTM = MKTAG('L','G','T','M'), // Lighting Template
|
||||
REC_LIGH = MKTAG('L','I','G','H'), // Light
|
||||
REC_LSCR = MKTAG('L','S','C','R'), // Load Screen
|
||||
REC_LTEX = MKTAG('L','T','E','X'), // Land Texture
|
||||
REC_LVLC = MKTAG('L','V','L','C'), // Leveled Creature
|
||||
REC_LVLI = MKTAG('L','V','L','I'), // Leveled Item
|
||||
REC_LVLN = MKTAG('L','V','L','N'), // Leveled Actor
|
||||
REC_LVSP = MKTAG('L','V','S','P'), // Leveled Spell
|
||||
REC_MATO = MKTAG('M','A','T','O'), // Material Object
|
||||
REC_MATT = MKTAG('M','A','T','T'), // Material Type
|
||||
REC_MESG = MKTAG('M','E','S','G'), // Message
|
||||
REC_MGEF = MKTAG('M','G','E','F'), // Magic Effect
|
||||
REC_MISC = MKTAG('M','I','S','C'), // Misc. Object
|
||||
REC_MOVT = MKTAG('M','O','V','T'), // Movement Type
|
||||
REC_MSTT = MKTAG('M','S','T','T'), // Movable Static
|
||||
REC_MUSC = MKTAG('M','U','S','C'), // Music Type
|
||||
REC_MUST = MKTAG('M','U','S','T'), // Music Track
|
||||
REC_NAVI = MKTAG('N','A','V','I'), // Navigation (master data)
|
||||
REC_NAVM = MKTAG('N','A','V','M'), // Nav Mesh
|
||||
REC_NPC_ = MKTAG('N','P','C','_'), // Actor (NPC, Creature)
|
||||
REC_OTFT = MKTAG('O','T','F','T'), // Outfit
|
||||
REC_PACK = MKTAG('P','A','C','K'), // AI Package
|
||||
REC_PERK = MKTAG('P','E','R','K'), // Perk
|
||||
REC_PGRE = MKTAG('P','G','R','E'), // Placed grenade
|
||||
REC_PHZD = MKTAG('P','H','Z','D'), // Placed hazard
|
||||
REC_PROJ = MKTAG('P','R','O','J'), // Projectile
|
||||
REC_QUST = MKTAG('Q','U','S','T'), // Quest
|
||||
REC_RACE = MKTAG('R','A','C','E'), // Race / Creature type
|
||||
REC_REFR = MKTAG('R','E','F','R'), // Object Reference
|
||||
REC_REGN = MKTAG('R','E','G','N'), // Region (Audio/Weather)
|
||||
REC_RELA = MKTAG('R','E','L','A'), // Relationship
|
||||
REC_REVB = MKTAG('R','E','V','B'), // Reverb Parameters
|
||||
REC_RFCT = MKTAG('R','F','C','T'), // Visual Effect
|
||||
REC_SBSP = MKTAG('S','B','S','P'), // Subspace (TES4 only?)
|
||||
REC_SCEN = MKTAG('S','C','E','N'), // Scene
|
||||
REC_SCRL = MKTAG('S','C','R','L'), // Scroll
|
||||
REC_SGST = MKTAG('S','G','S','T'), // Sigil Stone
|
||||
REC_SHOU = MKTAG('S','H','O','U'), // Shout
|
||||
REC_SLGM = MKTAG('S','L','G','M'), // Soul Gem
|
||||
REC_SMBN = MKTAG('S','M','B','N'), // Story Manager Branch Node
|
||||
REC_SMEN = MKTAG('S','M','E','N'), // Story Manager Event Node
|
||||
REC_SMQN = MKTAG('S','M','Q','N'), // Story Manager Quest Node
|
||||
REC_SNCT = MKTAG('S','N','C','T'), // Sound Category
|
||||
REC_SNDR = MKTAG('S','N','D','R'), // Sound Reference
|
||||
REC_SOPM = MKTAG('S','O','P','M'), // Sound Output Model
|
||||
REC_SOUN = MKTAG('S','O','U','N'), // Sound
|
||||
REC_SPEL = MKTAG('S','P','E','L'), // Spell
|
||||
REC_SPGD = MKTAG('S','P','G','D'), // Shader Particle Geometry
|
||||
REC_STAT = MKTAG('S','T','A','T'), // Static
|
||||
REC_TACT = MKTAG('T','A','C','T'), // Talking Activator
|
||||
REC_TES4 = MKTAG('T','E','S','4'), // Plugin info
|
||||
REC_TREE = MKTAG('T','R','E','E'), // Tree
|
||||
REC_TXST = MKTAG('T','X','S','T'), // Texture Set
|
||||
REC_VTYP = MKTAG('V','T','Y','P'), // Voice Type
|
||||
REC_WATR = MKTAG('W','A','T','R'), // Water Type
|
||||
REC_WEAP = MKTAG('W','E','A','P'), // Weapon
|
||||
REC_WOOP = MKTAG('W','O','O','P'), // Word Of Power
|
||||
REC_WRLD = MKTAG('W','R','L','D'), // World Space
|
||||
REC_WTHR = MKTAG('W','T','H','R'), // Weather
|
||||
REC_ACRE = MKTAG('A','C','R','E'), // Placed Creature (TES4 only?)
|
||||
REC_PGRD = MKTAG('P','G','R','D'), // Pathgrid (TES4 only?)
|
||||
REC_ROAD = MKTAG('R','O','A','D') // Road (TES4 only?)
|
||||
};
|
||||
|
||||
enum SubRecordTypes
|
||||
{
|
||||
SUB_HEDR = MKTAG('H','E','D','R'),
|
||||
SUB_CNAM = MKTAG('C','N','A','M'),
|
||||
SUB_SNAM = MKTAG('S','N','A','M'), // TES4 only?
|
||||
SUB_MAST = MKTAG('M','A','S','T'),
|
||||
SUB_DATA = MKTAG('D','A','T','A'),
|
||||
SUB_ONAM = MKTAG('O','N','A','M'),
|
||||
SUB_INTV = MKTAG('I','N','T','V'),
|
||||
SUB_INCC = MKTAG('I','N','C','C'),
|
||||
SUB_OFST = MKTAG('O','F','S','T'), // TES4 only?
|
||||
SUB_DELE = MKTAG('D','E','L','E'), // TES4 only?
|
||||
|
||||
SUB_DNAM = MKTAG('D','N','A','M'),
|
||||
SUB_EDID = MKTAG('E','D','I','D'),
|
||||
SUB_FULL = MKTAG('F','U','L','L'),
|
||||
SUB_LTMP = MKTAG('L','T','M','P'),
|
||||
SUB_MHDT = MKTAG('M','H','D','T'),
|
||||
SUB_MNAM = MKTAG('M','N','A','M'),
|
||||
SUB_MODL = MKTAG('M','O','D','L'),
|
||||
SUB_NAM0 = MKTAG('N','A','M','0'),
|
||||
SUB_NAM2 = MKTAG('N','A','M','2'),
|
||||
SUB_NAM3 = MKTAG('N','A','M','3'),
|
||||
SUB_NAM4 = MKTAG('N','A','M','4'),
|
||||
SUB_NAM9 = MKTAG('N','A','M','9'),
|
||||
SUB_NAMA = MKTAG('N','A','M','A'),
|
||||
SUB_PNAM = MKTAG('P','N','A','M'),
|
||||
SUB_RNAM = MKTAG('R','N','A','M'),
|
||||
SUB_TNAM = MKTAG('T','N','A','M'),
|
||||
SUB_UNAM = MKTAG('U','N','A','M'),
|
||||
SUB_WCTR = MKTAG('W','C','T','R'),
|
||||
SUB_WNAM = MKTAG('W','N','A','M'),
|
||||
SUB_XEZN = MKTAG('X','E','Z','N'),
|
||||
SUB_XLCN = MKTAG('X','L','C','N'),
|
||||
SUB_XXXX = MKTAG('X','X','X','X'),
|
||||
SUB_ZNAM = MKTAG('Z','N','A','M'),
|
||||
SUB_MODT = MKTAG('M','O','D','T'),
|
||||
SUB_ICON = MKTAG('I','C','O','N'), // TES4 only?
|
||||
|
||||
SUB_NVER = MKTAG('N','V','E','R'),
|
||||
SUB_NVMI = MKTAG('N','V','M','I'),
|
||||
SUB_NVPP = MKTAG('N','V','P','P'),
|
||||
SUB_NVSI = MKTAG('N','V','S','I'),
|
||||
|
||||
SUB_NVNM = MKTAG('N','V','N','M'),
|
||||
SUB_NNAM = MKTAG('N','N','A','M'),
|
||||
|
||||
SUB_XCLC = MKTAG('X','C','L','C'),
|
||||
SUB_XCLL = MKTAG('X','C','L','L'),
|
||||
SUB_TVDT = MKTAG('T','V','D','T'),
|
||||
SUB_XCGD = MKTAG('X','C','G','D'),
|
||||
SUB_LNAM = MKTAG('L','N','A','M'),
|
||||
SUB_XCLW = MKTAG('X','C','L','W'),
|
||||
SUB_XNAM = MKTAG('X','N','A','M'),
|
||||
SUB_XCLR = MKTAG('X','C','L','R'),
|
||||
SUB_XWCS = MKTAG('X','W','C','S'),
|
||||
SUB_XWCN = MKTAG('X','W','C','N'),
|
||||
SUB_XWCU = MKTAG('X','W','C','U'),
|
||||
SUB_XCWT = MKTAG('X','C','W','T'),
|
||||
SUB_XOWN = MKTAG('X','O','W','N'),
|
||||
SUB_XILL = MKTAG('X','I','L','L'),
|
||||
SUB_XWEM = MKTAG('X','W','E','M'),
|
||||
SUB_XCCM = MKTAG('X','C','C','M'),
|
||||
SUB_XCAS = MKTAG('X','C','A','S'),
|
||||
SUB_XCMO = MKTAG('X','C','M','O'),
|
||||
SUB_XCIM = MKTAG('X','C','I','M'),
|
||||
SUB_XCMT = MKTAG('X','C','M','T'), // TES4 only?
|
||||
SUB_XRNK = MKTAG('X','R','N','K'), // TES4 only?
|
||||
SUB_XGLB = MKTAG('X','G','L','B'), // TES4 only?
|
||||
|
||||
SUB_VNML = MKTAG('V','N','M','L'),
|
||||
SUB_VHGT = MKTAG('V','H','G','T'),
|
||||
SUB_VCLR = MKTAG('V','C','L','R'),
|
||||
SUA_BTXT = MKTAG('B','T','X','T'),
|
||||
SUB_ATXT = MKTAG('A','T','X','T'),
|
||||
SUB_VTXT = MKTAG('V','T','X','T'),
|
||||
SUB_VTEX = MKTAG('V','T','E','X'),
|
||||
|
||||
SUB_HNAM = MKTAG('H','N','A','M'),
|
||||
SUB_GNAM = MKTAG('G','N','A','M'),
|
||||
|
||||
SUB_RCLR = MKTAG('R','C','L','R'),
|
||||
SUB_RPLI = MKTAG('R','P','L','I'),
|
||||
SUB_RPLD = MKTAG('R','P','L','D'),
|
||||
SUB_RDAT = MKTAG('R','D','A','T'),
|
||||
SUB_RDMD = MKTAG('R','D','M','D'), // TES4 only?
|
||||
SUB_RDSD = MKTAG('R','D','S','D'), // TES4 only?
|
||||
SUB_RDGS = MKTAG('R','D','G','S'), // TES4 only?
|
||||
SUB_RDMO = MKTAG('R','D','M','O'),
|
||||
SUB_RDSA = MKTAG('R','D','S','A'),
|
||||
SUB_RDWT = MKTAG('R','D','W','T'),
|
||||
SUB_RDOT = MKTAG('R','D','O','T'),
|
||||
SUB_RDMP = MKTAG('R','D','M','P'),
|
||||
|
||||
SUB_MODB = MKTAG('M','O','D','B'),
|
||||
SUB_OBND = MKTAG('O','B','N','D'),
|
||||
SUB_MODS = MKTAG('M','O','D','S'),
|
||||
|
||||
SUB_NAME = MKTAG('N','A','M','E'),
|
||||
SUB_XMRK = MKTAG('X','M','R','K'),
|
||||
SUB_FNAM = MKTAG('F','N','A','M'),
|
||||
SUB_XSCL = MKTAG('X','S','C','L'),
|
||||
SUB_XTEL = MKTAG('X','T','E','L'),
|
||||
SUB_XTRG = MKTAG('X','T','R','G'),
|
||||
SUB_XSED = MKTAG('X','S','E','D'),
|
||||
SUB_XLOD = MKTAG('X','L','O','D'),
|
||||
SUB_XPCI = MKTAG('X','P','C','I'),
|
||||
SUB_XLOC = MKTAG('X','L','O','C'),
|
||||
SUB_XESP = MKTAG('X','E','S','P'),
|
||||
SUB_XLCM = MKTAG('X','L','C','M'),
|
||||
SUB_XRTM = MKTAG('X','R','T','M'),
|
||||
SUB_XACT = MKTAG('X','A','C','T'),
|
||||
SUB_XCNT = MKTAG('X','C','N','T'),
|
||||
SUB_VMAD = MKTAG('V','M','A','D'),
|
||||
SUB_XPRM = MKTAG('X','P','R','M'),
|
||||
SUB_XMBO = MKTAG('X','M','B','O'),
|
||||
SUB_XPOD = MKTAG('X','P','O','D'),
|
||||
SUB_XRMR = MKTAG('X','R','M','R'),
|
||||
SUB_INAM = MKTAG('I','N','A','M'),
|
||||
SUB_SCHR = MKTAG('S','C','H','R'),
|
||||
SUB_XLRM = MKTAG('X','L','R','M'),
|
||||
SUB_XRGD = MKTAG('X','R','G','D'),
|
||||
SUB_XRDS = MKTAG('X','R','D','S'),
|
||||
SUB_XEMI = MKTAG('X','E','M','I'),
|
||||
SUB_XLIG = MKTAG('X','L','I','G'),
|
||||
SUB_XALP = MKTAG('X','A','L','P'),
|
||||
SUB_XNDP = MKTAG('X','N','D','P'),
|
||||
SUB_XAPD = MKTAG('X','A','P','D'),
|
||||
SUB_XAPR = MKTAG('X','A','P','R'),
|
||||
SUB_XLIB = MKTAG('X','L','I','B'),
|
||||
SUB_XLKR = MKTAG('X','L','K','R'),
|
||||
SUB_XLRT = MKTAG('X','L','R','T'),
|
||||
SUB_XCVL = MKTAG('X','C','V','L'),
|
||||
SUB_XCVR = MKTAG('X','C','V','R'),
|
||||
SUB_XCZA = MKTAG('X','C','Z','A'),
|
||||
SUB_XCZC = MKTAG('X','C','Z','C'),
|
||||
SUB_XFVC = MKTAG('X','F','V','C'),
|
||||
SUB_XHTW = MKTAG('X','H','T','W'),
|
||||
SUB_XIS2 = MKTAG('X','I','S','2'),
|
||||
SUB_XMBR = MKTAG('X','M','B','R'),
|
||||
SUB_XCCP = MKTAG('X','C','C','P'),
|
||||
SUB_XPWR = MKTAG('X','P','W','R'),
|
||||
SUB_XTRI = MKTAG('X','T','R','I'),
|
||||
SUB_XATR = MKTAG('X','A','T','R'),
|
||||
SUB_XPRD = MKTAG('X','P','R','D'),
|
||||
SUB_XPPA = MKTAG('X','P','P','A'),
|
||||
SUB_PDTO = MKTAG('P','D','T','O'),
|
||||
SUB_XLRL = MKTAG('X','L','R','L'),
|
||||
|
||||
SUB_QNAM = MKTAG('Q','N','A','M'),
|
||||
SUB_COCT = MKTAG('C','O','C','T'),
|
||||
SUB_COED = MKTAG('C','O','E','D'),
|
||||
SUB_CNTO = MKTAG('C','N','T','O'),
|
||||
SUB_SCRI = MKTAG('S','C','R','I'),
|
||||
|
||||
SUB_BNAM = MKTAG('B','N','A','M'),
|
||||
|
||||
SUB_BMDT = MKTAG('B','M','D','T'),
|
||||
SUB_MOD2 = MKTAG('M','O','D','2'),
|
||||
SUB_MOD3 = MKTAG('M','O','D','3'),
|
||||
SUB_MOD4 = MKTAG('M','O','D','4'),
|
||||
SUB_MO2B = MKTAG('M','O','2','B'),
|
||||
SUB_MO3B = MKTAG('M','O','3','B'),
|
||||
SUB_MO4B = MKTAG('M','O','4','B'),
|
||||
SUB_MO2T = MKTAG('M','O','2','T'),
|
||||
SUB_MO3T = MKTAG('M','O','3','T'),
|
||||
SUB_MO4T = MKTAG('M','O','4','T'),
|
||||
SUB_ANAM = MKTAG('A','N','A','M'),
|
||||
SUB_ENAM = MKTAG('E','N','A','M'),
|
||||
SUB_ICO2 = MKTAG('I','C','O','2'),
|
||||
|
||||
SUB_ACBS = MKTAG('A','C','B','S'),
|
||||
SUB_SPLO = MKTAG('S','P','L','O'),
|
||||
SUB_AIDT = MKTAG('A','I','D','T'),
|
||||
SUB_PKID = MKTAG('P','K','I','D'),
|
||||
SUB_HCLR = MKTAG('H','C','L','R'),
|
||||
SUB_FGGS = MKTAG('F','G','G','S'),
|
||||
SUB_FGGA = MKTAG('F','G','G','A'),
|
||||
SUB_FGTS = MKTAG('F','G','T','S'),
|
||||
SUB_KFFZ = MKTAG('K','F','F','Z'),
|
||||
|
||||
SUB_PFIG = MKTAG('P','F','I','G'),
|
||||
SUB_PFPC = MKTAG('P','F','P','C'),
|
||||
|
||||
SUB_XHRS = MKTAG('X','H','R','S'),
|
||||
SUB_XMRC = MKTAG('X','M','R','C'),
|
||||
|
||||
SUB_SNDD = MKTAG('S','N','D','D'),
|
||||
SUB_SNDX = MKTAG('S','N','D','X'),
|
||||
|
||||
SUB_DESC = MKTAG('D','E','S','C'),
|
||||
|
||||
SUB_ENIT = MKTAG('E','N','I','T'),
|
||||
SUB_EFID = MKTAG('E','F','I','D'),
|
||||
SUB_EFIT = MKTAG('E','F','I','T'),
|
||||
SUB_SCIT = MKTAG('S','C','I','T'),
|
||||
|
||||
SUB_SOUL = MKTAG('S','O','U','L'),
|
||||
SUB_SLCP = MKTAG('S','L','C','P'),
|
||||
|
||||
SUB_CSCR = MKTAG('C','S','C','R'),
|
||||
SUB_CSDI = MKTAG('C','S','D','I'),
|
||||
SUB_CSDC = MKTAG('C','S','D','C'),
|
||||
SUB_NIFZ = MKTAG('N','I','F','Z'),
|
||||
SUB_CSDT = MKTAG('C','S','D','T'),
|
||||
SUB_NAM1 = MKTAG('N','A','M','1'),
|
||||
SUB_NIFT = MKTAG('N','I','F','T'),
|
||||
|
||||
SUB_LVLD = MKTAG('L','V','L','D'),
|
||||
SUB_LVLF = MKTAG('L','V','L','F'),
|
||||
SUB_LVLO = MKTAG('L','V','L','O'),
|
||||
|
||||
SUB_BODT = MKTAG('B','O','D','T'),
|
||||
SUB_YNAM = MKTAG('Y','N','A','M'),
|
||||
SUB_DEST = MKTAG('D','E','S','T'),
|
||||
SUB_DMDL = MKTAG('D','M','D','L'),
|
||||
SUB_DMDS = MKTAG('D','M','D','S'),
|
||||
SUB_DMDT = MKTAG('D','M','D','T'),
|
||||
SUB_DSTD = MKTAG('D','S','T','D'),
|
||||
SUB_DSTF = MKTAG('D','S','T','F'),
|
||||
SUB_KNAM = MKTAG('K','N','A','M'),
|
||||
SUB_KSIZ = MKTAG('K','S','I','Z'),
|
||||
SUB_KWDA = MKTAG('K','W','D','A'),
|
||||
SUB_VNAM = MKTAG('V','N','A','M'),
|
||||
SUB_SDSC = MKTAG('S','D','S','C'),
|
||||
SUB_MO2S = MKTAG('M','O','2','S'),
|
||||
SUB_MO4S = MKTAG('M','O','4','S'),
|
||||
SUB_BOD2 = MKTAG('B','O','D','2'),
|
||||
SUB_BAMT = MKTAG('B','A','M','T'),
|
||||
SUB_BIDS = MKTAG('B','I','D','S'),
|
||||
SUB_ETYP = MKTAG('E','T','Y','P'),
|
||||
SUB_BMCT = MKTAG('B','M','C','T'),
|
||||
SUB_MICO = MKTAG('M','I','C','O'),
|
||||
SUB_MIC2 = MKTAG('M','I','C','2'),
|
||||
SUB_EAMT = MKTAG('E','A','M','T'),
|
||||
SUB_EITM = MKTAG('E','I','T','M'),
|
||||
|
||||
SUB_SCTX = MKTAG('S','C','T','X'),
|
||||
SUB_XLTW = MKTAG('X','L','T','W'),
|
||||
SUB_XMBP = MKTAG('X','M','B','P'),
|
||||
SUB_XOCP = MKTAG('X','O','C','P'),
|
||||
SUB_XRGB = MKTAG('X','R','G','B'),
|
||||
SUB_XSPC = MKTAG('X','S','P','C'),
|
||||
SUB_XTNM = MKTAG('X','T','N','M'),
|
||||
SUB_ATKR = MKTAG('A','T','K','R'),
|
||||
SUB_CRIF = MKTAG('C','R','I','F'),
|
||||
SUB_DOFT = MKTAG('D','O','F','T'),
|
||||
SUB_DPLT = MKTAG('D','P','L','T'),
|
||||
SUB_ECOR = MKTAG('E','C','O','R'),
|
||||
SUB_ATKD = MKTAG('A','T','K','D'),
|
||||
SUB_ATKE = MKTAG('A','T','K','E'),
|
||||
SUB_FTST = MKTAG('F','T','S','T'),
|
||||
SUB_HCLF = MKTAG('H','C','L','F'),
|
||||
SUB_NAM5 = MKTAG('N','A','M','5'),
|
||||
SUB_NAM6 = MKTAG('N','A','M','6'),
|
||||
SUB_NAM7 = MKTAG('N','A','M','7'),
|
||||
SUB_NAM8 = MKTAG('N','A','M','8'),
|
||||
SUB_PRKR = MKTAG('P','R','K','R'),
|
||||
SUB_PRKZ = MKTAG('P','R','K','Z'),
|
||||
SUB_SOFT = MKTAG('S','O','F','T'),
|
||||
SUB_SPCT = MKTAG('S','P','C','T'),
|
||||
SUB_TINC = MKTAG('T','I','N','C'),
|
||||
SUB_TIAS = MKTAG('T','I','A','S'),
|
||||
SUB_TINI = MKTAG('T','I','N','I'),
|
||||
SUB_TINV = MKTAG('T','I','N','V'),
|
||||
SUB_TPLT = MKTAG('T','P','L','T'),
|
||||
SUB_VTCK = MKTAG('V','T','C','K'),
|
||||
SUB_SHRT = MKTAG('S','H','R','T'),
|
||||
SUB_SPOR = MKTAG('S','P','O','R'),
|
||||
SUB_XHOR = MKTAG('X','H','O','R'),
|
||||
SUB_CTDA = MKTAG('C','T','D','A'),
|
||||
SUB_CRDT = MKTAG('C','R','D','T'),
|
||||
SUB_FNMK = MKTAG('F','N','M','K'),
|
||||
SUB_FNPR = MKTAG('F','N','P','R'),
|
||||
SUB_WBDT = MKTAG('W','B','D','T'),
|
||||
SUB_QUAL = MKTAG('Q','U','A','L'),
|
||||
SUB_INDX = MKTAG('I','N','D','X'),
|
||||
SUB_ATTR = MKTAG('A','T','T','R'),
|
||||
|
||||
SUB_XHLT = MKTAG('X','H','L','T'), // Unofficial Oblivion Patch
|
||||
SUB_XCHG = MKTAG('X','C','H','G'), // thievery.exp
|
||||
|
||||
SUB_XIBS = MKTAG('X','I','B','S'), // FO3
|
||||
SUB_REPL = MKTAG('R','E','P','L'), // FO3
|
||||
SUB_BIPL = MKTAG('B','I','P','L'), // FO3
|
||||
SUB_MODD = MKTAG('M','O','D','D'), // FO3
|
||||
SUB_MOSD = MKTAG('M','O','S','D'), // FO3
|
||||
SUB_MO3S = MKTAG('M','O','3','S'), // FO3
|
||||
SUB_XCET = MKTAG('X','C','E','T'), // FO3
|
||||
SUB_LVLG = MKTAG('L','V','L','G'), // FO3
|
||||
SUB_NVCI = MKTAG('N','V','C','I'), // FO3
|
||||
SUB_NVVX = MKTAG('N','V','V','X'), // FO3
|
||||
SUB_NVTR = MKTAG('N','V','T','R'), // FO3
|
||||
SUB_NVCA = MKTAG('N','V','C','A'), // FO3
|
||||
SUB_NVDP = MKTAG('N','V','D','P'), // FO3
|
||||
SUB_NVGD = MKTAG('N','V','G','D'), // FO3
|
||||
SUB_NVEX = MKTAG('N','V','E','X'), // FO3
|
||||
SUB_XHLP = MKTAG('X','H','L','P'), // FO3
|
||||
SUB_XRDO = MKTAG('X','R','D','O'), // FO3
|
||||
SUB_XAMT = MKTAG('X','A','M','T'), // FO3
|
||||
SUB_XAMC = MKTAG('X','A','M','C'), // FO3
|
||||
SUB_XRAD = MKTAG('X','R','A','D'), // FO3
|
||||
SUB_XORD = MKTAG('X','O','R','D'), // FO3
|
||||
SUB_XCLP = MKTAG('X','C','L','P'), // FO3
|
||||
SUB_SCDA = MKTAG('S','C','D','A'), // FO3
|
||||
SUB_SCRO = MKTAG('S','C','R','O'), // FO3
|
||||
SUB_IMPS = MKTAG('I','M','P','S'), // FO3 Anchorage
|
||||
SUB_IMPF = MKTAG('I','M','P','F'), // FO3 Anchorage
|
||||
|
||||
SUB_XATO = MKTAG('X','A','T','O'), // FONV
|
||||
SUB_DAT2 = MKTAG('D','A','T','2'), // FONV
|
||||
SUB_RCIL = MKTAG('R','C','I','L'), // FONV
|
||||
SUB_MMRK = MKTAG('M','M','R','K'), // FONV
|
||||
SUB_SCRV = MKTAG('S','C','R','V'), // FONV
|
||||
SUB_SCVR = MKTAG('S','C','V','R'), // FONV
|
||||
SUB_SLSD = MKTAG('S','L','S','D'), // FONV
|
||||
SUB_XSRF = MKTAG('X','S','R','F'), // FONV
|
||||
SUB_XSRD = MKTAG('X','S','R','D'), // FONV
|
||||
SUB_WMI1 = MKTAG('W','M','I','1'), // FONV
|
||||
SUB_RDID = MKTAG('R','D','I','D'), // FONV
|
||||
SUB_RDSB = MKTAG('R','D','S','B'), // FONV
|
||||
SUB_RDSI = MKTAG('R','D','S','I'), // FONV
|
||||
SUB_BRUS = MKTAG('B','R','U','S'), // FONV
|
||||
SUB_VATS = MKTAG('V','A','T','S'), // FONV
|
||||
SUB_VANM = MKTAG('V','A','N','M'), // FONV
|
||||
SUB_MWD1 = MKTAG('M','W','D','1'), // FONV
|
||||
SUB_MWD2 = MKTAG('M','W','D','2'), // FONV
|
||||
SUB_MWD3 = MKTAG('M','W','D','3'), // FONV
|
||||
SUB_MWD4 = MKTAG('M','W','D','4'), // FONV
|
||||
SUB_MWD5 = MKTAG('M','W','D','5'), // FONV
|
||||
SUB_MWD6 = MKTAG('M','W','D','6'), // FONV
|
||||
SUB_MWD7 = MKTAG('M','W','D','7'), // FONV
|
||||
SUB_WMI2 = MKTAG('W','M','I','2'), // FONV
|
||||
SUB_WMI3 = MKTAG('W','M','I','3'), // FONV
|
||||
SUB_WMS1 = MKTAG('W','M','S','1'), // FONV
|
||||
SUB_WMS2 = MKTAG('W','M','S','2'), // FONV
|
||||
SUB_WNM1 = MKTAG('W','N','M','1'), // FONV
|
||||
SUB_WNM2 = MKTAG('W','N','M','2'), // FONV
|
||||
SUB_WNM3 = MKTAG('W','N','M','3'), // FONV
|
||||
SUB_WNM4 = MKTAG('W','N','M','4'), // FONV
|
||||
SUB_WNM5 = MKTAG('W','N','M','5'), // FONV
|
||||
SUB_WNM6 = MKTAG('W','N','M','6'), // FONV
|
||||
SUB_WNM7 = MKTAG('W','N','M','7'), // FONV
|
||||
};
|
||||
|
||||
enum MagicEffectID
|
||||
{
|
||||
// Alteration
|
||||
EFI_BRDN = MKTAG('B','R','D','N'),
|
||||
EFI_FTHR = MKTAG('F','T','H','R'),
|
||||
EFI_FISH = MKTAG('F','I','S','H'),
|
||||
EFI_FRSH = MKTAG('F','R','S','H'),
|
||||
EFI_OPEN = MKTAG('O','P','N','N'),
|
||||
EFI_SHLD = MKTAG('S','H','L','D'),
|
||||
EFI_LISH = MKTAG('L','I','S','H'),
|
||||
EFI_WABR = MKTAG('W','A','B','R'),
|
||||
EFI_WAWA = MKTAG('W','A','W','A'),
|
||||
|
||||
// Conjuration
|
||||
EFI_BABO = MKTAG('B','A','B','O'), // Bound Boots
|
||||
EFI_BACU = MKTAG('B','A','C','U'), // Bound Cuirass
|
||||
EFI_BAGA = MKTAG('B','A','G','A'), // Bound Gauntlets
|
||||
EFI_BAGR = MKTAG('B','A','G','R'), // Bound Greaves
|
||||
EFI_BAHE = MKTAG('B','A','H','E'), // Bound Helmet
|
||||
EFI_BASH = MKTAG('B','A','S','H'), // Bound Shield
|
||||
EFI_BWAX = MKTAG('B','W','A','X'), // Bound Axe
|
||||
EFI_BWBO = MKTAG('B','W','B','O'), // Bound Bow
|
||||
EFI_BWDA = MKTAG('B','W','D','A'), // Bound Dagger
|
||||
EFI_BWMA = MKTAG('B','W','M','A'), // Bound Mace
|
||||
EFI_BWSW = MKTAG('B','W','S','W'), // Bound Sword
|
||||
EFI_Z001 = MKTAG('Z','0','0','1'), // Summon Rufio's Ghost
|
||||
EFI_Z002 = MKTAG('Z','0','0','2'), // Summon Ancestor Guardian
|
||||
EFI_Z003 = MKTAG('Z','0','0','3'), // Summon Spiderling
|
||||
EFI_Z005 = MKTAG('Z','0','0','5'), // Summon Bear
|
||||
EFI_ZCLA = MKTAG('Z','C','L','A'), // Summon Clannfear
|
||||
EFI_ZDAE = MKTAG('Z','D','A','E'), // Summon Daedroth
|
||||
EFI_ZDRE = MKTAG('Z','D','R','E'), // Summon Dremora
|
||||
EFI_ZDRL = MKTAG('Z','D','R','L'), // Summon Dremora Lord
|
||||
EFI_ZFIA = MKTAG('Z','F','I','A'), // Summon Flame Atronach
|
||||
EFI_ZFRA = MKTAG('Z','F','R','A'), // Summon Frost Atronach
|
||||
EFI_ZGHO = MKTAG('Z','G','H','O'), // Summon Ghost
|
||||
EFI_ZHDZ = MKTAG('Z','H','D','Z'), // Summon Headless Zombie
|
||||
EFI_ZLIC = MKTAG('Z','L','I','C'), // Summon Lich
|
||||
EFI_ZSCA = MKTAG('Z','S','C','A'), // Summon Scamp
|
||||
EFI_ZSKE = MKTAG('Z','S','K','E'), // Summon Skeleton
|
||||
EFI_ZSKA = MKTAG('Z','S','K','A'), // Summon Skeleton Guardian
|
||||
EFI_ZSKH = MKTAG('Z','S','K','H'), // Summon Skeleton Hero
|
||||
EFI_ZSKC = MKTAG('Z','S','K','C'), // Summon Skeleton Champion
|
||||
EFI_ZSPD = MKTAG('Z','S','P','D'), // Summon Spider Daedra
|
||||
EFI_ZSTA = MKTAG('Z','S','T','A'), // Summon Storm Atronach
|
||||
EFI_ZWRA = MKTAG('Z','W','R','A'), // Summon Faded Wraith
|
||||
EFI_ZWRL = MKTAG('Z','W','R','L'), // Summon Gloom Wraith
|
||||
EFI_ZXIV = MKTAG('Z','X','I','V'), // Summon Xivilai
|
||||
EFI_ZZOM = MKTAG('Z','Z','O','M'), // Summon Zombie
|
||||
EFI_TURN = MKTAG('T','U','R','N'), // Turn Undead
|
||||
|
||||
// Destruction
|
||||
EFI_DGAT = MKTAG('D','G','A','T'), // Damage Attribute
|
||||
EFI_DGFA = MKTAG('D','G','F','A'), // Damage Fatigue
|
||||
EFI_DGHE = MKTAG('D','G','H','E'), // Damage Health
|
||||
EFI_DGSP = MKTAG('D','G','S','P'), // Damage Magicka
|
||||
EFI_DIAR = MKTAG('D','I','A','R'), // Disintegrate Armor
|
||||
EFI_DIWE = MKTAG('D','I','W','E'), // Disintegrate Weapon
|
||||
EFI_DRAT = MKTAG('D','R','A','T'), // Drain Attribute
|
||||
EFI_DRFA = MKTAG('D','R','F','A'), // Drain Fatigue
|
||||
EFI_DRHE = MKTAG('D','R','H','E'), // Drain Health
|
||||
EFI_DRSP = MKTAG('D','R','S','P'), // Drain Magicka
|
||||
EFI_DRSK = MKTAG('D','R','S','K'), // Drain Skill
|
||||
EFI_FIDG = MKTAG('F','I','D','G'), // Fire Damage
|
||||
EFI_FRDG = MKTAG('F','R','D','G'), // Frost Damage
|
||||
EFI_SHDG = MKTAG('S','H','D','G'), // Shock Damage
|
||||
EFI_WKDI = MKTAG('W','K','D','I'), // Weakness to Disease
|
||||
EFI_WKFI = MKTAG('W','K','F','I'), // Weakness to Fire
|
||||
EFI_WKFR = MKTAG('W','K','F','R'), // Weakness to Frost
|
||||
EFI_WKMA = MKTAG('W','K','M','A'), // Weakness to Magic
|
||||
EFI_WKNW = MKTAG('W','K','N','W'), // Weakness to Normal Weapons
|
||||
EFI_WKPO = MKTAG('W','K','P','O'), // Weakness to Poison
|
||||
EFI_WKSH = MKTAG('W','K','S','H'), // Weakness to Shock
|
||||
|
||||
// Illusion
|
||||
EFI_CALM = MKTAG('C','A','L','M'), // Calm
|
||||
EFI_CHML = MKTAG('C','H','M','L'), // Chameleon
|
||||
EFI_CHRM = MKTAG('C','H','R','M'), // Charm
|
||||
EFI_COCR = MKTAG('C','O','C','R'), // Command Creature
|
||||
EFI_COHU = MKTAG('C','O','H','U'), // Command Humanoid
|
||||
EFI_DEMO = MKTAG('D','E','M','O'), // Demoralize
|
||||
EFI_FRNZ = MKTAG('F','R','N','Z'), // Frenzy
|
||||
EFI_INVI = MKTAG('I','N','V','I'), // Invisibility
|
||||
EFI_LGHT = MKTAG('L','G','H','T'), // Light
|
||||
EFI_NEYE = MKTAG('N','E','Y','E'), // Night-Eye
|
||||
EFI_PARA = MKTAG('P','A','R','A'), // Paralyze
|
||||
EFI_RALY = MKTAG('R','A','L','Y'), // Rally
|
||||
EFI_SLNC = MKTAG('S','L','N','C'), // Silence
|
||||
|
||||
// Mysticism
|
||||
EFI_DTCT = MKTAG('D','T','C','T'), // Detect Life
|
||||
EFI_DSPL = MKTAG('D','S','P','L'), // Dispel
|
||||
EFI_REDG = MKTAG('R','E','D','G'), // Reflect Damage
|
||||
EFI_RFLC = MKTAG('R','F','L','C'), // Reflect Spell
|
||||
EFI_STRP = MKTAG('S','T','R','P'), // Soul Trap
|
||||
EFI_SABS = MKTAG('S','A','B','S'), // Spell Absorption
|
||||
EFI_TELE = MKTAG('T','E','L','E'), // Telekinesis
|
||||
|
||||
// Restoration
|
||||
EFI_ABAT = MKTAG('A','B','A','T'), // Absorb Attribute
|
||||
EFI_ABFA = MKTAG('A','B','F','A'), // Absorb Fatigue
|
||||
EFI_ABHe = MKTAG('A','B','H','e'), // Absorb Health
|
||||
EFI_ABSP = MKTAG('A','B','S','P'), // Absorb Magicka
|
||||
EFI_ABSK = MKTAG('A','B','S','K'), // Absorb Skill
|
||||
EFI_1400 = MKTAG('1','4','0','0'), // Cure Disease
|
||||
EFI_CUPA = MKTAG('C','U','P','A'), // Cure Paralysis
|
||||
EFI_CUPO = MKTAG('C','U','P','O'), // Cure Poison
|
||||
EFI_FOAT = MKTAG('F','O','A','T'), // Fortify Attribute
|
||||
EFI_FOFA = MKTAG('F','O','F','A'), // Fortify Fatigue
|
||||
EFI_FOHE = MKTAG('F','O','H','E'), // Fortify Health
|
||||
EFI_FOSP = MKTAG('F','O','S','P'), // Fortify Magicka
|
||||
EFI_FOSK = MKTAG('F','O','S','K'), // Fortify Skill
|
||||
EFI_RSDI = MKTAG('R','S','D','I'), // Resist Disease
|
||||
EFI_RSFI = MKTAG('R','S','F','I'), // Resist Fire
|
||||
EFI_RSFR = MKTAG('R','S','F','R'), // Resist Frost
|
||||
EFI_RSMA = MKTAG('R','S','M','A'), // Resist Magic
|
||||
EFI_RSNW = MKTAG('R','S','N','W'), // Resist Normal Weapons
|
||||
EFI_RSPA = MKTAG('R','S','P','A'), // Resist Paralysis
|
||||
EFI_RSPO = MKTAG('R','S','P','O'), // Resist Poison
|
||||
EFI_RSSH = MKTAG('R','S','S','H'), // Resist Shock
|
||||
EFI_REAT = MKTAG('R','E','A','T'), // Restore Attribute
|
||||
EFI_REFA = MKTAG('R','E','F','A'), // Restore Fatigue
|
||||
EFI_REHE = MKTAG('R','E','H','E'), // Restore Health
|
||||
EFI_RESP = MKTAG('R','E','S','P'), // Restore Magicka
|
||||
|
||||
// Effects
|
||||
EFI_LOCK = MKTAG('L','O','C','K'), // Lock Lock
|
||||
EFI_SEFF = MKTAG('S','E','F','F'), // Script Effect
|
||||
EFI_Z020 = MKTAG('Z','0','2','0'), // Summon 20 Extra
|
||||
EFI_MYHL = MKTAG('M','Y','H','L'), // Summon Mythic Dawn Helmet
|
||||
EFI_MYTH = MKTAG('M','Y','T','H'), // Summon Mythic Dawn Armor
|
||||
EFI_REAN = MKTAG('R','E','A','N'), // Reanimate
|
||||
EFI_DISE = MKTAG('D','I','S','E'), // Disease Info
|
||||
EFI_POSN = MKTAG('P','O','S','N'), // Poison Info
|
||||
EFI_DUMY = MKTAG('D','U','M','Y'), // Mehrunes Dagon Custom Effect
|
||||
EFI_STMA = MKTAG('S','T','M','A'), // Stunted Magicka
|
||||
EFI_SUDG = MKTAG('S','U','D','G'), // Sun Damage
|
||||
EFI_VAMP = MKTAG('V','A','M','P'), // Vampirism
|
||||
EFI_DARK = MKTAG('D','A','R','K'), // Darkness
|
||||
EFI_RSWD = MKTAG('R','S','W','D') // Resist Water Damage
|
||||
};
|
||||
|
||||
// Based on http://www.uesp.net/wiki/Tes5Mod:Mod_File_Format#Groups
|
||||
enum GroupType
|
||||
{
|
||||
Grp_RecordType = 0,
|
||||
Grp_WorldChild = 1,
|
||||
Grp_InteriorCell = 2,
|
||||
Grp_InteriorSubCell = 3,
|
||||
Grp_ExteriorCell = 4,
|
||||
Grp_ExteriorSubCell = 5,
|
||||
Grp_CellChild = 6,
|
||||
Grp_TopicChild = 7,
|
||||
Grp_CellPersistentChild = 8,
|
||||
Grp_CellTemporaryChild = 9,
|
||||
Grp_CellVisibleDistChild = 10
|
||||
};
|
||||
|
||||
// Based on http://www.uesp.net/wiki/Tes5Mod:Mod_File_Format#Records
|
||||
enum RecordFlag
|
||||
{
|
||||
Rec_ESM = 0x00000001, // (TES4 record only) Master (ESM) file.
|
||||
Rec_Deleted = 0x00000020, // Deleted
|
||||
Rec_Constant = 0x00000040, // Constant
|
||||
Rec_HiddenLMap = 0x00000040, // (REFR) Hidden From Local Map (Needs Confirmation: Related to shields)
|
||||
Rec_Localized = 0x00000080, // (TES4 record only) Is localized. This will make Skyrim load the
|
||||
// .STRINGS, .DLSTRINGS, and .ILSTRINGS files associated with the mod.
|
||||
// If this flag is not set, lstrings are treated as zstrings.
|
||||
Rec_FireOff = 0x00000080, // (PHZD) Turn off fire
|
||||
Rec_UpdateAnim = 0x00000100, // Must Update Anims
|
||||
Rec_NoAccess = 0x00000100, // (REFR) Inaccessible
|
||||
Rec_Hidden = 0x00000200, // (REFR) Hidden from local map
|
||||
Rec_StartDead = 0x00000200, // (ACHR) Starts dead /(REFR) MotionBlurCastsShadows
|
||||
Rec_Persistent = 0x00000400, // Quest item / Persistent reference
|
||||
Rec_DispMenu = 0x00000400, // (LSCR) Displays in Main Menu
|
||||
Rec_Disabled = 0x00000800, // Initially disabled
|
||||
Rec_Ignored = 0x00001000, // Ignored
|
||||
Rec_DistVis = 0x00008000, // Visible when distant
|
||||
Rec_RandAnim = 0x00010000, // (ACTI) Random Animation Start
|
||||
Rec_Danger = 0x00020000, // (ACTI) Dangerous / Off limits (Interior cell)
|
||||
// Dangerous Can't be set withough Ignore Object Interaction
|
||||
Rec_Compressed = 0x00040000, // Data is compressed
|
||||
Rec_CanNotWait = 0x00080000, // Can't wait
|
||||
Rec_IgnoreObj = 0x00100000, // (ACTI) Ignore Object Interaction
|
||||
// Ignore Object Interaction Sets Dangerous Automatically
|
||||
Rec_Marker = 0x00800000, // Is Marker
|
||||
Rec_Obstacle = 0x02000000, // (ACTI) Obstacle / (REFR) No AI Acquire
|
||||
Rec_NavMFilter = 0x04000000, // NavMesh Gen - Filter
|
||||
Rec_NavMBBox = 0x08000000, // NavMesh Gen - Bounding Box
|
||||
Rec_ExitToTalk = 0x10000000, // (FURN) Must Exit to Talk
|
||||
Rec_Refected = 0x10000000, // (REFR) Reflected By Auto Water
|
||||
Rec_ChildUse = 0x20000000, // (FURN/IDLM) Child Can Use
|
||||
Rec_NoHavok = 0x20000000, // (REFR) Don't Havok Settle
|
||||
Rec_NavMGround = 0x40000000, // NavMesh Gen - Ground
|
||||
Rec_NoRespawn = 0x40000000, // (REFR) NoRespawn
|
||||
Rec_MultiBound = 0x80000000 // (REFR) MultiBound
|
||||
};
|
||||
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
// NOTE: the label field of a group is not reliable (http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format)
|
||||
union GroupLabel
|
||||
{
|
||||
std::uint32_t value; // formId, blockNo or raw int representation of type
|
||||
char recordType[4]; // record type in ascii
|
||||
std::int16_t grid[2]; // grid y, x (note the reverse order)
|
||||
};
|
||||
|
||||
union TypeId
|
||||
{
|
||||
std::uint32_t value;
|
||||
char name[4]; // record type in ascii
|
||||
};
|
||||
|
||||
struct GroupTypeHeader
|
||||
{
|
||||
std::uint32_t typeId;
|
||||
std::uint32_t groupSize; // includes the 24 bytes (20 for TES4) of header (i.e. this struct)
|
||||
GroupLabel label; // format based on type
|
||||
std::int32_t type;
|
||||
std::uint16_t stamp; // & 0xff for day, & 0xff00 for months since Dec 2002 (i.e. 1 = Jan 2003)
|
||||
std::uint16_t unknown;
|
||||
std::uint16_t version; // not in TES4
|
||||
std::uint16_t unknown2; // not in TES4
|
||||
};
|
||||
|
||||
struct RecordTypeHeader
|
||||
{
|
||||
std::uint32_t typeId;
|
||||
std::uint32_t dataSize; // does *not* include 24 bytes (20 for TES4) of header
|
||||
std::uint32_t flags;
|
||||
FormId id;
|
||||
std::uint32_t revision;
|
||||
std::uint16_t version; // not in TES4
|
||||
std::uint16_t unknown; // not in TES4
|
||||
};
|
||||
|
||||
union RecordHeader
|
||||
{
|
||||
struct GroupTypeHeader group;
|
||||
struct RecordTypeHeader record;
|
||||
};
|
||||
|
||||
struct SubRecordHeader
|
||||
{
|
||||
std::uint32_t typeId;
|
||||
std::uint16_t dataSize;
|
||||
};
|
||||
|
||||
// Grid, CellGrid and Vertex are shared by NVMI(NAVI) and NVNM(NAVM)
|
||||
|
||||
struct Grid
|
||||
{
|
||||
std::int16_t x;
|
||||
std::int16_t y;
|
||||
};
|
||||
|
||||
union CellGrid
|
||||
{
|
||||
FormId cellId;
|
||||
Grid grid;
|
||||
};
|
||||
|
||||
struct Vector3
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
|
||||
typedef Vector3 Vertex;
|
||||
|
||||
// REFR, ACHR, ACRE
|
||||
struct Position
|
||||
{
|
||||
Vector3 pos;
|
||||
Vector3 rot; // angles are in radian, rz applied first and rx applied last
|
||||
};
|
||||
|
||||
// REFR, ACHR, ACRE
|
||||
struct EnableParent
|
||||
{
|
||||
FormId parent;
|
||||
std::uint32_t flags; //0x0001 = Set Enable State Opposite Parent, 0x0002 = Pop In
|
||||
};
|
||||
|
||||
// LVLC, LVLI
|
||||
struct LVLO
|
||||
{
|
||||
std::int16_t level;
|
||||
std::uint16_t unknown; // sometimes missing
|
||||
FormId item;
|
||||
std::int16_t count;
|
||||
std::uint16_t unknown2; // sometimes missing
|
||||
};
|
||||
|
||||
struct InventoryItem // NPC_, CREA, CONT
|
||||
{
|
||||
FormId item;
|
||||
std::uint32_t count;
|
||||
};
|
||||
|
||||
struct AIData // NPC_, CREA
|
||||
{
|
||||
std::uint8_t aggression;
|
||||
std::uint8_t confidence;
|
||||
std::uint8_t energyLevel;
|
||||
std::uint8_t responsibility;
|
||||
std::uint32_t aiFlags;
|
||||
std::uint8_t trainSkill;
|
||||
std::uint8_t trainLevel;
|
||||
std::uint16_t unknown;
|
||||
};
|
||||
|
||||
struct AttributeValues
|
||||
{
|
||||
std::uint8_t strength;
|
||||
std::uint8_t intelligence;
|
||||
std::uint8_t willpower;
|
||||
std::uint8_t agility;
|
||||
std::uint8_t speed;
|
||||
std::uint8_t endurance;
|
||||
std::uint8_t personality;
|
||||
std::uint8_t luck;
|
||||
};
|
||||
|
||||
struct ActorBaseConfig
|
||||
{
|
||||
#if 0
|
||||
enum ACBS_NPC
|
||||
{
|
||||
ACBS_Female = 0x000001,
|
||||
ACBS_Essential = 0x000002,
|
||||
ACBS_Respawn = 0x000008,
|
||||
ACBS_Autocalcstats = 0x000010,
|
||||
ACBS_PCLevelOffset = 0x000080,
|
||||
ACBS_NoLowLevelProcessing = 0x000200,
|
||||
ACBS_NoRumors = 0x002000,
|
||||
ACBS_Summonable = 0x004000,
|
||||
ACBS_NoPersuasion = 0x008000, // different meaning to crea
|
||||
ACBS_CanCorpseCheck = 0x100000 // opposite of crea
|
||||
};
|
||||
|
||||
enum ACBS_CREA
|
||||
{
|
||||
ACBS_Essential = 0x000002,
|
||||
ACBS_WeapAndShield = 0x000004,
|
||||
ACBS_Respawn = 0x000008,
|
||||
ACBS_PCLevelOffset = 0x000080,
|
||||
ACBS_NoLowLevelProcessing = 0x000200,
|
||||
ACBS_NoHead = 0x008000, // different meaning to npc_
|
||||
ACBS_NoRightArm = 0x010000,
|
||||
ACBS_NoLeftArm = 0x020000,
|
||||
ACBS_NoCombatWater = 0x040000,
|
||||
ACBS_NoShadow = 0x080000,
|
||||
ACBS_NoCorpseCheck = 0x100000 // opposite of npc_
|
||||
};
|
||||
#endif
|
||||
std::uint32_t flags;
|
||||
std::uint16_t baseSpell; // Base spell points
|
||||
std::uint16_t fatigue; // Fatigue
|
||||
std::uint16_t barterGold; // Barter gold
|
||||
std::int16_t level; // Level/Offset level
|
||||
std::uint16_t calcMin; // Calc Min
|
||||
std::uint16_t calcMax; // Calc Max
|
||||
};
|
||||
|
||||
struct ActorFaction
|
||||
{
|
||||
FormId faction;
|
||||
std::int8_t rank;
|
||||
std::uint8_t unknown1;
|
||||
std::uint8_t unknown2;
|
||||
std::uint8_t unknown3;
|
||||
};
|
||||
|
||||
union EFI_Label
|
||||
{
|
||||
std::uint32_t value;
|
||||
char effect[4];
|
||||
};
|
||||
|
||||
struct ScriptEffect
|
||||
{
|
||||
FormId formId; // Script effect (Magic effect must be SEFF)
|
||||
std::int32_t school; // Magic school. See Magic schools for more information.
|
||||
EFI_Label visualEffect; // Visual effect name or 0x00000000 if None
|
||||
std::uint8_t flags; // 0x01 = Hostile
|
||||
std::uint8_t unknown1;
|
||||
std::uint8_t unknown2;
|
||||
std::uint8_t unknown3;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// For pretty printing GroupHeader labels
|
||||
std::string printLabel(const GroupLabel& label, const std::uint32_t type);
|
||||
|
||||
std::string printName(const std::uint32_t typeId);
|
||||
|
||||
void gridToString(std::int16_t x, std::int16_t y, std::string& str);
|
||||
}
|
||||
|
||||
#endif // ESM4_COMMON_H
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "cont.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Container::Container() : mFormId(0), mFlags(0), mBoundRadius(0.f), mDataFlags(0), mWeight(0.f),
|
||||
mOpenSound(0), mCloseSound(0), mScript(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
}
|
||||
|
||||
ESM4::Container::~Container()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Container::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("CONT FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
reader.get(mDataFlags);
|
||||
reader.get(mWeight);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_CNTO:
|
||||
{
|
||||
static InventoryItem inv; // FIXME: use unique_ptr here?
|
||||
reader.get(inv);
|
||||
reader.adjustFormId(inv.item);
|
||||
mInventory.push_back(inv);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_SNAM: reader.getFormId(mOpenSound); break;
|
||||
case ESM4::SUB_QNAM: reader.getFormId(mCloseSound); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_MODS: // TES5 only
|
||||
case ESM4::SUB_VMAD: // TES5 only
|
||||
case ESM4::SUB_OBND: // TES5 only
|
||||
case ESM4::SUB_COCT: // TES5 only
|
||||
case ESM4::SUB_COED: // TES5 only
|
||||
case ESM4::SUB_DEST: // FONV
|
||||
case ESM4::SUB_DSTD: // FONV
|
||||
case ESM4::SUB_DSTF: // FONV
|
||||
case ESM4::SUB_DMDL: // FONV
|
||||
case ESM4::SUB_DMDT: // FONV
|
||||
case ESM4::SUB_RNAM: // FONV
|
||||
{
|
||||
//std::cout << "CONT " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::CONT::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Container::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Container::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_CONT_H
|
||||
#define ESM4_CONT_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common.hpp" // InventoryItem
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct Container
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
|
||||
float mBoundRadius;
|
||||
unsigned char mDataFlags;
|
||||
float mWeight;
|
||||
|
||||
FormId mOpenSound;
|
||||
FormId mCloseSound;
|
||||
FormId mScript; // TES4 only
|
||||
|
||||
std::vector<InventoryItem> mInventory;
|
||||
|
||||
Container();
|
||||
virtual ~Container();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_CONT_H
|
@ -0,0 +1,223 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "crea.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream> // FIXME
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
#ifdef NDEBUG // FIXME: debuggigng only
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
ESM4::Creature::Creature() : mFormId(0), mFlags(0), mDeathItem(0), mScript(0), mCombatStyle(0),
|
||||
mSoundBase(0), mSound(0), mSoundChance(0), mBaseScale(0.f),
|
||||
mTurningSpeed(0.f), mFootWeight(0.f), mBoundRadius(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
|
||||
mBloodSpray.clear();
|
||||
mBloodDecal.clear();
|
||||
|
||||
mAIData.aggression = 0;
|
||||
mAIData.confidence = 0;
|
||||
mAIData.energyLevel = 0;
|
||||
mAIData.responsibility = 0;
|
||||
mAIData.aiFlags = 0;
|
||||
mAIData.trainSkill = 0;
|
||||
mAIData.trainLevel = 0;
|
||||
|
||||
std::memset(&mData, 0, sizeof(Data));
|
||||
}
|
||||
|
||||
ESM4::Creature::~Creature()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Creature::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL: reader.getZString(mFullName); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_CNTO:
|
||||
{
|
||||
static InventoryItem inv; // FIXME: use unique_ptr here?
|
||||
reader.get(inv);
|
||||
reader.adjustFormId(inv.item);
|
||||
mInventory.push_back(inv);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_SPLO:
|
||||
{
|
||||
FormId id;
|
||||
reader.getFormId(id);
|
||||
mSpell.push_back(id);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_PKID:
|
||||
{
|
||||
FormId id;
|
||||
reader.getFormId(id);
|
||||
mAIPackages.push_back(id);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_SNAM:
|
||||
{
|
||||
reader.get(mFaction);
|
||||
reader.adjustFormId(mFaction.faction);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_INAM: reader.getFormId(mDeathItem); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_AIDT:
|
||||
{
|
||||
if (subHdr.dataSize == 20) // FO3
|
||||
reader.skipSubRecordData();
|
||||
else
|
||||
reader.get(mAIData); // 12 bytes
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ACBS:
|
||||
{
|
||||
if (subHdr.dataSize == 24) // FO3
|
||||
reader.skipSubRecordData();
|
||||
else
|
||||
reader.get(mBaseConfig);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
if (subHdr.dataSize == 17) // FO3
|
||||
reader.skipSubRecordData();
|
||||
else
|
||||
reader.get(mData);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ZNAM: reader.getFormId(mCombatStyle); break;
|
||||
case ESM4::SUB_CSCR: reader.getFormId(mSoundBase); break;
|
||||
case ESM4::SUB_CSDI: reader.getFormId(mSound); break;
|
||||
case ESM4::SUB_CSDC: reader.get(mSoundChance); break;
|
||||
case ESM4::SUB_BNAM: reader.get(mBaseScale); break;
|
||||
case ESM4::SUB_TNAM: reader.get(mTurningSpeed); break;
|
||||
case ESM4::SUB_WNAM: reader.get(mFootWeight); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_NAM0: reader.getZString(mBloodSpray); break;
|
||||
case ESM4::SUB_NAM1: reader.getZString(mBloodDecal); break;
|
||||
case ESM4::SUB_NIFZ:
|
||||
{
|
||||
std::string str;
|
||||
if (!reader.getZString(str))
|
||||
throw std::runtime_error ("CREA NIFZ data read error");
|
||||
|
||||
std::stringstream ss(str);
|
||||
std::string file;
|
||||
while (std::getline(ss, file, '\0')) // split the strings
|
||||
mNif.push_back(file);
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_NIFT:
|
||||
{
|
||||
if (subHdr.dataSize != 4) // FIXME: FO3
|
||||
{
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
|
||||
assert(subHdr.dataSize == 4 && "CREA NIFT datasize error");
|
||||
std::uint32_t nift;
|
||||
reader.get(nift);
|
||||
if (nift)
|
||||
std::cout << "CREA NIFT " << mFormId << ", non-zero " << nift << std::endl;
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_KFFZ:
|
||||
{
|
||||
std::string str;
|
||||
if (!reader.getZString(str))
|
||||
throw std::runtime_error ("CREA KFFZ data read error");
|
||||
|
||||
std::stringstream ss(str);
|
||||
std::string file;
|
||||
while (std::getline(ss, file, '\0')) // split the strings
|
||||
mKf.push_back(file);
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_RNAM:
|
||||
case ESM4::SUB_CSDT:
|
||||
case ESM4::SUB_OBND: // FO3
|
||||
case ESM4::SUB_EAMT: // FO3
|
||||
case ESM4::SUB_VTCK: // FO3
|
||||
case ESM4::SUB_TPLT: // FO3
|
||||
case ESM4::SUB_PNAM: // FO3
|
||||
case ESM4::SUB_NAM4: // FO3
|
||||
case ESM4::SUB_NAM5: // FO3
|
||||
case ESM4::SUB_CNAM: // FO3
|
||||
case ESM4::SUB_LNAM: // FO3
|
||||
case ESM4::SUB_EITM: // FO3
|
||||
case ESM4::SUB_DEST: // FO3
|
||||
case ESM4::SUB_DSTD: // FO3
|
||||
case ESM4::SUB_DSTF: // FO3
|
||||
case ESM4::SUB_DMDL: // FO3
|
||||
case ESM4::SUB_DMDT: // FO3
|
||||
case ESM4::SUB_COED: // FO3
|
||||
{
|
||||
//std::cout << "CREA " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::CREA::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Creature::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Creature::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_CREA_H
|
||||
#define ESM4_CREA_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct Creature
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
std::uint8_t unknown;
|
||||
std::uint8_t combat;
|
||||
std::uint8_t magic;
|
||||
std::uint8_t stealth;
|
||||
std::uint16_t soul;
|
||||
std::uint16_t health;
|
||||
std::uint16_t unknown2;
|
||||
std::uint16_t damage;
|
||||
AttributeValues attribs;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
|
||||
FormId mDeathItem;
|
||||
std::vector<FormId> mSpell;
|
||||
FormId mScript;
|
||||
|
||||
AIData mAIData;
|
||||
std::vector<FormId> mAIPackages;
|
||||
ActorBaseConfig mBaseConfig;
|
||||
ActorFaction mFaction;
|
||||
Data mData;
|
||||
FormId mCombatStyle;
|
||||
FormId mSoundBase;
|
||||
FormId mSound;
|
||||
std::uint8_t mSoundChance;
|
||||
float mBaseScale;
|
||||
float mTurningSpeed;
|
||||
float mFootWeight;
|
||||
std::string mBloodSpray;
|
||||
std::string mBloodDecal;
|
||||
|
||||
float mBoundRadius;
|
||||
std::vector<std::string> mNif; // NIF filenames, get directory from mModel
|
||||
std::vector<std::string> mKf;
|
||||
|
||||
std::vector<InventoryItem> mInventory;
|
||||
|
||||
Creature();
|
||||
virtual ~Creature();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_CREA_H
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "door.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Door::Door() : mFormId(0), mFlags(0), mDoorFlags(0), mBoundRadius(0.f), mScript(0),
|
||||
mOpenSound(0), mCloseSound(0), mLoopSound(0), mRandomTeleport(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
}
|
||||
|
||||
ESM4::Door::~Door()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Door::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("DOOR FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_SNAM: reader.getFormId(mOpenSound); break;
|
||||
case ESM4::SUB_ANAM: reader.getFormId(mCloseSound); break;
|
||||
case ESM4::SUB_BNAM: reader.getFormId(mLoopSound); break;
|
||||
case ESM4::SUB_FNAM: reader.get(mDoorFlags); break;
|
||||
case ESM4::SUB_TNAM: reader.getFormId(mRandomTeleport); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_MODS:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_VMAD:
|
||||
case ESM4::SUB_DEST: // FO3
|
||||
case ESM4::SUB_DSTD: // FO3
|
||||
case ESM4::SUB_DSTF: // FO3
|
||||
case ESM4::SUB_DMDL: // FO3
|
||||
case ESM4::SUB_DMDT: // FO3
|
||||
{
|
||||
//std::cout << "DOOR " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::DOOR::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Door::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Door::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_DOOR_H
|
||||
#define ESM4_DOOR_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Door
|
||||
{
|
||||
enum Flags
|
||||
{
|
||||
Flag_OblivionGate = 0x01,
|
||||
Flag_AutomaticDoor = 0x02,
|
||||
Flag_Hidden = 0x04,
|
||||
Flag_MinimalUse = 0x08
|
||||
};
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
std::uint8_t mDoorFlags;
|
||||
FormId mScript;
|
||||
FormId mOpenSound;
|
||||
FormId mCloseSound;
|
||||
FormId mLoopSound;
|
||||
FormId mRandomTeleport;
|
||||
|
||||
Door();
|
||||
virtual ~Door();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_DOOR_H
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "eyes.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Eyes::Eyes() : mFormId(0), mFlags(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mIcon.clear();
|
||||
|
||||
mData.flags = 0;
|
||||
}
|
||||
|
||||
ESM4::Eyes::~Eyes()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Eyes::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("EYES FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_DATA: reader.get(mData); break;
|
||||
default:
|
||||
throw std::runtime_error("ESM4::EYES::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Eyes::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Eyes::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_EYES_H
|
||||
#define ESM4_EYES_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Eyes
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
std::uint8_t flags; // 0x01 = playable?
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mIcon; // inventory
|
||||
|
||||
Data mData;
|
||||
|
||||
Eyes();
|
||||
virtual ~Eyes();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_EYES_H
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "flor.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Flora::Flora() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0), mIngredient(0),
|
||||
mSound(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
}
|
||||
|
||||
ESM4::Flora::~Flora()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Flora::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("FLOR FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_PFIG: reader.getFormId(mIngredient); break;
|
||||
case ESM4::SUB_PFPC: reader.get(mPercentHarvest); break;
|
||||
case ESM4::SUB_SNAM: reader.getFormId(mSound); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_MODS:
|
||||
case ESM4::SUB_FNAM:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_PNAM:
|
||||
case ESM4::SUB_RNAM:
|
||||
case ESM4::SUB_VMAD:
|
||||
{
|
||||
//std::cout << "FLOR " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::FLOR::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Flora::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Flora::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_FLOR_H
|
||||
#define ESM4_FLOR_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Flora
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct Production
|
||||
{
|
||||
std::uint8_t spring;
|
||||
std::uint8_t summer;
|
||||
std::uint8_t autumn;
|
||||
std::uint8_t winter;
|
||||
|
||||
Production::Production() : spring(0), summer(0), autumn(0), winter(0) {}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
FormId mScript;
|
||||
FormId mIngredient;
|
||||
FormId mSound;
|
||||
Production mPercentHarvest;
|
||||
|
||||
Flora();
|
||||
virtual ~Flora();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_FLOR_H
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (C) 2016 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
*/
|
||||
#include "formid.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <cstdlib> // strtol
|
||||
|
||||
#include <libs/platform/strings.h>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
void formIdToString(FormId formId, std::string& str)
|
||||
{
|
||||
char buf[8+1];
|
||||
int res = snprintf(buf, 8+1, "%08X", formId);
|
||||
if (res > 0 && res < 8+1)
|
||||
str.assign(buf);
|
||||
else
|
||||
throw std::runtime_error("Possible buffer overflow while converting formId");
|
||||
}
|
||||
|
||||
std::string formIdToString(FormId formId)
|
||||
{
|
||||
std::string str;
|
||||
formIdToString(formId, str);
|
||||
return str;
|
||||
}
|
||||
|
||||
bool isFormId(const std::string& str, FormId *id)
|
||||
{
|
||||
if (str.size() != 8)
|
||||
return false;
|
||||
|
||||
char *tmp;
|
||||
errno = 0;
|
||||
unsigned long val = strtol(str.c_str(), &tmp, 16);
|
||||
|
||||
if (tmp == str.c_str() || *tmp != '\0' || ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE))
|
||||
return false;
|
||||
|
||||
if (id != nullptr)
|
||||
*id = static_cast<FormId>(val);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FormId stringToFormId(const std::string& str)
|
||||
{
|
||||
if (str.size() != 8)
|
||||
throw std::out_of_range("StringToFormId: incorrect string size");
|
||||
|
||||
return static_cast<FormId>(std::stoul(str, nullptr, 16));
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (C) 2016 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
*/
|
||||
#ifndef ESM4_FORMID_H
|
||||
#define ESM4_FORMID_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
void formIdToString(FormId formId, std::string& str);
|
||||
|
||||
std::string formIdToString(FormId formId);
|
||||
|
||||
bool isFormId(const std::string& str, FormId *id = nullptr);
|
||||
|
||||
FormId stringToFormId(const std::string& str);
|
||||
}
|
||||
|
||||
#endif // ESM4_FORMID_H
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "furn.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Furniture::Furniture() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0),
|
||||
mActiveMarkerFlags(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
}
|
||||
|
||||
ESM4::Furniture::~Furniture()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Furniture::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("FURN FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_MNAM: reader.get(mActiveMarkerFlags); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_DEST:
|
||||
case ESM4::SUB_DSTD:
|
||||
case ESM4::SUB_DSTF:
|
||||
case ESM4::SUB_ENAM:
|
||||
case ESM4::SUB_FNAM:
|
||||
case ESM4::SUB_FNMK:
|
||||
case ESM4::SUB_FNPR:
|
||||
case ESM4::SUB_KNAM:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_MODS:
|
||||
case ESM4::SUB_NAM0:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_PNAM:
|
||||
case ESM4::SUB_VMAD:
|
||||
case ESM4::SUB_WBDT:
|
||||
case ESM4::SUB_XMRK:
|
||||
{
|
||||
//std::cout << "FURN " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::FURN::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Furniture::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Furniture::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_FURN_H
|
||||
#define ESM4_FURN_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Furniture
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
FormId mScript;
|
||||
std::uint32_t mActiveMarkerFlags;
|
||||
|
||||
Furniture();
|
||||
virtual ~Furniture();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_FURN_H
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "gras.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Grass::Grass() : mFormId(0), mFlags(0), mBoundRadius(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mModel.clear();
|
||||
}
|
||||
|
||||
ESM4::Grass::~Grass()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Grass::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_DATA: reader.get(mData); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_OBND:
|
||||
{
|
||||
//std::cout << "GRAS " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::GRAS::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Grass::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Grass::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_GRAS_H
|
||||
#define ESM4_GRAS_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Grass
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
// unused fields are probably packing
|
||||
struct Data
|
||||
{
|
||||
std::uint8_t density;
|
||||
std::uint8_t minSlope;
|
||||
std::uint8_t maxSlope;
|
||||
std::uint8_t unused;
|
||||
std::uint16_t distanceFromWater;
|
||||
std::uint16_t unused2;
|
||||
/*
|
||||
1 Above - At Least
|
||||
2 Above - At Most
|
||||
3 Below - At Least
|
||||
4 Below - At Most
|
||||
5 Either - At Least
|
||||
6 Either - At Most
|
||||
7 Either - At Most Above
|
||||
8 Either - At Most Below
|
||||
*/
|
||||
std::uint32_t waterDistApplication;
|
||||
float positionRange;
|
||||
float heightRange;
|
||||
float colorRange;
|
||||
float wavePeriod;
|
||||
/*
|
||||
0x01 Vertex Lighting
|
||||
0x02 Uniform Scaling
|
||||
0x04 Fit to Slope
|
||||
*/
|
||||
std::uint8_t flags;
|
||||
std::uint8_t unused3;
|
||||
std::uint16_t unused4;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mModel;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
Data mData;
|
||||
|
||||
Grass();
|
||||
virtual ~Grass();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_GRAS_H
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_GRUP_H
|
||||
#define ESM4_GRUP_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common.hpp" // GroupLabel
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
// http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format#Hierarchical_Top_Groups
|
||||
//
|
||||
// Type | Info |
|
||||
// ------+--------------------------------------+-------------------
|
||||
// 2 | Interior Cell Block |
|
||||
// 3 | Interior Cell Sub-Block |
|
||||
// R | CELL |
|
||||
// 6 | Cell Childen |
|
||||
// 8 | Persistent children |
|
||||
// R | REFR, ACHR, ACRE |
|
||||
// 10 | Visible distant children |
|
||||
// R | REFR, ACHR, ACRE |
|
||||
// 9 | Temp Children |
|
||||
// R | PGRD |
|
||||
// R | REFR, ACHR, ACRE |
|
||||
// | |
|
||||
// 0 | Top (Type) |
|
||||
// R | WRLD |
|
||||
// 1 | World Children |
|
||||
// R | ROAD |
|
||||
// R | CELL |
|
||||
// 6 | Cell Childen |
|
||||
// 8 | Persistent children |
|
||||
// R | REFR, ACHR, ACRE |
|
||||
// 10 | Visible distant children |
|
||||
// R | REFR, ACHR, ACRE |
|
||||
// 9 | Temp Children |
|
||||
// R | PGRD |
|
||||
// R | REFR, ACHR, ACRE |
|
||||
// 4 | Exterior World Block |
|
||||
// 5 | Exterior World Sub-block |
|
||||
// R | CELL |
|
||||
// 6 | Cell Childen |
|
||||
// 8 | Persistent children |
|
||||
// R | REFR, ACHR, ACRE |
|
||||
// 10 | Visible distant children |
|
||||
// R | REFR, ACHR, ACRE |
|
||||
// 9 | Temp Children |
|
||||
// R | LAND |
|
||||
// R | PGRD |
|
||||
// R | REFR, ACHR, ACRE |
|
||||
//
|
||||
struct WorldGroup
|
||||
{
|
||||
FormId mWorld; // WRLD record for this group
|
||||
|
||||
// occurs only after World Child (type 1)
|
||||
// since GRUP label may not be reliable, need to keep the formid of the current WRLD in
|
||||
// the reader's context
|
||||
FormId mRoad;
|
||||
|
||||
std::vector<FormId> mCells; // FIXME should this be CellGroup* instead?
|
||||
|
||||
WorldGroup() : mWorld(0), mRoad(0) {}
|
||||
};
|
||||
|
||||
// http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format/CELL
|
||||
//
|
||||
// The block and subblock groups for an interior cell are determined by the last two decimal
|
||||
// digits of the lower 3 bytes of the cell form ID (the modindex is not included in the
|
||||
// calculation). For example, for form ID 0x000CF2=3314, the block is 4 and the subblock is 1.
|
||||
//
|
||||
// The block and subblock groups for an exterior cell are determined by the X-Y coordinates of
|
||||
// the cell. Each block contains 16 subblocks (4x4) and each subblock contains 64 cells (8x8).
|
||||
// So each block contains 1024 cells (32x32).
|
||||
//
|
||||
// NOTE: There may be many CELL records in one subblock
|
||||
struct CellGroup
|
||||
{
|
||||
FormId mCell; // CELL record for this cell group
|
||||
int mCellModIndex; // from which file to get the CELL record (e.g. may have been updated)
|
||||
|
||||
// For retrieving parent group size (for lazy loading or skipping) and sub-block number / grid
|
||||
// NOTE: There can be more than one file that adds/modifies records to this cell group
|
||||
//
|
||||
// Use Case 1: To quickly get only the visble when distant records:
|
||||
//
|
||||
// - Find the FormId of the CELL (maybe WRLD/X/Y grid lookup or from XTEL of a REFR)
|
||||
// - search a map of CELL FormId to CellGroup
|
||||
// - load CELL and its child groups (or load the visible distant only, or whatever)
|
||||
//
|
||||
// Use Case 2: Scan the files but don't load CELL or cell group
|
||||
//
|
||||
// - Load referenceables and other records up front, updating them as required
|
||||
// - Don't load CELL, LAND, PGRD or ROAD (keep FormId's and file index, and file
|
||||
// context then skip the rest of the group)
|
||||
//
|
||||
std::vector<GroupTypeHeader> mHeaders; // FIXME: is this needed?
|
||||
|
||||
// FIXME: should these be pairs? i.e. <FormId, modindex> so that we know from which file
|
||||
// the formid came (it may have been updated by a mod)
|
||||
// but does it matter? the record itself keeps track of whether it is base,
|
||||
// added or modified anyway
|
||||
// FIXME: should these be maps? e.g. std::map<FormId, std::uint8_t>
|
||||
// or vector for storage with a corresponding map of index?
|
||||
|
||||
// cache (modindex adjusted) formId's of children
|
||||
// FIXME: also need file index + file context of all those that has type 8 GRUP
|
||||
GroupTypeHeader mHdrPersist;
|
||||
std::vector<FormId> mPersistent; // REFR, ACHR, ACRE
|
||||
std::vector<FormId> mdelPersistent;
|
||||
|
||||
// FIXME: also need file index + file context of all those that has type 10 GRUP
|
||||
GroupTypeHeader mHdrVisDist;
|
||||
std::vector<FormId> mVisibleDist; // REFR, ACHR, ACRE
|
||||
std::vector<FormId> mdelVisibleDist;
|
||||
|
||||
// FIXME: also need file index + file context of all those that has type 9 GRUP
|
||||
GroupTypeHeader mHdrTemp;
|
||||
FormId mLand; // if present, assume only one LAND per exterior CELL
|
||||
FormId mPgrd; // if present, seems to be the first record after LAND in Temp Cell Child GRUP
|
||||
std::vector<FormId> mTemporary; // REFR, ACHR, ACRE
|
||||
std::vector<FormId> mdelTemporary;
|
||||
|
||||
// need to keep modindex and context for lazy loading (of all the files that contribute
|
||||
// to this group)
|
||||
|
||||
CellGroup() : mCell(0), mLand(0), mPgrd(0) {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_GRUP_H
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "hair.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Hair::Hair() : mFormId(0), mFlags(0), mBoundRadius(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIcon.clear();
|
||||
|
||||
mData.flags = 0;
|
||||
}
|
||||
|
||||
ESM4::Hair::~Hair()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Hair::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL: reader.getZString(mFullName); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_DATA: reader.get(mData); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
{
|
||||
//std::cout << "HAIR " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::HAIR::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Hair::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Hair::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_HAIR
|
||||
#define ESM4_HAIR
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Hair
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
std::uint8_t flags; // 0x01 = not playable, 0x02 = not male, 0x04 = not female, ?? = fixed
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIcon; // inventory
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
Data mData;
|
||||
|
||||
Hair();
|
||||
virtual ~Hair();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_HAIR
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "idle.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::IdleAnimation::IdleAnimation() : mFormId(0), mFlags(0), mParent(0), mPrevious(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mCollision.clear();
|
||||
mEvent.clear();
|
||||
}
|
||||
|
||||
ESM4::IdleAnimation::~IdleAnimation()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::IdleAnimation::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_DNAM: reader.getZString(mCollision); break;
|
||||
case ESM4::SUB_ENAM: reader.getZString(mEvent); break;
|
||||
case ESM4::SUB_ANAM:
|
||||
{
|
||||
reader.get(mParent);
|
||||
reader.get(mPrevious);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_CTDA: // formId
|
||||
case ESM4::SUB_DATA: // formId
|
||||
{
|
||||
//std::cout << "IDLE " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::IDLE::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::IdleAnimation::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::IdleAnimation::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_IDLE_H
|
||||
#define ESM4_IDLE_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct IdleAnimation
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mCollision;
|
||||
std::string mEvent;
|
||||
|
||||
FormId mParent; // IDLE or AACT
|
||||
FormId mPrevious;
|
||||
|
||||
IdleAnimation();
|
||||
virtual ~IdleAnimation();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_IDLE_H
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "ingr.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Ingredient::Ingredient() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIcon.clear();
|
||||
|
||||
mData.value = 0;
|
||||
mData.weight = 0.f;
|
||||
mEnchantment.value = 0;
|
||||
mEnchantment.flags = 0;
|
||||
|
||||
std::memset(&mEffect, 0, sizeof(ScriptEffect));
|
||||
}
|
||||
|
||||
ESM4::Ingredient::~Ingredient()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Ingredient::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (mFullName.empty())
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("INGR FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
else // in TES4 subsequent FULL records are script effect names
|
||||
{
|
||||
// FIXME: should be part of a struct?
|
||||
std::string scriptEffectName;
|
||||
if (!reader.getZString(scriptEffectName))
|
||||
throw std::runtime_error ("INGR FULL data read error");
|
||||
|
||||
mScriptEffect.push_back(scriptEffectName);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
//if (reader.esmVersion() == ESM4::VER_094 || reader.esmVersion() == ESM4::VER_170)
|
||||
if (subHdr.dataSize == 8) // FO3 is size 4 even though VER_094
|
||||
reader.get(mData);
|
||||
else
|
||||
reader.get(mData.weight);
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_ENIT: reader.get(mEnchantment); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_SCIT:
|
||||
{
|
||||
reader.get(mEffect);
|
||||
reader.adjustFormId(mEffect.formId);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_MODS: // Dragonborn only?
|
||||
case ESM4::SUB_EFID:
|
||||
case ESM4::SUB_EFIT:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_VMAD:
|
||||
case ESM4::SUB_YNAM:
|
||||
case ESM4::SUB_ZNAM:
|
||||
case ESM4::SUB_ETYP: // FO3
|
||||
{
|
||||
//std::cout << "INGR " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::INGR::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Ingredient::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Ingredient::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_INGR_H
|
||||
#define ESM4_INGR_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct Ingredient
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
std::uint32_t value;
|
||||
float weight;
|
||||
};
|
||||
|
||||
struct ENIT
|
||||
{
|
||||
std::uint32_t value;
|
||||
std::uint32_t flags;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIcon; // inventory
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
std::vector<std::string> mScriptEffect; // FIXME: prob. should be in a struct
|
||||
FormId mScript;
|
||||
ScriptEffect mEffect;
|
||||
ENIT mEnchantment;
|
||||
|
||||
Data mData;
|
||||
|
||||
Ingredient();
|
||||
virtual ~Ingredient();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_INGR_H
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "keym.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Key::Key() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIcon.clear();
|
||||
|
||||
mData.value = 0;
|
||||
mData.weight = 0.f;
|
||||
}
|
||||
|
||||
ESM4::Key::~Key()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Key::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("KEYM FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_DATA: reader.get(mData); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_VMAD:
|
||||
case ESM4::SUB_YNAM:
|
||||
case ESM4::SUB_ZNAM:
|
||||
case ESM4::SUB_MICO: // FO3
|
||||
{
|
||||
//std::cout << "KEYM " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::KEYM::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Key::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Key::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_KEYM_H
|
||||
#define ESM4_KEYM_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Key
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
std::uint32_t value; // gold
|
||||
float weight;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIcon; // inventory
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
FormId mScript;
|
||||
|
||||
Data mData;
|
||||
|
||||
Key();
|
||||
virtual ~Key();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_KEYM_H
|
@ -0,0 +1,222 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "land.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <iostream> // FIXME: debug only
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
#ifdef NDEBUG // FIXME: debuggigng only
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
ESM4::Land::Land() : mFormId(0), mFlags(0), mLandFlags(0), mDataTypes(0)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
mTextures[i].base.formId = 0;
|
||||
}
|
||||
|
||||
ESM4::Land::~Land()
|
||||
{
|
||||
}
|
||||
|
||||
// overlap north
|
||||
//
|
||||
// 32
|
||||
// 31
|
||||
// 30
|
||||
// overlap .
|
||||
// west .
|
||||
// .
|
||||
// 2
|
||||
// 1
|
||||
// 0
|
||||
// 0 1 2 ... 30 31 32
|
||||
//
|
||||
// overlap south
|
||||
//
|
||||
void ESM4::Land::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
TxtLayer layer;
|
||||
std::int8_t currentAddQuad = -1; // for VTXT following ATXT
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
reader.get(mLandFlags);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_VNML: // vertex normals, 33x33x(1+1+1) = 3267
|
||||
{
|
||||
reader.get(mVertNorm);
|
||||
mDataTypes |= LAND_VNML;
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_VHGT: // vertex height gradient, 4+33x33+3 = 4+1089+3 = 1096
|
||||
{
|
||||
#if 0
|
||||
reader.get(mHeightMap.heightOffset);
|
||||
reader.get(mHeightMap.gradientData);
|
||||
reader.get(mHeightMap.unknown1);
|
||||
reader.get(mHeightMap.unknown2);
|
||||
#endif
|
||||
reader.get(mHeightMap);
|
||||
mDataTypes |= LAND_VHGT;
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_VCLR: // vertex colours, 24bit RGB, 33x33x(1+1+1) = 3267
|
||||
{
|
||||
reader.get(mVertColr);
|
||||
mDataTypes |= LAND_VCLR;
|
||||
break;
|
||||
}
|
||||
case ESM4::SUA_BTXT:
|
||||
{
|
||||
BTXT base;
|
||||
if (reader.get(base))
|
||||
{
|
||||
assert(base.quadrant < 4 && base.quadrant >= 0 && "base texture quadrant index error");
|
||||
|
||||
reader.adjustFormId(base.formId);
|
||||
mTextures[base.quadrant].base = base; // FIXME: any way to avoid double-copying?
|
||||
#if 0
|
||||
std::cout << "Base Texture formid: 0x"
|
||||
<< std::hex << mTextures[base.quadrant].base.formId
|
||||
<< ", quad " << std::dec << (int)base.quadrant << std::endl;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ATXT:
|
||||
{
|
||||
if (currentAddQuad != -1)
|
||||
{
|
||||
// FIXME: sometimes there are no VTXT following an ATXT? Just add a dummy one for now
|
||||
//std::cout << "ESM4::Land VTXT empty layer " << (int)layer.additional.layer << std::endl;
|
||||
mTextures[currentAddQuad].layers.push_back(layer);
|
||||
}
|
||||
reader.get(layer.additional);
|
||||
reader.adjustFormId(layer.additional.formId);
|
||||
assert(layer.additional.quadrant < 4 && layer.additional.quadrant >= 0
|
||||
&& "additional texture quadrant index error");
|
||||
#if 0
|
||||
std::cout << "Additional Texture formId: 0x"
|
||||
<< std::hex << layer.additional.formId
|
||||
<< ", quad " << std::dec << (int)layer.additional.quadrant << std::endl;
|
||||
std::cout << "Additional Texture layer: "
|
||||
<< std::dec << (int)layer.additional.layer << std::endl;
|
||||
#endif
|
||||
currentAddQuad = layer.additional.quadrant;
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_VTXT:
|
||||
{
|
||||
assert(currentAddQuad != -1 && "VTXT without ATXT found");
|
||||
|
||||
int count = (int)reader.subRecordHeader().dataSize / sizeof(ESM4::Land::VTXT);
|
||||
int remainder = reader.subRecordHeader().dataSize % sizeof(ESM4::Land::VTXT);
|
||||
assert(remainder == 0 && "ESM4::LAND VTXT data size error");
|
||||
|
||||
if (count)
|
||||
{
|
||||
layer.data.resize(count);
|
||||
std::vector<ESM4::Land::VTXT>::iterator it = layer.data.begin();
|
||||
for (;it != layer.data.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
// FIXME: debug only
|
||||
//std::cout << "pos: " << std::dec << (int)(*it).position << std::endl;
|
||||
}
|
||||
}
|
||||
mTextures[currentAddQuad].layers.push_back(layer);
|
||||
|
||||
// Assumed that the layers are added in the correct sequence
|
||||
// FIXME: Knights.esp doesn't seem to observe this - investigate more
|
||||
//assert(layer.additional.layer == mTextures[currentAddQuad].layers.size()-1
|
||||
//&& "additional texture layer index error");
|
||||
|
||||
currentAddQuad = -1;
|
||||
// FIXME: debug only
|
||||
//std::cout << "VTXT: count " << std::dec << count << std::endl;
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_VTEX: // only in Oblivion?
|
||||
{
|
||||
int count = (int)reader.subRecordHeader().dataSize / sizeof(FormId);
|
||||
int remainder = reader.subRecordHeader().dataSize % sizeof(FormId);
|
||||
assert(remainder == 0 && "ESM4::LAND VTEX data size error");
|
||||
|
||||
if (count)
|
||||
{
|
||||
mIds.resize(count);
|
||||
for (std::vector<FormId>::iterator it = mIds.begin(); it != mIds.end(); ++it)
|
||||
{
|
||||
reader.getFormId(*it);
|
||||
// FIXME: debug only
|
||||
//std::cout << "VTEX: " << std::hex << *it << std::endl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::LAND::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
|
||||
bool missing = false;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (mTextures[i].base.formId == 0)
|
||||
{
|
||||
//std::cout << "ESM::LAND " << ESM4::formIdToString(mFormId) << " missing base, quad " << i << std::endl;
|
||||
missing = true;
|
||||
}
|
||||
}
|
||||
// at least one of the quadrants do not have a base texture, return without setting the flag
|
||||
if (!missing)
|
||||
mDataTypes |= LAND_VTEX;
|
||||
}
|
||||
|
||||
//void ESM4::Land::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Land::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_LAND_H
|
||||
#define ESM4_LAND_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Land
|
||||
{
|
||||
enum
|
||||
{
|
||||
LAND_VNML = 1,
|
||||
LAND_VHGT = 2,
|
||||
LAND_WNAM = 4, // only in TES3?
|
||||
LAND_VCLR = 8,
|
||||
LAND_VTEX = 16
|
||||
};
|
||||
|
||||
// number of vertices per side
|
||||
static const int VERTS_PER_SIDE = 33;
|
||||
|
||||
// cell terrain size in world coords
|
||||
static const int REAL_SIZE = 4096;
|
||||
|
||||
// total number of vertices
|
||||
static const int LAND_NUM_VERTS = VERTS_PER_SIDE * VERTS_PER_SIDE;
|
||||
|
||||
static const int HEIGHT_SCALE = 8;
|
||||
|
||||
//number of textures per side of a land quadrant
|
||||
static const int QUAD_TEXTURE_PER_SIDE = 16;
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct VHGT
|
||||
{
|
||||
float heightOffset;
|
||||
std::int8_t gradientData[VERTS_PER_SIDE * VERTS_PER_SIDE];
|
||||
std::uint16_t unknown1;
|
||||
unsigned char unknown2;
|
||||
};
|
||||
|
||||
struct BTXT
|
||||
{
|
||||
FormId formId;
|
||||
std::uint8_t quadrant; // 0 = bottom left. 1 = bottom right. 2 = upper-left. 3 = upper-right
|
||||
std::uint8_t unknown1;
|
||||
std::uint16_t unknown2;
|
||||
};
|
||||
|
||||
struct ATXT
|
||||
{
|
||||
FormId formId;
|
||||
std::uint8_t quadrant; // 0 = bottom left. 1 = bottom right. 2 = upper-left. 3 = upper-right
|
||||
std::uint8_t unknown;
|
||||
std::uint16_t layer; // texture layer, 0..7
|
||||
};
|
||||
|
||||
struct VTXT
|
||||
{
|
||||
std::uint16_t position; // 0..288 (17x17 grid)
|
||||
std::uint8_t unknown1;
|
||||
std::uint8_t unknown2;
|
||||
float opacity;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct TxtLayer
|
||||
{
|
||||
ATXT additional;
|
||||
std::vector<VTXT> data; // FIXME: is this UV map?
|
||||
};
|
||||
|
||||
struct Texture
|
||||
{
|
||||
BTXT base;
|
||||
std::vector<TxtLayer> layers;
|
||||
};
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::uint32_t mLandFlags; // from DATA subrecord
|
||||
|
||||
// FIXME: lazy loading not yet implemented
|
||||
int mDataTypes; // which data types are loaded
|
||||
|
||||
signed char mVertNorm[VERTS_PER_SIDE * VERTS_PER_SIDE * 3]; // from VNML subrecord
|
||||
signed char mVertColr[VERTS_PER_SIDE * VERTS_PER_SIDE * 3]; // from VCLR subrecord
|
||||
VHGT mHeightMap;
|
||||
Texture mTextures[4]; // 0 = bottom left. 1 = bottom right. 2 = upper-left. 3 = upper-right
|
||||
std::vector<FormId> mIds; // land texture (LTEX) formids
|
||||
|
||||
Land();
|
||||
virtual ~Land();
|
||||
|
||||
virtual void load(Reader& reader);
|
||||
//virtual void save(Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_LAND_H
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "ligh.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Light::Light() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0), mSound(0),
|
||||
mFade(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIcon.clear();
|
||||
}
|
||||
|
||||
ESM4::Light::~Light()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Light::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
std::uint32_t esmVer = reader.esmVersion();
|
||||
bool isFONV = esmVer == ESM4::VER_132 || esmVer == ESM4::VER_133 || esmVer == ESM4::VER_134;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("LIGH FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
if (isFONV || (esmVer == ESM4::VER_094 && subHdr.dataSize == 32)/*FO3*/)
|
||||
{
|
||||
reader.get(mData.time); // uint32
|
||||
}
|
||||
else
|
||||
reader.get(mData.duration); // float
|
||||
|
||||
reader.get(mData.radius);
|
||||
reader.get(mData.colour);
|
||||
reader.get(mData.flags);
|
||||
//if (reader.esmVersion() == ESM4::VER_094 || reader.esmVersion() == ESM4::VER_170)
|
||||
if (subHdr.dataSize == 48)
|
||||
{
|
||||
reader.get(mData.falloff);
|
||||
reader.get(mData.FOV);
|
||||
reader.get(mData.nearClip);
|
||||
reader.get(mData.frequency);
|
||||
reader.get(mData.intensityAmplitude);
|
||||
reader.get(mData.movementAmplitude);
|
||||
}
|
||||
else if (subHdr.dataSize == 32)
|
||||
{
|
||||
reader.get(mData.falloff);
|
||||
reader.get(mData.FOV);
|
||||
}
|
||||
reader.get(mData.value);
|
||||
reader.get(mData.weight);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_SNAM: reader.getFormId(mSound); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_FNAM: reader.get(mFade); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_VMAD: // Dragonborn only?
|
||||
{
|
||||
//std::cout << "LIGH " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::LIGH::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Light::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Light::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_LIGH_H
|
||||
#define ESM4_LIGH_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Light
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
std::uint32_t time; // FO/FONV only
|
||||
float duration;
|
||||
std::uint32_t radius;
|
||||
std::uint32_t colour; // RGBA
|
||||
std::int32_t flags;
|
||||
float falloff;
|
||||
float FOV;
|
||||
float nearClip; // TES5 only
|
||||
float frequency; // TES5 only
|
||||
float intensityAmplitude; // TES5 only
|
||||
float movementAmplitude; // TES5 only
|
||||
std::uint32_t value; // gold
|
||||
float weight;
|
||||
Data() : duration(-1), radius(0), flags(0), colour(0), falloff(1.f), FOV(90),
|
||||
nearClip(0.f), frequency(0.f), intensityAmplitude(0.f), movementAmplitude(0.f),
|
||||
value(0), weight(0.f) // FIXME: FOV in degrees or radians?
|
||||
{}
|
||||
};
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIcon;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
FormId mScript;
|
||||
FormId mSound;
|
||||
|
||||
float mFade;
|
||||
|
||||
Data mData;
|
||||
|
||||
Light();
|
||||
virtual ~Light();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_LIGH_H
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "ltex.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
#ifdef NDEBUG // FIXME: debuggigng only
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
ESM4::LandTexture::LandTexture() : mFormId(0), mFlags(0), mHavokFriction(0), mHavokRestitution(0),
|
||||
mTextureSpecular(0), mGrass(0), mHavokMaterial(0), mTexture(0),
|
||||
mMaterial(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mTextureFile.clear();
|
||||
}
|
||||
|
||||
ESM4::LandTexture::~LandTexture()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::LandTexture::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
std::uint32_t esmVer = reader.esmVersion();
|
||||
bool isFONV = esmVer == ESM4::VER_132 || esmVer == ESM4::VER_133 || esmVer == ESM4::VER_134;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_HNAM:
|
||||
{
|
||||
if (isFONV)
|
||||
{
|
||||
reader.skipSubRecordData(); // FIXME: skip FONV for now
|
||||
break;
|
||||
}
|
||||
|
||||
if ((reader.esmVersion() == ESM4::VER_094 || reader.esmVersion() == ESM4::VER_170)
|
||||
&& subHdr.dataSize == 2) // FO3 is VER_094 but dataSize 3
|
||||
{
|
||||
//assert(subHdr.dataSize == 2 && "LTEX unexpected HNAM size");
|
||||
reader.get(mHavokFriction);
|
||||
reader.get(mHavokRestitution);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(subHdr.dataSize == 3 && "LTEX unexpected HNAM size");
|
||||
reader.get(mHavokMaterial);
|
||||
reader.get(mHavokFriction);
|
||||
reader.get(mHavokRestitution);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ICON: reader.getZString(mTextureFile); break; // Oblivion only?
|
||||
case ESM4::SUB_SNAM: reader.get(mTextureSpecular); break;
|
||||
case ESM4::SUB_GNAM: reader.getFormId(mGrass); break;
|
||||
case ESM4::SUB_TNAM: reader.getFormId(mTexture); break; // TES5 only
|
||||
case ESM4::SUB_MNAM: reader.getFormId(mMaterial); break; // TES5 only
|
||||
default:
|
||||
throw std::runtime_error("ESM4::LTEX::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::LandTexture::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::LandTexture::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_LTEX_H
|
||||
#define ESM4_LTEX_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct LandTexture
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
|
||||
std::uint8_t mHavokFriction;
|
||||
std::uint8_t mHavokRestitution;
|
||||
|
||||
std::uint8_t mTextureSpecular; // default 30
|
||||
FormId mGrass;
|
||||
|
||||
// ------ TES4 only -----
|
||||
|
||||
std::string mTextureFile;
|
||||
std::uint8_t mHavokMaterial;
|
||||
|
||||
// ------ TES5 only -----
|
||||
|
||||
FormId mTexture;
|
||||
FormId mMaterial;
|
||||
|
||||
// ----------------------
|
||||
|
||||
LandTexture();
|
||||
virtual ~LandTexture();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_LTEX_H
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "lvlc.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::LeveledCreature::LeveledCreature() : mFormId(0), mFlags(0), mScript(0), mTemplate(0),
|
||||
mChanceNone(0), mLvlCreaFlags(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
}
|
||||
|
||||
ESM4::LeveledCreature::~LeveledCreature()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::LeveledCreature::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_TNAM: reader.getFormId(mTemplate); break;
|
||||
case ESM4::SUB_LVLD: reader.get(mChanceNone); break;
|
||||
case ESM4::SUB_LVLF: reader.get(mLvlCreaFlags); break;
|
||||
case ESM4::SUB_LVLO:
|
||||
{
|
||||
static LVLO lvlo;
|
||||
if (subHdr.dataSize != 12)
|
||||
{
|
||||
if (subHdr.dataSize == 8)
|
||||
{
|
||||
reader.get(lvlo.level);
|
||||
reader.get(lvlo.item);
|
||||
reader.get(lvlo.count);
|
||||
//std::cout << "LVLC " << mEditorId << " LVLO lev " << lvlo.level << ", item " << lvlo.item
|
||||
//<< ", count " << lvlo.count << std::endl;
|
||||
// FIXME: seems to happen only once, don't add to mLvlObject
|
||||
// LVLC TesKvatchCreature LVLO lev 1, item 1393819648, count 2
|
||||
// 0x0001, 0x5314 0000, 0x0002
|
||||
break;
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("ESM4::LVLC::load - " + mEditorId + " LVLO size error");
|
||||
}
|
||||
else
|
||||
reader.get(lvlo);
|
||||
|
||||
reader.adjustFormId(lvlo.item);
|
||||
mLvlObject.push_back(lvlo);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_OBND: // FO3
|
||||
{
|
||||
//std::cout << "LVLC " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::LVLC::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::LeveledCreature::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::LeveledCreature::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_LVLC_H
|
||||
#define ESM4_LVLC_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct LeveledCreature
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
|
||||
FormId mScript;
|
||||
FormId mTemplate;
|
||||
std::int8_t mChanceNone;
|
||||
std::uint8_t mLvlCreaFlags;
|
||||
std::vector<LVLO> mLvlObject;
|
||||
|
||||
LeveledCreature();
|
||||
virtual ~LeveledCreature();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_LVLC_H
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "lvli.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::LeveledItem::LeveledItem() : mFormId(0), mFlags(0), mChanceNone(0), mLvlItemFlags(0), mData(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
}
|
||||
|
||||
ESM4::LeveledItem::~LeveledItem()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::LeveledItem::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_LVLD: reader.get(mChanceNone); break;
|
||||
case ESM4::SUB_LVLF: reader.get(mLvlItemFlags); break;
|
||||
case ESM4::SUB_DATA: reader.get(mData); break;
|
||||
case ESM4::SUB_LVLO:
|
||||
{
|
||||
static LVLO lvlo;
|
||||
if (subHdr.dataSize != 12)
|
||||
{
|
||||
if (subHdr.dataSize == 8)
|
||||
{
|
||||
reader.get(lvlo.level);
|
||||
reader.get(lvlo.item);
|
||||
reader.get(lvlo.count);
|
||||
std::cout << "LVLI " << mEditorId << " LVLO lev " << lvlo.level << ", item " << lvlo.item
|
||||
<< ", count " << lvlo.count << std::endl;
|
||||
break;
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("ESM4::LVLI::load - " + mEditorId + " LVLO size error");
|
||||
}
|
||||
else
|
||||
reader.get(lvlo);
|
||||
|
||||
reader.adjustFormId(lvlo.item);
|
||||
mLvlObject.push_back(lvlo);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_OBND: // FO3
|
||||
case ESM4::SUB_COED: // FO3
|
||||
case ESM4::SUB_LVLG: // FO3
|
||||
{
|
||||
|
||||
//std::cout << "LVLI " << ESM4::printName(subHdr.typeId) << " skipping..." << subHdr.dataSize << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::LVLI::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::LeveledItem::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::LeveledItem::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_LVLI_H
|
||||
#define ESM4_LVLI_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct LeveledItem
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
|
||||
std::int8_t mChanceNone;
|
||||
std::uint8_t mLvlItemFlags;
|
||||
std::uint8_t mData;
|
||||
std::vector<LVLO> mLvlObject;
|
||||
|
||||
LeveledItem();
|
||||
virtual ~LeveledItem();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_LVLI_H
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "mato.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Material::Material() : mFormId(0), mFlags(0)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mModel.clear();
|
||||
}
|
||||
|
||||
ESM4::Material::~Material()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Material::load(ESM4::Reader& reader)
|
||||
{
|
||||
//mFormId = reader.adjustFormId(reader.hdr().record.id); // FIXME: use master adjusted?
|
||||
mFormId = reader.hdr().record.id;
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_DNAM:
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
//std::cout << "MATO " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::MATO::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Material::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Material::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_MATO_H
|
||||
#define ESM4_MATO_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Material
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mModel;
|
||||
|
||||
Material();
|
||||
virtual ~Material();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_MATO_H
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "misc.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::MiscItem::MiscItem() : mFormId(0), mFlags(0), mScript(0), mBoundRadius(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIcon.clear();
|
||||
|
||||
mData.value = 0;
|
||||
mData.weight = 0.f;
|
||||
}
|
||||
|
||||
ESM4::MiscItem::~MiscItem()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::MiscItem::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("MISC FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
case ESM4::SUB_DATA: reader.get(mData); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_MODS:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_VMAD:
|
||||
case ESM4::SUB_YNAM:
|
||||
case ESM4::SUB_ZNAM:
|
||||
case ESM4::SUB_MICO: // FO3
|
||||
case ESM4::SUB_RNAM: // FONV
|
||||
{
|
||||
//std::cout << "MISC " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::MISC::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::MiscItem::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::MiscItem::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_MISC_H
|
||||
#define ESM4_MISC_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct MiscItem
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
std::uint32_t value; // gold
|
||||
float weight;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIcon; // inventory
|
||||
|
||||
FormId mScript;
|
||||
float mBoundRadius;
|
||||
|
||||
Data mData;
|
||||
|
||||
MiscItem();
|
||||
virtual ~MiscItem();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_MISC_H
|
@ -0,0 +1,373 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "navi.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <iostream> // FIXME: debugging only
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
#ifdef NDEBUG // FIXME: debuggigng only
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
ESM4::Navigation::Navigation()
|
||||
{
|
||||
mEditorId.clear();
|
||||
}
|
||||
|
||||
ESM4::Navigation::~Navigation()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Navigation::IslandInfo::load(ESM4::Reader& reader)
|
||||
{
|
||||
reader.get(minX);
|
||||
reader.get(minY);
|
||||
reader.get(minZ);
|
||||
reader.get(maxX);
|
||||
reader.get(maxY);
|
||||
reader.get(maxZ);
|
||||
|
||||
std::uint32_t count;
|
||||
reader.get(count); // countTriangle;
|
||||
if (count)
|
||||
{
|
||||
triangles.resize(count);
|
||||
//std::cout << "NVMI island triangles " << std::dec << count << std::endl; // FIXME
|
||||
for (std::vector<Navigation::Triangle>::iterator it = triangles.begin(); it != triangles.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
}
|
||||
}
|
||||
|
||||
reader.get(count); // countVertex;
|
||||
if (count)
|
||||
{
|
||||
verticies.resize(count);
|
||||
for (std::vector<ESM4::Vertex>::iterator it = verticies.begin(); it != verticies.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
// FIXME: debugging only
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
std::cout << padding << "NVMI vert " << std::dec << (*it).x << ", " << (*it).y << ", " << (*it).z << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ESM4::Navigation::NavMeshInfo::load(ESM4::Reader& reader)
|
||||
{
|
||||
std::uint32_t count;
|
||||
|
||||
reader.get(formId);
|
||||
reader.get(flags);
|
||||
reader.get(x);
|
||||
reader.get(y);
|
||||
reader.get(z);
|
||||
|
||||
// FIXME: for debugging only
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
if (flags == ESM4::FLG_Modified)
|
||||
padding.insert(0, 2, '-');
|
||||
else if (flags == ESM4::FLG_Unmodified)
|
||||
padding.insert(0, 4, '.');
|
||||
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
std::cout << padding << "NVMI formId: 0x" << std::hex << formId << std::endl;
|
||||
std::cout << padding << "NVMI flags: " << std::hex << flags << std::endl;
|
||||
std::cout << padding << "NVMI center: " << std::dec << x << ", " << y << ", " << z << std::endl;
|
||||
#endif
|
||||
|
||||
reader.get(flagPrefMerges);
|
||||
|
||||
reader.get(count); // countMerged;
|
||||
if (count)
|
||||
{
|
||||
//std::cout << "NVMI countMerged " << std::dec << count << std::endl;
|
||||
formIdMerged.resize(count);
|
||||
for (std::vector<FormId>::iterator it = formIdMerged.begin(); it != formIdMerged.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
}
|
||||
}
|
||||
|
||||
reader.get(count); // countPrefMerged;
|
||||
if (count)
|
||||
{
|
||||
//std::cout << "NVMI countPrefMerged " << std::dec << count << std::endl;
|
||||
formIdPrefMerged.resize(count);
|
||||
for (std::vector<FormId>::iterator it = formIdPrefMerged.begin(); it != formIdPrefMerged.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
}
|
||||
}
|
||||
|
||||
reader.get(count); // countLinkedDoors;
|
||||
if (count)
|
||||
{
|
||||
//std::cout << "NVMI countLinkedDoors " << std::dec << count << std::endl;
|
||||
linkedDoors.resize(count);
|
||||
for (std::vector<DoorRef>::iterator it = linkedDoors.begin(); it != linkedDoors.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char island;
|
||||
reader.get(island);
|
||||
if (island)
|
||||
{
|
||||
Navigation::IslandInfo island;
|
||||
island.load(reader);
|
||||
islandInfo.push_back(island); // Maybe don't use a vector for just one entry?
|
||||
}
|
||||
else if (flags == FLG_Island) // FIXME: debug only
|
||||
std::cerr << "nvmi no island but has 0x20 flag" << std::endl;
|
||||
|
||||
reader.get(locationMarker);
|
||||
|
||||
reader.get(worldSpaceId);
|
||||
//FLG_Tamriel = 0x0000003c, // grid info follows, possibly Tamriel?
|
||||
//FLG_Morrowind = 0x01380000, // grid info follows, probably Skywind
|
||||
if (worldSpaceId == 0x0000003c || worldSpaceId == 0x01380000)
|
||||
{
|
||||
reader.get(cellGrid.grid.y); // NOTE: reverse order
|
||||
reader.get(cellGrid.grid.x);
|
||||
// FIXME: debugging only
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
if (worldSpaceId == ESM4::FLG_Morrowind)
|
||||
std::cout << padding << "NVMI MW: X " << std::dec << cellGrid.grid.x << ", Y " << cellGrid.grid.y << std::endl;
|
||||
else
|
||||
std::cout << padding << "NVMI SR: X " << std::dec << cellGrid.grid.x << ", Y " << cellGrid.grid.y << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.get(cellGrid.cellId);
|
||||
|
||||
#if 0
|
||||
if (worldSpaceId == 0) // interior
|
||||
std::cout << "NVMI Interior: cellId " << std::hex << cellGrid.cellId << std::endl;
|
||||
else
|
||||
std::cout << "NVMI FormID: cellId " << std::hex << cellGrid.cellId << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// NVPP data seems to be organised this way (total is 0x64 = 100)
|
||||
//
|
||||
// (0) total | 0x1 | formid (index 0) | count | formid's
|
||||
// (1) | count | formid's
|
||||
// (2) | count | formid's
|
||||
// (3) | count | formid's
|
||||
// (4) | count | formid's
|
||||
// (5) | count | formid's
|
||||
// (6) | count | formid's
|
||||
// (7) | count | formid's
|
||||
// (8) | count | formid's
|
||||
// (9) | count | formid's
|
||||
// (10) | 0x1 | formid (index 1) | count | formid's
|
||||
// (11) | count | formid's
|
||||
// (12) | count | formid's
|
||||
// (13) | count | formid's
|
||||
// (14) | count | formid's
|
||||
// (15) | count | formid's
|
||||
// ...
|
||||
//
|
||||
// (88) | count | formid's
|
||||
// (89) | count | formid's
|
||||
//
|
||||
// Here the pattern changes (final count is 0xa = 10)
|
||||
//
|
||||
// (90) | 0x1 | formid (index 9) | count | formid | index
|
||||
// (91) | formid | index
|
||||
// (92) | formid | index
|
||||
// (93) | formid | index
|
||||
// (94) | formid | index
|
||||
// (95) | formid | index
|
||||
// (96) | formid | index
|
||||
// (97) | formid | index
|
||||
// (98) | formid | index
|
||||
// (99) | formid | index
|
||||
//
|
||||
// Note that the index values are not sequential, i.e. the first index value
|
||||
// (i.e. row 90) for Update.esm is 2.
|
||||
//
|
||||
// Also note that there's no list of formid's following the final node (index 9)
|
||||
//
|
||||
// The same 10 formids seem to be used for the indicies, but not necessarily
|
||||
// with the same index value (but only Update.esm differs?)
|
||||
//
|
||||
// formid cellid X Y Editor ID other formids in same X,Y S U D D
|
||||
// -------- ------ --- --- --------------------------- ---------------------------- - - - -
|
||||
// 00079bbf 9639 5 -4 WhiterunExterior17 00079bc3 0 6 0 0
|
||||
// 0010377b 8ed5 6 24 DawnstarWesternMineExterior 1 1 1 1
|
||||
// 000a3f44 9577 -22 2 RoriksteadEdge 2 9 2 2
|
||||
// 00100f4b 8ea2 26 25 WinterholdExterior01 00100f4a, 00100f49 3 3 3 3
|
||||
// 00103120 bc8e 42 -22 (near Riften) 4 2 4 4
|
||||
// 00105e9a 929d -18 24 SolitudeExterior03 5 0 5 5
|
||||
// 001030cb 7178 -40 1 SalviusFarmExterior01 (east of Markarth) 6 8 6 6
|
||||
// 00098776 980b 4 -19 HelgenExterior 000cce3d 7 5 7 7
|
||||
// 000e88cc 93de -9 14 (near Morthal) 0010519e, 0010519d, 000e88d2 8 7 8 8
|
||||
// 000b87df b51d 33 5 WindhelmAttackStart05 9 4 9 9
|
||||
//
|
||||
void ESM4::Navigation::load(ESM4::Reader& reader)
|
||||
{
|
||||
//mFormId = reader.hdr().record.id;
|
||||
//mFlags = reader.hdr().record.flags;
|
||||
std::uint32_t esmVer = reader.esmVersion();
|
||||
bool isFONV = esmVer == ESM4::VER_132 || esmVer == ESM4::VER_133 || esmVer == ESM4::VER_134;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: // seems to be unused?
|
||||
{
|
||||
if (!reader.getZString(mEditorId))
|
||||
throw std::runtime_error ("NAVI EDID data read error");
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_NVPP:
|
||||
{
|
||||
std::uint32_t total;
|
||||
std::uint32_t count;
|
||||
reader.get(total);
|
||||
if (!total)
|
||||
{
|
||||
reader.get(count); // throw away
|
||||
break;
|
||||
}
|
||||
|
||||
total -= 10; // HACK
|
||||
std::uint32_t node;
|
||||
for (std::uint32_t i = 0; i < total; ++i)
|
||||
{
|
||||
std::vector<FormId> preferredPaths;
|
||||
reader.get(count);
|
||||
if (count == 1)
|
||||
{
|
||||
reader.get(node);
|
||||
reader.get(count);
|
||||
}
|
||||
if (count)
|
||||
{
|
||||
preferredPaths.resize(count);
|
||||
for (std::vector<FormId>::iterator it = preferredPaths.begin();
|
||||
it != preferredPaths.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
}
|
||||
}
|
||||
mPreferredPaths.push_back(std::make_pair(node, preferredPaths));
|
||||
#if 0
|
||||
std::cout << "node " << std::hex << node // FIXME: debugging only
|
||||
<< ", count " << count << ", i " << std::dec << i << std::endl;
|
||||
#endif
|
||||
}
|
||||
reader.get(count);
|
||||
assert(count == 1 && "expected separator");
|
||||
|
||||
reader.get(node); // HACK
|
||||
std::vector<FormId> preferredPaths;
|
||||
mPreferredPaths.push_back(std::make_pair(node, preferredPaths)); // empty
|
||||
#if 0
|
||||
std::cout << "node " << std::hex << node // FIXME: debugging only
|
||||
<< ", count " << 0 << std::endl;
|
||||
#endif
|
||||
|
||||
reader.get(count); // HACK
|
||||
assert(count == 10 && "expected 0xa");
|
||||
std::uint32_t index;
|
||||
for (std::uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
reader.get(node);
|
||||
reader.get(index);
|
||||
#if 0
|
||||
std::cout << "node " << std::hex << node // FIXME: debugging only
|
||||
<< ", index " << index << ", i " << std::dec << total+i << std::endl;
|
||||
#endif
|
||||
std::pair<std::map<FormId, std::uint32_t>::iterator, bool> res =
|
||||
mPathIndexMap.insert(std::make_pair(node, index));
|
||||
// FIXME: this throws if more than one file is being loaded
|
||||
//if (!res.second)
|
||||
//throw std::runtime_error ("node already exists in the preferred path index map");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_NVER:
|
||||
{
|
||||
std::uint32_t version; // always the same? (0x0c)
|
||||
reader.get(version); // TODO: store this or use it for merging?
|
||||
//std::cout << "NAVI version " << std::dec << version << std::endl;
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_NVMI: // multiple
|
||||
{
|
||||
if (esmVer == ESM4::VER_094 || esmVer == ESM4::VER_170 || isFONV)
|
||||
{
|
||||
reader.skipSubRecordData(); // FIXME: FO3/FONV have different form of NavMeshInfo
|
||||
break;
|
||||
}
|
||||
|
||||
//std::cout << "\nNVMI start" << std::endl;
|
||||
NavMeshInfo nvmi;
|
||||
nvmi.load(reader);
|
||||
mNavMeshInfo.push_back (nvmi);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_NVSI: // from Dawnguard onwards
|
||||
case ESM4::SUB_NVCI: // FO3
|
||||
{
|
||||
reader.skipSubRecordData(); // FIXME:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw std::runtime_error("ESM4::NAVI::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Navigation::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Navigation::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_NAVI_H
|
||||
#define ESM4_NAVI_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "common.hpp" // CellGrid, Vertex
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct Navigation
|
||||
{
|
||||
#pragma pack(push,1)
|
||||
struct DoorRef
|
||||
{
|
||||
std::uint32_t unknown;
|
||||
FormId formId;
|
||||
};
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
std::uint16_t vertexIndex0;
|
||||
std::uint16_t vertexIndex1;
|
||||
std::uint16_t vertexIndex2;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct IslandInfo
|
||||
{
|
||||
float minX;
|
||||
float minY;
|
||||
float minZ;
|
||||
float maxX;
|
||||
float maxY;
|
||||
float maxZ;
|
||||
std::vector<Triangle> triangles;
|
||||
std::vector<Vertex> verticies;
|
||||
|
||||
void load(ESM4::Reader& reader);
|
||||
};
|
||||
|
||||
enum Flags // NVMI island flags (not certain)
|
||||
{
|
||||
FLG_Island = 0x00000020,
|
||||
FLG_Modified = 0x00000000, // not island
|
||||
FLG_Unmodified = 0x00000040 // not island
|
||||
};
|
||||
|
||||
struct NavMeshInfo
|
||||
{
|
||||
FormId formId;
|
||||
std::uint32_t flags;
|
||||
// center point of the navmesh
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
std::uint32_t flagPrefMerges;
|
||||
std::vector<FormId> formIdMerged;
|
||||
std::vector<FormId> formIdPrefMerged;
|
||||
std::vector<DoorRef> linkedDoors;
|
||||
std::vector<IslandInfo> islandInfo;
|
||||
std::uint32_t locationMarker;
|
||||
FormId worldSpaceId;
|
||||
CellGrid cellGrid;
|
||||
|
||||
void load(ESM4::Reader& reader);
|
||||
};
|
||||
|
||||
std::string mEditorId;
|
||||
|
||||
std::vector<NavMeshInfo> mNavMeshInfo;
|
||||
|
||||
std::vector<std::pair<std::uint32_t, std::vector<FormId> > > mPreferredPaths;
|
||||
|
||||
std::map<FormId, std::uint32_t> mPathIndexMap;
|
||||
|
||||
Navigation();
|
||||
virtual ~Navigation();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_NAVI_H
|
@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "navm.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <iostream> // FIXME: debugging only
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::NavMesh::NavMesh() : mFormId(0), mFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
ESM4::NavMesh::~NavMesh()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::NavMesh::NVNMstruct::load(ESM4::Reader& reader)
|
||||
{
|
||||
//std::cout << "start: divisor " << std::dec << divisor << ", segments " << triSegments.size() << //std::endl;
|
||||
//"this 0x" << this << std::endl; // FIXME
|
||||
|
||||
std::uint32_t count;
|
||||
|
||||
reader.get(unknownNVER);
|
||||
reader.get(unknownLCTN);
|
||||
reader.get(worldSpaceId);
|
||||
//FLG_Tamriel = 0x0000003c, // grid info follows, possibly Tamriel?
|
||||
//FLG_Morrowind = 0x01380000, // grid info follows, probably Skywind
|
||||
if (worldSpaceId == 0x0000003c || worldSpaceId == 0x01380000)
|
||||
{
|
||||
// ^
|
||||
// Y | X Y Index
|
||||
// | 0,0 0
|
||||
// 1 |23 0,1 1
|
||||
// 0 |01 1,0 2
|
||||
// +--- 1,1 3
|
||||
// 01 ->
|
||||
// X
|
||||
//
|
||||
// e.g. Dagonfel X:13,14,15,16 Y:43,44,45,46 (Morrowind X:7 Y:22)
|
||||
//
|
||||
// Skywind: -4,-3 -2,-1 0,1 2,3 4,5 6,7
|
||||
// Morrowind: -2 -1 0 1 2 3
|
||||
//
|
||||
// Formula seems to be floor(Skywind coord / 2) <cmath>
|
||||
//
|
||||
reader.get(cellGrid.grid.y); // NOTE: reverse order
|
||||
reader.get(cellGrid.grid.x);
|
||||
// FIXME: debugging only
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
if (worldSpaceId == ESM4::FLG_Morrowind)
|
||||
std::cout << padding << "NVNM MW: X " << std::dec << cellGrid.grid.x << ", Y " << cellGrid.grid.y << std::endl;
|
||||
else
|
||||
std::cout << padding << "NVNM SR: X " << std::dec << cellGrid.grid.x << ", Y " << cellGrid.grid.y << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.get(cellGrid.cellId);
|
||||
|
||||
#if 0
|
||||
std::string padding = ""; // FIXME
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
if (worldSpaceId == 0) // interior
|
||||
std::cout << padding << "NVNM Interior: cellId " << std::hex << cellGrid.cellId << std::endl;
|
||||
else
|
||||
std::cout << padding << "NVNM FormID: cellId " << std::hex << cellGrid.cellId << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
reader.get(count); // numVerticies
|
||||
if (count)
|
||||
{
|
||||
verticies.resize(count);
|
||||
for (std::vector<Vertex>::iterator it = verticies.begin(); it != verticies.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
// FIXME: debugging only
|
||||
#if 0
|
||||
//if (reader.hdr().record.id == 0x2004ecc) // FIXME
|
||||
std::cout << "nvnm vert " << (*it).x << ", " << (*it).y << ", " << (*it).z << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
reader.get(count); // numTriangles;
|
||||
if (count)
|
||||
{
|
||||
triangles.resize(count);
|
||||
for (std::vector<Triangle>::iterator it = triangles.begin(); it != triangles.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
}
|
||||
}
|
||||
|
||||
reader.get(count); // numExtConn;
|
||||
if (count)
|
||||
{
|
||||
extConns.resize(count);
|
||||
for (std::vector<ExtConnection>::iterator it = extConns.begin(); it != extConns.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
// FIXME: debugging only
|
||||
#if 0
|
||||
std::cout << "nvnm ext 0x" << std::hex << (*it).navMesh << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
reader.get(count); // numDoorTriangles;
|
||||
if (count)
|
||||
{
|
||||
doorTriangles.resize(count);
|
||||
for (std::vector<DoorTriangle>::iterator it = doorTriangles.begin(); it != doorTriangles.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
}
|
||||
}
|
||||
|
||||
reader.get(count); // numCoverTriangles;
|
||||
if (count)
|
||||
{
|
||||
coverTriangles.resize(count);
|
||||
for (std::vector<std::uint16_t>::iterator it = coverTriangles.begin(); it != coverTriangles.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// abs((maxX - minX) / divisor) = Max X Distance
|
||||
reader.get(divisor); // FIXME: latest over-writes old
|
||||
|
||||
reader.get(maxXDist); // FIXME: update with formula
|
||||
reader.get(maxYDist);
|
||||
reader.get(minX); // FIXME: use std::min
|
||||
reader.get(minY);
|
||||
reader.get(minZ);
|
||||
reader.get(maxX);
|
||||
reader.get(maxY);
|
||||
reader.get(maxZ);
|
||||
|
||||
// FIXME: should check remaining size here
|
||||
// there are divisor^2 segments, each segment is a vector of triangle indicies
|
||||
for (unsigned int i = 0; i < divisor*divisor; ++i)
|
||||
{
|
||||
reader.get(count); // NOTE: count may be zero
|
||||
|
||||
std::vector<std::uint16_t> indicies;
|
||||
indicies.resize(count);
|
||||
for (std::vector<std::uint16_t>::iterator it = indicies.begin(); it != indicies.end(); ++it)
|
||||
{
|
||||
reader.get(*it);
|
||||
}
|
||||
triSegments.push_back(indicies);
|
||||
}
|
||||
assert(triSegments.size() == divisor*divisor && "tiangle segments size is not the square of divisor");
|
||||
#if 0
|
||||
if (triSegments.size() != divisor*divisor)
|
||||
std::cout << "divisor " << std::dec << divisor << ", segments " << triSegments.size() << //std::endl;
|
||||
"this 0x" << this << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ESM4::NavMesh::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
//std::cout << "NavMesh 0x" << std::hex << this << std::endl; // FIXME
|
||||
std::uint32_t subSize = 0; // for XXXX sub record
|
||||
|
||||
// FIXME: debugging only
|
||||
#if 0
|
||||
std::string padding = "";
|
||||
padding.insert(0, reader.stackSize()*2, ' ');
|
||||
std::cout << padding << "NAVM flags 0x" << std::hex << reader.hdr().record.flags << std::endl;
|
||||
std::cout << padding << "NAVM id 0x" << std::hex << reader.hdr().record.id << std::endl;
|
||||
#endif
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
switch (reader.subRecordHeader().typeId)
|
||||
{
|
||||
case ESM4::SUB_NVNM:
|
||||
{
|
||||
NVNMstruct nvnm;
|
||||
nvnm.load(reader);
|
||||
mData.push_back(nvnm); // FIXME try swap
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ONAM:
|
||||
case ESM4::SUB_PNAM:
|
||||
case ESM4::SUB_NNAM:
|
||||
{
|
||||
if (subSize)
|
||||
{
|
||||
reader.skipSubRecordData(subSize); // special post XXXX
|
||||
reader.updateRecordRemaining(subSize); // WARNING: manual update
|
||||
subSize = 0;
|
||||
}
|
||||
else
|
||||
//const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
//std::cout << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData(); // FIXME: process the subrecord rather than skip
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_XXXX:
|
||||
{
|
||||
reader.get(subSize);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_NVER: // FO3
|
||||
case ESM4::SUB_DATA: // FO3
|
||||
case ESM4::SUB_NVVX: // FO3
|
||||
case ESM4::SUB_NVTR: // FO3
|
||||
case ESM4::SUB_NVCA: // FO3
|
||||
case ESM4::SUB_NVDP: // FO3
|
||||
case ESM4::SUB_NVGD: // FO3
|
||||
case ESM4::SUB_NVEX: // FO3
|
||||
case ESM4::SUB_EDID: // FO3
|
||||
{
|
||||
reader.skipSubRecordData(); // FIXME:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::NAVM::load - Unknown subrecord " +
|
||||
ESM4::printName(reader.subRecordHeader().typeId));
|
||||
}
|
||||
}
|
||||
//std::cout << "num nvnm " << std::dec << mData.size() << std::endl; // FIXME
|
||||
}
|
||||
|
||||
//void ESM4::NavMesh::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
void ESM4::NavMesh::blank()
|
||||
{
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright (C) 2015, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_NAVM_H
|
||||
#define ESM4_NAVM_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common.hpp" // CellGrid, Vertex
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct NavMesh
|
||||
{
|
||||
#pragma pack(push,1)
|
||||
struct Triangle
|
||||
{
|
||||
std::uint16_t vertexIndex0;
|
||||
std::uint16_t vertexIndex1;
|
||||
std::uint16_t vertexIndex2;
|
||||
std::uint16_t edge0;
|
||||
std::uint16_t edge1;
|
||||
std::uint16_t edge2;
|
||||
std::uint16_t coverMarker;
|
||||
std::uint16_t coverFlags;
|
||||
};
|
||||
|
||||
struct ExtConnection
|
||||
{
|
||||
std::uint32_t unknown;
|
||||
FormId navMesh;
|
||||
std::uint16_t triangleIndex;
|
||||
};
|
||||
|
||||
struct DoorTriangle
|
||||
{
|
||||
std::uint16_t triangleIndex;
|
||||
std::uint32_t unknown;
|
||||
FormId doorRef;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct NVNMstruct
|
||||
{
|
||||
std::uint32_t unknownNVER;
|
||||
std::uint32_t unknownLCTN;
|
||||
FormId worldSpaceId;
|
||||
CellGrid cellGrid;
|
||||
std::vector<Vertex> verticies;
|
||||
std::vector<Triangle> triangles;
|
||||
std::vector<ExtConnection> extConns;
|
||||
std::vector<DoorTriangle> doorTriangles;
|
||||
std::vector<std::uint16_t> coverTriangles;
|
||||
std::uint32_t divisor;
|
||||
float maxXDist;
|
||||
float maxYDist;
|
||||
float minX;
|
||||
float minY;
|
||||
float minZ;
|
||||
float maxX;
|
||||
float maxY;
|
||||
float maxZ;
|
||||
// there are divisor^2 segments, each segment is a vector of triangle indicies
|
||||
std::vector<std::vector<std::uint16_t> > triSegments;
|
||||
|
||||
void load(ESM4::Reader& esm);
|
||||
};
|
||||
|
||||
std::vector<NVNMstruct> mData; // Up to 4 skywind cells in one Morrowind cell
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
NavMesh();
|
||||
virtual ~NavMesh();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
void blank();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ESM4_NAVM_H
|
@ -0,0 +1,237 @@
|
||||
/*
|
||||
Copyright (C) 2016-2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "npc_.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Npc::Npc() : mFormId(0), mFlags(0), mRace(0), mClass(0), mHair(0), mEyes(0), mDeathItem(0),
|
||||
mScript(0), mCombatStyle(0), mSoundBase(0), mSound(0), mSoundChance(0),
|
||||
mFootWeight(0.f), mBoundRadius(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
|
||||
std::memset(&mAIData, 0, sizeof(AIData));
|
||||
std::memset(&mData, 0, sizeof(Data));
|
||||
std::memset(&mBaseConfig, 0, sizeof(ActorBaseConfig));
|
||||
std::memset(&mFaction, 0, sizeof(ActorFaction));
|
||||
}
|
||||
|
||||
ESM4::Npc::~Npc()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Npc::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
std::uint32_t esmVer = reader.esmVersion();
|
||||
bool isFONV = esmVer == ESM4::VER_132 || esmVer == ESM4::VER_133 || esmVer == ESM4::VER_134;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("NPC_ FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_CNTO:
|
||||
{
|
||||
static InventoryItem inv; // FIXME: use unique_ptr here?
|
||||
reader.get(inv);
|
||||
reader.adjustFormId(inv.item);
|
||||
mInventory.push_back(inv);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_SPLO:
|
||||
{
|
||||
FormId id;
|
||||
reader.getFormId(id);
|
||||
mSpell.push_back(id);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_PKID:
|
||||
{
|
||||
FormId id;
|
||||
reader.getFormId(id);
|
||||
mAIPackages.push_back(id);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_SNAM:
|
||||
{
|
||||
reader.get(mFaction);
|
||||
reader.adjustFormId(mFaction.faction);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_RNAM: reader.getFormId(mRace); break;
|
||||
case ESM4::SUB_CNAM: reader.getFormId(mClass); break;
|
||||
case ESM4::SUB_HNAM: reader.getFormId(mHair); break;
|
||||
case ESM4::SUB_ENAM: reader.getFormId(mEyes); break;
|
||||
//
|
||||
case ESM4::SUB_INAM: reader.getFormId(mDeathItem); break;
|
||||
case ESM4::SUB_SCRI: reader.getFormId(mScript); break;
|
||||
//
|
||||
case ESM4::SUB_AIDT:
|
||||
{
|
||||
if (esmVer == ESM4::VER_094 || esmVer == ESM4::VER_170 || isFONV)
|
||||
{
|
||||
reader.skipSubRecordData(); // FIXME: process the subrecord rather than skip
|
||||
break;
|
||||
}
|
||||
|
||||
reader.get(mAIData);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ACBS:
|
||||
{
|
||||
if (esmVer == ESM4::VER_094 || esmVer == ESM4::VER_170 || isFONV)
|
||||
{
|
||||
reader.skipSubRecordData(); // FIXME: process the subrecord rather than skip
|
||||
break;
|
||||
}
|
||||
|
||||
reader.get(mBaseConfig);
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_DATA:
|
||||
{
|
||||
if (esmVer == ESM4::VER_094 || esmVer == ESM4::VER_170 || isFONV)
|
||||
{
|
||||
if (subHdr.dataSize != 0) // FIXME FO3
|
||||
reader.skipSubRecordData();
|
||||
break; // zero length
|
||||
}
|
||||
|
||||
reader.get(&mData, 33); // FIXME: check packing
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ZNAM: reader.getFormId(mCombatStyle); break;
|
||||
case ESM4::SUB_CSCR: reader.getFormId(mSoundBase); break;
|
||||
case ESM4::SUB_CSDI: reader.getFormId(mSound); break;
|
||||
case ESM4::SUB_CSDC: reader.get(mSoundChance); break;
|
||||
case ESM4::SUB_WNAM: reader.get(mFootWeight); break;
|
||||
//
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
case ESM4::SUB_KFFZ:
|
||||
{
|
||||
std::string str;
|
||||
if (!reader.getZString(str))
|
||||
throw std::runtime_error ("NPC_ KFFZ data read error");
|
||||
|
||||
// Seems to be only below 3, and only happens 3 times while loading TES4:
|
||||
// Forward_SheogorathWithCane.kf
|
||||
// TurnLeft_SheogorathWithCane.kf
|
||||
// TurnRight_SheogorathWithCane.kf
|
||||
std::stringstream ss(str);
|
||||
std::string file;
|
||||
while (std::getline(ss, file, '\0')) // split the strings
|
||||
mKf.push_back(file);
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_LNAM:
|
||||
case ESM4::SUB_HCLR:
|
||||
case ESM4::SUB_FGGS:
|
||||
case ESM4::SUB_FGGA:
|
||||
case ESM4::SUB_FGTS:
|
||||
case ESM4::SUB_FNAM:
|
||||
case ESM4::SUB_ATKR:
|
||||
case ESM4::SUB_COCT:
|
||||
case ESM4::SUB_CRIF:
|
||||
case ESM4::SUB_CSDT:
|
||||
case ESM4::SUB_DNAM:
|
||||
case ESM4::SUB_DOFT:
|
||||
case ESM4::SUB_DPLT:
|
||||
case ESM4::SUB_ECOR:
|
||||
case ESM4::SUB_ANAM:
|
||||
case ESM4::SUB_ATKD:
|
||||
case ESM4::SUB_ATKE:
|
||||
case ESM4::SUB_DEST:
|
||||
case ESM4::SUB_DSTD:
|
||||
case ESM4::SUB_DSTF:
|
||||
case ESM4::SUB_FTST:
|
||||
case ESM4::SUB_HCLF:
|
||||
case ESM4::SUB_KSIZ:
|
||||
case ESM4::SUB_KWDA:
|
||||
case ESM4::SUB_NAM5:
|
||||
case ESM4::SUB_NAM6:
|
||||
case ESM4::SUB_NAM7:
|
||||
case ESM4::SUB_NAM8:
|
||||
case ESM4::SUB_NAM9:
|
||||
case ESM4::SUB_NAMA:
|
||||
case ESM4::SUB_OBND:
|
||||
case ESM4::SUB_PNAM:
|
||||
case ESM4::SUB_PRKR:
|
||||
case ESM4::SUB_PRKZ:
|
||||
case ESM4::SUB_QNAM:
|
||||
case ESM4::SUB_SOFT:
|
||||
case ESM4::SUB_SPCT:
|
||||
case ESM4::SUB_TIAS:
|
||||
case ESM4::SUB_TINC:
|
||||
case ESM4::SUB_TINI:
|
||||
case ESM4::SUB_TINV:
|
||||
case ESM4::SUB_TPLT:
|
||||
case ESM4::SUB_VMAD:
|
||||
case ESM4::SUB_VTCK:
|
||||
case ESM4::SUB_GNAM:
|
||||
case ESM4::SUB_SHRT:
|
||||
case ESM4::SUB_SPOR:
|
||||
case ESM4::SUB_EAMT: // FO3
|
||||
case ESM4::SUB_NAM4: // FO3
|
||||
case ESM4::SUB_COED: // FO3
|
||||
{
|
||||
//std::cout << "NPC_ " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::NPC_::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Npc::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Npc::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_NPC__H
|
||||
#define ESM4_NPC__H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
|
||||
struct Npc
|
||||
{
|
||||
struct SkillValues
|
||||
{
|
||||
std::uint8_t armorer;
|
||||
std::uint8_t athletics;
|
||||
std::uint8_t blade;
|
||||
std::uint8_t block;
|
||||
std::uint8_t blunt;
|
||||
std::uint8_t handToHand;
|
||||
std::uint8_t heavyArmor;
|
||||
std::uint8_t alchemy;
|
||||
std::uint8_t alteration;
|
||||
std::uint8_t conjuration;
|
||||
std::uint8_t destruction;
|
||||
std::uint8_t illusion;
|
||||
std::uint8_t mysticism;
|
||||
std::uint8_t restoration;
|
||||
std::uint8_t acrobatics;
|
||||
std::uint8_t lightArmor;
|
||||
std::uint8_t marksman;
|
||||
std::uint8_t mercantile;
|
||||
std::uint8_t security;
|
||||
std::uint8_t sneak;
|
||||
std::uint8_t speechcraft;
|
||||
};
|
||||
|
||||
struct Data
|
||||
{
|
||||
SkillValues skills;
|
||||
std::uint32_t health;
|
||||
AttributeValues attribs;
|
||||
};
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
|
||||
FormId mRace;
|
||||
FormId mClass;
|
||||
FormId mHair;
|
||||
FormId mEyes;
|
||||
|
||||
FormId mDeathItem;
|
||||
std::vector<FormId> mSpell;
|
||||
FormId mScript;
|
||||
|
||||
AIData mAIData;
|
||||
std::vector<FormId> mAIPackages;
|
||||
ActorBaseConfig mBaseConfig;
|
||||
ActorFaction mFaction;
|
||||
Data mData;
|
||||
FormId mCombatStyle;
|
||||
FormId mSoundBase;
|
||||
FormId mSound;
|
||||
std::uint8_t mSoundChance;
|
||||
float mFootWeight;
|
||||
|
||||
float mBoundRadius;
|
||||
std::vector<std::string> mKf; // filenames only, get directory path from mModel
|
||||
|
||||
std::vector<InventoryItem> mInventory;
|
||||
|
||||
Npc();
|
||||
virtual ~Npc();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_NPC__H
|
@ -0,0 +1,229 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#include "race.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iostream> // FIXME: debugging only
|
||||
#include <iomanip>
|
||||
|
||||
#include "reader.hpp"
|
||||
//#include "writer.hpp"
|
||||
|
||||
ESM4::Race::Race() : mFormId(0), mFlags(0), mBoundRadius(0.f)
|
||||
{
|
||||
mEditorId.clear();
|
||||
mFullName.clear();
|
||||
mModel.clear();
|
||||
mIcon.clear();
|
||||
|
||||
mData.flags = 0;
|
||||
}
|
||||
|
||||
ESM4::Race::~Race()
|
||||
{
|
||||
}
|
||||
|
||||
void ESM4::Race::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.id;
|
||||
reader.adjustFormId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
{
|
||||
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||
switch (subHdr.typeId)
|
||||
{
|
||||
case ESM4::SUB_EDID:
|
||||
{
|
||||
reader.getZString(mEditorId);
|
||||
std::cout << "RACE " << mEditorId << std::endl;
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_FULL:
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mFullName);
|
||||
else if (!reader.getZString(mFullName))
|
||||
throw std::runtime_error ("RACE FULL data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_MODL: reader.getZString(mModel); break;
|
||||
case ESM4::SUB_ICON: reader.getZString(mIcon); break; // Only in TES4?
|
||||
//case ESM4::SUB_DATA: reader.get(mData); break;
|
||||
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||
//case ESM4::SUB_MODT:
|
||||
case ESM4::SUB_DESC: //skipping...1 <- different lenghts
|
||||
{
|
||||
if (reader.hasLocalizedStrings())
|
||||
reader.getLocalizedString(mDesc); // TODO check if formid is null
|
||||
else if (!reader.getZString(mDesc))
|
||||
throw std::runtime_error ("RACE DESC data read error");
|
||||
|
||||
break;
|
||||
}
|
||||
case ESM4::SUB_ATTR: //skipping...16 // Only in TES4? guess - 8 attrib each for male/female?
|
||||
// Argonian 28 28 1e 32 32 1e 1e 32 28 32 28 28 28 1e 1e 32
|
||||
// 40 40 30 50 50 30 30 50 40 50 40 40 40 30 30 50
|
||||
// Nord 32 1e 1e 28 28 32 1e 32 32 1e 28 28 28 28 1e 32
|
||||
// 50 30 30 40 40 50 30 50 50 30 40 40 40 40 30 50
|
||||
// StrIntWilAglSpdEndPerLuk
|
||||
// Male Female
|
||||
case ESM4::SUB_CNAM: //skipping...1 // Only in TES4?
|
||||
// Sheogorath 0x00
|
||||
// Golden Saint 0x03
|
||||
// Dark Seducer 0x0C
|
||||
// Vampire Race 0x00
|
||||
// Dremora 0x07
|
||||
// Argonian 0x00
|
||||
// Nord 0x05
|
||||
// Breton 0x05
|
||||
// Wood Elf 0x0D
|
||||
// khajiit 0x05
|
||||
// Dark Elf 0x00
|
||||
// Orc 0x0C
|
||||
// High Elf 0x0F
|
||||
// Redguard 0x0D
|
||||
// Imperial 0x0D
|
||||
case ESM4::SUB_DATA: //skipping...36 // ?? different length to TES5
|
||||
// Altimer
|
||||
//
|
||||
// hex 13 05 14 0a 15 05 16 0a 17 05 18 0a ff 00 00 00
|
||||
// dec 5 10 5 10 5 10 -1 0
|
||||
// alc alt conj dest illu myst none unknown (always 00 00)
|
||||
//
|
||||
// cd cc 8c 3f : 1.1 height Male
|
||||
// cd cc 8c 3f : 1.1 height Female
|
||||
// 00 00 80 3f : 1.0 weihgt Male
|
||||
// 00 00 80 3f : 1.0 weight Female
|
||||
// 01 00 00 00 fist byte 1 means playable? uint32_t flag?
|
||||
//
|
||||
// Redguard
|
||||
//
|
||||
// hex 0d 0a 10 0a 12 05 1b 05 0e 0a 1d 05 ff 00 00 00
|
||||
// dec 10 10 5 5 10 5 -1
|
||||
// ath blun h.arm l.arm blade merch
|
||||
//
|
||||
//
|
||||
// 0a d7 83 3f : 1.03 height Male
|
||||
// 00 00 80 3f : 1.0 height Female
|
||||
// 0a d7 83 3f : 1.03 weight Male
|
||||
// 00 00 80 3f : 1.0 weight Female
|
||||
// 01 00 00 00
|
||||
//
|
||||
// skill index
|
||||
// 0x0C Armorer
|
||||
// 0x0D Athletics
|
||||
// 0x0E Blade
|
||||
// 0x0F Block
|
||||
// 0x10 Blunt
|
||||
// 0x11 HandToHand
|
||||
// 0x12 HeavyArmor
|
||||
// 0x13 Alchemy
|
||||
// 0x14 Alteration
|
||||
// 0x15 Conjuration
|
||||
// 0x16 Destruction
|
||||
// 0x17 Illusion
|
||||
// 0x18 Mysticism
|
||||
// 0x19 Restoration
|
||||
// 0x1A Acrobatics
|
||||
// 0x1B LightArmor
|
||||
// 0x1C Marksman
|
||||
// 0x1D Mercantile
|
||||
// 0x1E Security
|
||||
// 0x1F Sneak
|
||||
// 0x20 Speechcraft
|
||||
case ESM4::SUB_SNAM: //skipping...2 // only in TES4?
|
||||
case ESM4::SUB_XNAM: //skipping...8 // only in TES4? Often has similar numbers to VNAM
|
||||
case ESM4::SUB_ENAM: //skipping...0 <- different lengthts, maybe formids for EYES?
|
||||
case ESM4::SUB_HNAM: //skipping...0 <- different lengthts, maybe formids for HAIR?
|
||||
case ESM4::SUB_VNAM: //skipping...8 // equipment type flags meant to be uint32 ???
|
||||
// GLOB reference? shows up in SCRO in sript
|
||||
// records and CTDA in INFO records
|
||||
{
|
||||
std::cout << "RACE " << ESM4::printName(subHdr.typeId) << " skipping..." << subHdr.dataSize << std::endl;
|
||||
// For debugging only
|
||||
//#if 0
|
||||
unsigned char mDataBuf[256/*bufSize*/];
|
||||
reader.get(&mDataBuf[0], subHdr.dataSize);
|
||||
|
||||
std::ostringstream ss;
|
||||
for (unsigned int i = 0; i < subHdr.dataSize; ++i)
|
||||
{
|
||||
//if (mDataBuf[i] > 64 && mDataBuf[i] < 91)
|
||||
//ss << (char)(mDataBuf[i]) << " ";
|
||||
//else
|
||||
ss << std::setfill('0') << std::setw(2) << std::hex << (int)(mDataBuf[i]);
|
||||
if ((i & 0x000f) == 0xf)
|
||||
ss << "\n";
|
||||
else if (i < 256/*bufSize*/-1)
|
||||
ss << " ";
|
||||
}
|
||||
std::cout << ss.str() << std::endl;
|
||||
|
||||
//reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
//#endif
|
||||
case ESM4::SUB_DNAM: //skipping...8 // decapitate armor, 2 formids
|
||||
case ESM4::SUB_FGGA: //skipping...120 // prob face gen stuff
|
||||
case ESM4::SUB_FGGS: //skipping...200 // prob face gen stuff
|
||||
case ESM4::SUB_FGTS: //skipping...200 // prob face gen stuff
|
||||
case ESM4::SUB_FNAM: //skipping...0 // start marker female model
|
||||
case ESM4::SUB_INDX: //skipping...4 // marker preceding egt models? uint32 always 0
|
||||
case ESM4::SUB_MNAM: //skipping...0 // start marker male model
|
||||
case ESM4::SUB_NAM0: //skipping...0 // start marker head data
|
||||
case ESM4::SUB_NAM1: //skipping...0 // strat marker egt models
|
||||
case ESM4::SUB_PNAM: //skipping...4 // face gen main clamp float
|
||||
case ESM4::SUB_SPLO: //skipping...4 // bonus spell formid (TES5 may have SPCT and multiple SPLO)
|
||||
case ESM4::SUB_UNAM: //skipping...4 // face gen face clamp float
|
||||
case ESM4::SUB_YNAM: // FO3
|
||||
case ESM4::SUB_NAM2: // FO3
|
||||
case ESM4::SUB_VTCK: // FO3
|
||||
case ESM4::SUB_MODT: // FO3
|
||||
case ESM4::SUB_MODD: // FO3
|
||||
case ESM4::SUB_ONAM: // FO3
|
||||
{
|
||||
|
||||
//std::cout << "RACE " << ESM4::printName(subHdr.typeId) << " skipping..." << subHdr.dataSize << std::endl;
|
||||
reader.skipSubRecordData();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ESM4::RACE::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void ESM4::Race::save(ESM4::Writer& writer) const
|
||||
//{
|
||||
//}
|
||||
|
||||
//void ESM4::Race::blank()
|
||||
//{
|
||||
//}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright (C) 2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
Much of the information on the data structures are based on the information
|
||||
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
|
||||
trial & error. See http://en.uesp.net/wiki for details.
|
||||
|
||||
*/
|
||||
#ifndef ESM4_RACE
|
||||
#define ESM4_RACE
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class Reader;
|
||||
class Writer;
|
||||
typedef std::uint32_t FormId;
|
||||
|
||||
struct Race
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
std::uint8_t flags; // 0x01 = not playable, 0x02 = not male, 0x04 = not female, ?? = fixed
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
FormId mFormId; // from the header
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
std::string mModel;
|
||||
std::string mIcon; // inventory
|
||||
std::string mDesc;
|
||||
|
||||
float mBoundRadius;
|
||||
|
||||
Data mData;
|
||||
|
||||
Race();
|
||||
virtual ~Race();
|
||||
|
||||
virtual void load(ESM4::Reader& reader);
|
||||
//virtual void save(ESM4::Writer& writer) const;
|
||||
|
||||
//void blank();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ESM4_RACE
|
@ -0,0 +1,560 @@
|
||||
/*
|
||||
Copyright (C) 2015-2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
*/
|
||||
#include "reader.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
#include <OgreResourceGroupManager.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "formid.hpp"
|
||||
|
||||
#ifdef NDEBUG // FIXME: debugging only
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
ESM4::Reader::Reader() : mObserver(nullptr), mRecordRemaining(0), mCellGridValid(false)
|
||||
{
|
||||
mCtx.modIndex = 0;
|
||||
mCtx.currWorld = 0;
|
||||
mCtx.currCell = 0;
|
||||
mCtx.recHeaderSize = sizeof(ESM4::RecordHeader);
|
||||
|
||||
mInBuf.reset();
|
||||
mDataBuf.reset();
|
||||
mStream.setNull();
|
||||
mSavedStream.setNull();
|
||||
}
|
||||
|
||||
ESM4::Reader::~Reader()
|
||||
{
|
||||
}
|
||||
|
||||
// Since the record data may have been compressed, it is not always possible to use seek() to
|
||||
// go to a position of a sub record.
|
||||
//
|
||||
// The record header needs to be saved in the context or the header needs to be re-loaded after
|
||||
// restoring the context. The latter option was chosen.
|
||||
ESM4::ReaderContext ESM4::Reader::getContext()
|
||||
{
|
||||
mCtx.filePos = mStream->tell() - mCtx.recHeaderSize; // update file position
|
||||
return mCtx;
|
||||
}
|
||||
|
||||
// NOTE: Assumes that the caller has reopened the file if necessary
|
||||
bool ESM4::Reader::restoreContext(const ESM4::ReaderContext& ctx)
|
||||
{
|
||||
if (!mSavedStream.isNull())
|
||||
{
|
||||
mStream = mSavedStream;
|
||||
mSavedStream.setNull();
|
||||
}
|
||||
|
||||
mCtx.groupStack.clear(); // probably not necessary?
|
||||
mCtx = ctx;
|
||||
mStream->seek(ctx.filePos); // update file position
|
||||
|
||||
//return getRecordHeader(); // can't use it because mStream may have been switched
|
||||
|
||||
if (mObserver)
|
||||
mObserver->update(mCtx.recHeaderSize);
|
||||
|
||||
return (mStream->read(&mRecordHeader, mCtx.recHeaderSize) == mCtx.recHeaderSize
|
||||
&& (mRecordRemaining = mRecordHeader.record.dataSize)); // for keeping track of sub records
|
||||
}
|
||||
|
||||
bool ESM4::Reader::skipNextGroupCellChild()
|
||||
{
|
||||
if (mStream->eof())
|
||||
return false;
|
||||
|
||||
std::size_t pos = mStream->tell(); // save
|
||||
ESM4::RecordHeader hdr;
|
||||
if (!mStream->read(&hdr, mCtx.recHeaderSize))
|
||||
throw std::runtime_error("ESM4::Reader::could not peek header");
|
||||
|
||||
if (hdr.group.type != ESM4::Grp_CellChild)
|
||||
{
|
||||
mStream->seek(pos); // go back to saved
|
||||
return false;
|
||||
}
|
||||
|
||||
mCtx.groupStack.back().second -= hdr.group.groupSize;
|
||||
mStream->skip(hdr.group.groupSize - (std::uint32_t)mCtx.recHeaderSize); // already read the header
|
||||
if (mObserver)
|
||||
mObserver->update(hdr.group.groupSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: consider checking file path using boost::filesystem::exists()
|
||||
std::size_t ESM4::Reader::openTes4File(const std::string& name)
|
||||
{
|
||||
mCtx.filename = name;
|
||||
mStream = Ogre::DataStreamPtr(new Ogre::FileStreamDataStream(
|
||||
OGRE_NEW_T(std::ifstream(name.c_str(), std::ios_base::binary),
|
||||
Ogre::MEMCATEGORY_GENERAL), /*freeOnClose*/true));
|
||||
return mStream->size();
|
||||
}
|
||||
|
||||
void ESM4::Reader::setRecHeaderSize(const std::size_t size)
|
||||
{
|
||||
mCtx.recHeaderSize = size;
|
||||
}
|
||||
|
||||
void ESM4::Reader::registerForUpdates(ESM4::ReaderObserver *observer)
|
||||
{
|
||||
mObserver = observer;
|
||||
}
|
||||
|
||||
// FIXME: only "English" strings supported for now
|
||||
void ESM4::Reader::buildLStringIndex()
|
||||
{
|
||||
if ((mHeader.mFlags & Rec_ESM) == 0 || (mHeader.mFlags & Rec_Localized) == 0)
|
||||
return;
|
||||
|
||||
boost::filesystem::path p(mCtx.filename);
|
||||
std::string filename = p.stem().filename().string();
|
||||
|
||||
buildLStringIndex("Strings/" + filename + "_English.STRINGS", Type_Strings);
|
||||
buildLStringIndex("Strings/" + filename + "_English.ILSTRINGS", Type_ILStrings);
|
||||
buildLStringIndex("Strings/" + filename + "_English.DLSTRINGS", Type_DLStrings);
|
||||
}
|
||||
|
||||
void ESM4::Reader::buildLStringIndex(const std::string& stringFile, LocalizedStringType stringType)
|
||||
{
|
||||
std::uint32_t numEntries;
|
||||
std::uint32_t dataSize;
|
||||
std::uint32_t stringId;
|
||||
LStringOffset sp;
|
||||
sp.type = stringType;
|
||||
|
||||
// TODO: possibly check if the resource exists?
|
||||
Ogre::DataStreamPtr filestream = Ogre::ResourceGroupManager::getSingleton().openResource(stringFile);
|
||||
|
||||
switch (stringType)
|
||||
{
|
||||
case Type_Strings: mStrings = filestream; break;
|
||||
case Type_ILStrings: mILStrings = filestream; break;
|
||||
case Type_DLStrings: mDLStrings = filestream; break;
|
||||
default:
|
||||
throw std::runtime_error("ESM4::Reader::unexpected string type");
|
||||
}
|
||||
|
||||
filestream->read(&numEntries, sizeof(numEntries));
|
||||
filestream->read(&dataSize, sizeof(dataSize));
|
||||
std::size_t dataStart = filestream->size() - dataSize;
|
||||
for (unsigned int i = 0; i < numEntries; ++i)
|
||||
{
|
||||
filestream->read(&stringId, sizeof(stringId));
|
||||
filestream->read(&sp.offset, sizeof(sp.offset));
|
||||
sp.offset += (std::uint32_t)dataStart;
|
||||
mLStringIndex[stringId] = sp;
|
||||
}
|
||||
//assert(dataStart - filestream->tell() == 0 && "String file start of data section mismatch");
|
||||
}
|
||||
|
||||
void ESM4::Reader::getLocalizedString(std::string& str)
|
||||
{
|
||||
std::uint32_t stringId;
|
||||
get(stringId);
|
||||
getLocalizedString(stringId, str);
|
||||
}
|
||||
|
||||
// FIXME: very messy and probably slow/inefficient
|
||||
void ESM4::Reader::getLocalizedString(const FormId stringId, std::string& str)
|
||||
{
|
||||
const std::map<FormId, LStringOffset>::const_iterator it = mLStringIndex.find(stringId);
|
||||
|
||||
if (it != mLStringIndex.end())
|
||||
{
|
||||
Ogre::DataStreamPtr filestream;
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case Type_Strings:
|
||||
{
|
||||
filestream = mStrings;
|
||||
filestream->seek(it->second.offset);
|
||||
|
||||
char ch;
|
||||
std::vector<char> data;
|
||||
do {
|
||||
filestream->read(&ch, sizeof(ch));
|
||||
data.push_back(ch);
|
||||
} while (ch != 0);
|
||||
|
||||
str = std::string(data.data());
|
||||
return;
|
||||
}
|
||||
case Type_ILStrings: filestream = mILStrings; break;
|
||||
case Type_DLStrings: filestream = mDLStrings; break;
|
||||
default:
|
||||
throw std::runtime_error("ESM4::Reader::getLocalizedString unexpected string type");
|
||||
}
|
||||
|
||||
// get ILStrings or DLStrings
|
||||
filestream->seek(it->second.offset);
|
||||
getZString(str, filestream);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("ESM4::Reader::getLocalizedString localized string not found");
|
||||
}
|
||||
|
||||
bool ESM4::Reader::getRecordHeader()
|
||||
{
|
||||
// FIXME: this seems very hacky but we may have skipped subrecords from within an inflated data block
|
||||
if (/*mStream->eof() && */!mSavedStream.isNull())
|
||||
{
|
||||
mStream = mSavedStream;
|
||||
mSavedStream.setNull();
|
||||
}
|
||||
|
||||
// keep track of data left to read from the file
|
||||
// FIXME: having a default instance of mObserver might be faster than checking for null all the time?
|
||||
if (mObserver)
|
||||
mObserver->update(mCtx.recHeaderSize);
|
||||
|
||||
return (mStream->read(&mRecordHeader, mCtx.recHeaderSize) == mCtx.recHeaderSize
|
||||
&& (mRecordRemaining = mRecordHeader.record.dataSize)); // for keeping track of sub records
|
||||
|
||||
// After reading the record header we can cache a WRLD or CELL formId for convenient access later.
|
||||
// (currently currWorld and currCell are set manually when loading the WRLD and CELL records)
|
||||
}
|
||||
|
||||
bool ESM4::Reader::getSubRecordHeader()
|
||||
{
|
||||
bool result = false;
|
||||
// NOTE: some SubRecords have 0 dataSize (e.g. SUB_RDSD in one of REC_REGN records in Oblivion.esm).
|
||||
// Also SUB_XXXX has zero dataSize and the following 4 bytes represent the actual dataSize
|
||||
// - hence it require manual updtes to mRecordRemaining. See ESM4::NavMesh and ESM4::World.
|
||||
if (mRecordRemaining >= sizeof(mSubRecordHeader))
|
||||
{
|
||||
result = get(mSubRecordHeader);
|
||||
mRecordRemaining -= (sizeof(mSubRecordHeader) + mSubRecordHeader.dataSize);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: the parameter 'files' must have the file names in the loaded order
|
||||
void ESM4::Reader::updateModIndicies(const std::vector<std::string>& files)
|
||||
{
|
||||
if (files.size() >= 0xff)
|
||||
throw std::runtime_error("ESM4::Reader::updateModIndicies too many files"); // 0xff is reserved
|
||||
|
||||
// NOTE: this map is rebuilt each time this method is called (i.e. each time a file is loaded)
|
||||
// Perhaps there is an opportunity to optimize this by saving the result somewhere.
|
||||
// But then, the number of files is at most around 250 so perhaps keeping it simple might be better.
|
||||
|
||||
// build a lookup map
|
||||
std::unordered_map<std::string, size_t> fileIndex;
|
||||
|
||||
for (size_t i = 0; i < files.size(); ++i) // ATTENTION: assumes current file is not included
|
||||
fileIndex[boost::to_lower_copy<std::string>(files[i])] = i;
|
||||
|
||||
mHeader.mModIndicies.resize(mHeader.mMaster.size());
|
||||
for (unsigned int i = 0; i < mHeader.mMaster.size(); ++i)
|
||||
{
|
||||
// locate the position of the dependency in already loaded files
|
||||
std::unordered_map<std::string, size_t>::const_iterator it
|
||||
= fileIndex.find(boost::to_lower_copy<std::string>(mHeader.mMaster[i].name));
|
||||
|
||||
if (it != fileIndex.end())
|
||||
mHeader.mModIndicies[i] = (std::uint32_t)((it->second << 24) & 0xff000000);
|
||||
else
|
||||
throw std::runtime_error("ESM4::Reader::updateModIndicies required dependency file not loaded");
|
||||
#if 0
|
||||
std::cout << "Master Mod: " << mHeader.mMaster[i].name << ", " // FIXME: debugging only
|
||||
<< ESM4::formIdToString(mHeader.mModIndicies[i]) << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!mHeader.mModIndicies.empty() && mHeader.mModIndicies[0] != 0)
|
||||
throw std::runtime_error("ESM4::Reader::updateModIndicies base modIndex is not zero");
|
||||
}
|
||||
|
||||
void ESM4::Reader::saveGroupStatus()
|
||||
{
|
||||
#if 0
|
||||
std::string padding = ""; // FIXME: debugging only
|
||||
padding.insert(0, mCtx.groupStack.size()*2, ' ');
|
||||
std::cout << padding << "Starting record group "
|
||||
<< ESM4::printLabel(mRecordHeader.group.label, mRecordHeader.group.type) << std::endl;
|
||||
#endif
|
||||
if (mRecordHeader.group.groupSize == (std::uint32_t)mCtx.recHeaderSize)
|
||||
{
|
||||
#if 0
|
||||
std::cout << padding << "Igorning record group " // FIXME: debugging only
|
||||
<< ESM4::printLabel(mRecordHeader.group.label, mRecordHeader.group.type)
|
||||
<< " (empty)" << std::endl;
|
||||
#endif
|
||||
if (!mCtx.groupStack.empty()) // top group may be empty (e.g. HAIR in Skyrim)
|
||||
{
|
||||
// don't put on the stack, checkGroupStatus() may not get called before recursing into this method
|
||||
mCtx.groupStack.back().second -= mRecordHeader.group.groupSize;
|
||||
checkGroupStatus();
|
||||
}
|
||||
return; // DLCMehrunesRazor - Unofficial Patch.esp is at EOF after one of these empty groups...
|
||||
}
|
||||
|
||||
// push group
|
||||
mCtx.groupStack.push_back(std::make_pair(mRecordHeader.group,
|
||||
mRecordHeader.group.groupSize - (std::uint32_t)mCtx.recHeaderSize));
|
||||
}
|
||||
|
||||
const ESM4::CellGrid& ESM4::Reader::currCellGrid() const
|
||||
{
|
||||
// Maybe should throw an exception instead?
|
||||
assert(mCellGridValid && "Attempt to use an invalid cell grid");
|
||||
|
||||
return mCurrCellGrid;
|
||||
}
|
||||
|
||||
void ESM4::Reader::checkGroupStatus()
|
||||
{
|
||||
// pop finished groups
|
||||
while (!mCtx.groupStack.empty() && mCtx.groupStack.back().second == 0)
|
||||
{
|
||||
ESM4::GroupTypeHeader grp = mCtx.groupStack.back().first; // FIXME: grp is for debugging only
|
||||
|
||||
uint32_t groupSize = mCtx.groupStack.back().first.groupSize;
|
||||
mCtx.groupStack.pop_back();
|
||||
#if 0
|
||||
std::string padding = ""; // FIXME: debugging only
|
||||
padding.insert(0, mCtx.groupStack.size()*2, ' ');
|
||||
std::cout << padding << "Finished record group " << ESM4::printLabel(grp.label, grp.type) << std::endl;
|
||||
#endif
|
||||
// Check if the previous group was the final one
|
||||
if (mCtx.groupStack.empty())
|
||||
return;
|
||||
|
||||
//assert (mCtx.groupStack.back().second >= groupSize && "Read more records than available");
|
||||
#if 0
|
||||
if (mCtx.groupStack.back().second < groupSize) // FIXME: debugging only
|
||||
std::cerr << ESM4::printLabel(mCtx.groupStack.back().first.label,
|
||||
mCtx.groupStack.back().first.type)
|
||||
<< " read more records than available" << std::endl;
|
||||
#endif
|
||||
mCtx.groupStack.back().second -= groupSize;
|
||||
}
|
||||
}
|
||||
|
||||
// WARNING: this method should be used after first calling saveGroupStatus()
|
||||
const ESM4::GroupTypeHeader& ESM4::Reader::grp(std::size_t pos) const
|
||||
{
|
||||
assert(pos <= mCtx.groupStack.size()-1 && "ESM4::Reader::grp - exceeded stack depth");
|
||||
|
||||
return (*(mCtx.groupStack.end()-pos-1)).first;
|
||||
}
|
||||
|
||||
void ESM4::Reader::getRecordData()
|
||||
{
|
||||
std::uint32_t bufSize = 0;
|
||||
|
||||
if ((mRecordHeader.record.flags & ESM4::Rec_Compressed) != 0)
|
||||
{
|
||||
mInBuf.reset(new unsigned char[mRecordHeader.record.dataSize-(int)sizeof(bufSize)]);
|
||||
mStream->read(&bufSize, sizeof(bufSize));
|
||||
mStream->read(mInBuf.get(), mRecordHeader.record.dataSize-(int)sizeof(bufSize));
|
||||
mDataBuf.reset(new unsigned char[bufSize]);
|
||||
|
||||
int ret;
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.avail_in = bufSize;
|
||||
strm.next_in = mInBuf.get();
|
||||
ret = inflateInit(&strm);
|
||||
if (ret != Z_OK)
|
||||
throw std::runtime_error("ESM4::Reader::getRecordData - inflateInit failed");
|
||||
|
||||
strm.avail_out = bufSize;
|
||||
strm.next_out = mDataBuf.get();
|
||||
ret = inflate(&strm, Z_NO_FLUSH);
|
||||
assert(ret != Z_STREAM_ERROR && "ESM4::Reader::getRecordData - inflate - state clobbered");
|
||||
switch (ret)
|
||||
{
|
||||
case Z_NEED_DICT:
|
||||
ret = Z_DATA_ERROR; /* and fall through */
|
||||
case Z_DATA_ERROR: //FONV.esm 0xB0CFF04 LAND record zlip DATA_ERROR
|
||||
case Z_MEM_ERROR:
|
||||
inflateEnd(&strm);
|
||||
getRecordDataPostActions();
|
||||
throw std::runtime_error("ESM4::Reader::getRecordData - inflate failed");
|
||||
}
|
||||
assert(ret == Z_OK || ret == Z_STREAM_END);
|
||||
|
||||
// For debugging only
|
||||
#if 0
|
||||
std::ostringstream ss;
|
||||
for (unsigned int i = 0; i < bufSize; ++i)
|
||||
{
|
||||
if (mDataBuf[i] > 64 && mDataBuf[i] < 91)
|
||||
ss << (char)(mDataBuf[i]) << " ";
|
||||
else
|
||||
ss << std::setfill('0') << std::setw(2) << std::hex << (int)(mDataBuf[i]);
|
||||
if ((i & 0x000f) == 0xf)
|
||||
ss << "\n";
|
||||
else if (i < bufSize-1)
|
||||
ss << " ";
|
||||
}
|
||||
std::cout << ss.str() << std::endl;
|
||||
#endif
|
||||
inflateEnd(&strm);
|
||||
|
||||
mSavedStream = mStream;
|
||||
mStream = Ogre::DataStreamPtr(new Ogre::MemoryDataStream(mDataBuf.get(), bufSize, false, true));
|
||||
}
|
||||
|
||||
getRecordDataPostActions();
|
||||
//std::cout << "data size 0x" << std::hex << mRecordHeader.record.dataSize << std::endl; // FIXME: debug only
|
||||
}
|
||||
|
||||
void ESM4::Reader::getRecordDataPostActions()
|
||||
{
|
||||
// keep track of data left to read from the current group
|
||||
assert (!mCtx.groupStack.empty() && "Read data for a record without a group");
|
||||
mCtx.groupStack.back().second -= (std::uint32_t)mCtx.recHeaderSize + mRecordHeader.record.dataSize;
|
||||
|
||||
// keep track of data left to read from the file
|
||||
if (mObserver)
|
||||
mObserver->update(mRecordHeader.record.dataSize);
|
||||
}
|
||||
|
||||
bool ESM4::Reader::getZString(std::string& str)
|
||||
{
|
||||
return getZString(str, mStream);
|
||||
}
|
||||
|
||||
// FIXME: how to without using a temp buffer?
|
||||
bool ESM4::Reader::getZString(std::string& str, Ogre::DataStreamPtr filestream)
|
||||
{
|
||||
std::uint32_t size = 0;
|
||||
if (filestream == mStream)
|
||||
size = mSubRecordHeader.dataSize; // WARNING: assumed size from the header is correct
|
||||
else
|
||||
filestream->read(&size, sizeof(size));
|
||||
|
||||
boost::scoped_array<char> buf(new char[size]);
|
||||
if (filestream->read(buf.get(), size) == (size_t)size)
|
||||
{
|
||||
|
||||
if (buf[size - 1] != 0)
|
||||
{
|
||||
str.assign(buf.get(), size);
|
||||
//std::cerr << "ESM4::Reader::getZString string is not terminated with a zero" << std::endl;
|
||||
}
|
||||
else
|
||||
str.assign(buf.get(), size - 1);// don't copy null terminator
|
||||
|
||||
//assert((size_t)size-1 == str.size() && "ESM4::Reader::getZString string size mismatch");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
str.clear();
|
||||
return false; // FIXME: throw instead?
|
||||
}
|
||||
}
|
||||
|
||||
// Assumes that saveGroupStatus() is not called before this (hence we don't update mCtx.groupStack)
|
||||
void ESM4::Reader::skipGroup()
|
||||
{
|
||||
#if 0
|
||||
std::string padding = ""; // FIXME: debugging only
|
||||
padding.insert(0, mCtx.groupStack.size()*2, ' ');
|
||||
std::cout << padding << "Skipping record group "
|
||||
<< ESM4::printLabel(mRecordHeader.group.label, mRecordHeader.group.type) << std::endl;
|
||||
#endif
|
||||
// Note: subtract the size of header already read before skipping
|
||||
mStream->skip(mRecordHeader.group.groupSize - (std::uint32_t)mCtx.recHeaderSize);
|
||||
|
||||
// keep track of data left to read from the file
|
||||
if (mObserver)
|
||||
mObserver->update((std::size_t)mRecordHeader.group.groupSize - mCtx.recHeaderSize);
|
||||
|
||||
if (!mCtx.groupStack.empty())
|
||||
mCtx.groupStack.back().second -= mRecordHeader.group.groupSize;
|
||||
}
|
||||
|
||||
void ESM4::Reader::skipRecordData()
|
||||
{
|
||||
mStream->skip(mRecordHeader.record.dataSize);
|
||||
|
||||
// keep track of data left to read from the current group
|
||||
assert (!mCtx.groupStack.empty() && "Skipping a record without a group");
|
||||
mCtx.groupStack.back().second -= (std::uint32_t)mCtx.recHeaderSize + mRecordHeader.record.dataSize;
|
||||
|
||||
// keep track of data left to read from the file
|
||||
if (mObserver)
|
||||
mObserver->update(mRecordHeader.record.dataSize);
|
||||
}
|
||||
|
||||
void ESM4::Reader::skipSubRecordData()
|
||||
{
|
||||
mStream->skip(mSubRecordHeader.dataSize);
|
||||
}
|
||||
|
||||
void ESM4::Reader::skipSubRecordData(std::uint32_t size)
|
||||
{
|
||||
mStream->skip(size);
|
||||
}
|
||||
|
||||
// ModIndex adjusted formId according to master file dependencies
|
||||
// (see http://www.uesp.net/wiki/Tes4Mod:FormID_Fixup)
|
||||
// NOTE: need to update modindex to mModIndicies.size() before saving
|
||||
void ESM4::Reader::adjustFormId(FormId& id)
|
||||
{
|
||||
if (mHeader.mModIndicies.empty())
|
||||
return;
|
||||
|
||||
unsigned int index = (id >> 24) & 0xff;
|
||||
|
||||
if (index < mHeader.mModIndicies.size())
|
||||
id = mHeader.mModIndicies[index] | (id & 0x00ffffff);
|
||||
else
|
||||
id = mCtx.modIndex | (id & 0x00ffffff);
|
||||
}
|
||||
|
||||
bool ESM4::Reader::getFormId(FormId& id)
|
||||
{
|
||||
if (!get(id))
|
||||
return false;
|
||||
|
||||
adjustFormId(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ESM4::Reader::adjustGRUPFormId()
|
||||
{
|
||||
adjustFormId(mRecordHeader.group.label.value);
|
||||
}
|
@ -0,0 +1,278 @@
|
||||
/*
|
||||
Copyright (C) 2015-2016, 2018 cc9cii
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
cc9cii cc9c@iinet.net.au
|
||||
|
||||
*/
|
||||
#ifndef ESM4_READER_H
|
||||
#define ESM4_READER_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/scoped_array.hpp>
|
||||
|
||||
#include <OgreDataStream.h>
|
||||
|
||||
#include "common.hpp"
|
||||
#include "tes4.hpp"
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
class ReaderObserver
|
||||
{
|
||||
public:
|
||||
ReaderObserver() {}
|
||||
virtual ~ReaderObserver() {}
|
||||
|
||||
virtual void update(std::size_t size) = 0;
|
||||
};
|
||||
|
||||
typedef std::vector<std::pair<ESM4::GroupTypeHeader, std::uint32_t> > GroupStack;
|
||||
|
||||
struct ReaderContext
|
||||
{
|
||||
std::string filename; // from openTes4File()
|
||||
std::uint32_t modIndex; // the sequential position of this file in the load order:
|
||||
// 0x00 reserved, 0xFF in-game (see notes below)
|
||||
|
||||
GroupStack groupStack; // keep track of bytes left to find when a group is done
|
||||
|
||||
FormId currWorld; // formId of current world - for grouping CELL records
|
||||
FormId currCell; // formId of current cell
|
||||
|
||||
std::size_t recHeaderSize; // normally should be already set correctly, but just in
|
||||
// case the file was re-opened. default = TES5 size,
|
||||
// can be reduced for TES4 by setRecHeaderSize()
|
||||
|
||||
std::size_t filePos; // assume that the record header will be re-read once
|
||||
// the context is restored.
|
||||
};
|
||||
|
||||
class Reader
|
||||
{
|
||||
ReaderObserver *mObserver; // observer for tracking bytes read
|
||||
|
||||
Header mHeader; // ESM header // FIXME
|
||||
RecordHeader mRecordHeader; // header of the current record or group being processed
|
||||
SubRecordHeader mSubRecordHeader; // header of the current sub record being processed
|
||||
std::size_t mRecordRemaining; // number of bytes to be read by sub records following current
|
||||
|
||||
// FIXME: try to get rid of these two members, seem like massive hacks
|
||||
CellGrid mCurrCellGrid; // TODO: should keep a map of cell formids
|
||||
bool mCellGridValid;
|
||||
|
||||
ReaderContext mCtx;
|
||||
|
||||
// Use scoped arrays to avoid memory leak due to exceptions, etc.
|
||||
// TODO: try fixed size buffers on the stack for both buffers (may be faster)
|
||||
boost::scoped_array<unsigned char> mInBuf;
|
||||
boost::scoped_array<unsigned char> mDataBuf;
|
||||
|
||||
Ogre::DataStreamPtr mStream;
|
||||
Ogre::DataStreamPtr mSavedStream; // mStream is saved here while using deflated memory stream
|
||||
|
||||
Ogre::DataStreamPtr mStrings;
|
||||
Ogre::DataStreamPtr mILStrings;
|
||||
Ogre::DataStreamPtr mDLStrings;
|
||||
|
||||
enum LocalizedStringType
|
||||
{
|
||||
Type_Strings = 0,
|
||||
Type_ILStrings = 1,
|
||||
Type_DLStrings = 2
|
||||
};
|
||||
|
||||
struct LStringOffset
|
||||
{
|
||||
LocalizedStringType type;
|
||||
std::uint32_t offset;
|
||||
};
|
||||
std::map<FormId, LStringOffset> mLStringIndex;
|
||||
|
||||
void getRecordDataPostActions(); // housekeeping actions before processing the next record
|
||||
void buildLStringIndex(const std::string& stringFile, LocalizedStringType stringType);
|
||||
|
||||
public:
|
||||
|
||||
Reader();
|
||||
~Reader();
|
||||
|
||||
// Methods added for updating loading progress bars
|
||||
inline std::size_t getFileSize() const { return mStream->size(); }
|
||||
inline std::size_t getFileOffset() const { return mStream->tell(); }
|
||||
|
||||
// Methods added for saving/restoring context
|
||||
ReaderContext getContext();
|
||||
bool restoreContext(const ReaderContext& ctx); // returns the result of re-reading the header
|
||||
bool skipNextGroupCellChild(); // returns true if skipped
|
||||
|
||||
std::size_t openTes4File(const std::string& name);
|
||||
|
||||
// NOTE: must be called before calling getRecordHeader()
|
||||
void setRecHeaderSize(const std::size_t size);
|
||||
|
||||
inline void loadHeader() { mHeader.load(*this); }
|
||||
inline unsigned int esmVersion() const { return mHeader.mData.version.ui; }
|
||||
inline unsigned int numRecords() const { return mHeader.mData.records; }
|
||||
|
||||
void buildLStringIndex();
|
||||
inline bool hasLocalizedStrings() const { return (mHeader.mFlags & Rec_Localized) != 0; }
|
||||
void getLocalizedString(std::string& str); // convenience method for below
|
||||
void getLocalizedString(const FormId stringId, std::string& str);
|
||||
|
||||
// Read 24 bytes of header. The caller can then decide whether to process or skip the data.
|
||||
bool getRecordHeader();
|
||||
|
||||
inline const RecordHeader& hdr() const { return mRecordHeader; }
|
||||
|
||||
const GroupTypeHeader& grp(std::size_t pos = 0) const;
|
||||
|
||||
// The object setting up this reader needs to supply the file's load order index
|
||||
// so that the formId's in this file can be adjusted with the file (i.e. mod) index.
|
||||
void setModIndex(int index) { mCtx.modIndex = (index << 24) & 0xff000000; }
|
||||
void updateModIndicies(const std::vector<std::string>& files);
|
||||
|
||||
// Maybe should throw an exception if called when not valid?
|
||||
const CellGrid& currCellGrid() const;
|
||||
|
||||
inline const bool hasCellGrid() const { return mCellGridValid; }
|
||||
|
||||
// This is set while loading a CELL record (XCLC sub record) and invalidated
|
||||
// each time loading a CELL (see clearCellGrid())
|
||||
inline void setCurrCellGrid(const CellGrid& currCell) {
|
||||
mCellGridValid = true;
|
||||
mCurrCellGrid = currCell;
|
||||
}
|
||||
|
||||
// FIXME: This is called each time a new CELL record is read. Rather than calling this
|
||||
// methos explicitly, mCellGridValid should be set automatically somehow.
|
||||
//
|
||||
// Cell 2c143 is loaded immedicatly after 1bdb1 and can mistakely appear to have grid 0, 1.
|
||||
inline void clearCellGrid() { mCellGridValid = false; }
|
||||
|
||||
// Should be set at the beginning of a CELL load
|
||||
inline void setCurrCell(FormId formId) { mCtx.currCell = formId; }
|
||||
|
||||
inline FormId currCell() const { return mCtx.currCell; }
|
||||
|
||||
// Should be set at the beginning of a WRLD load
|
||||
inline void setCurrWorld(FormId formId) { mCtx.currWorld = formId; }
|
||||
|
||||
inline FormId currWorld() const { return mCtx.currWorld; }
|
||||
|
||||
// Get the data part of a record
|
||||
// Note: assumes the header was read correctly and nothing else was read
|
||||
void getRecordData();
|
||||
|
||||
// Skip the data part of a record
|
||||
// Note: assumes the header was read correctly and nothing else was read
|
||||
void skipRecordData();
|
||||
|
||||
// Skip the rest of the group
|
||||
// Note: assumes the header was read correctly and nothing else was read
|
||||
void skipGroup();
|
||||
|
||||
// Read 6 bytes of header. The caller can then decide whether to process or skip the data.
|
||||
bool getSubRecordHeader();
|
||||
|
||||
// Manally update (i.e. reduce) the bytes remaining to be read after SUB_XXXX
|
||||
inline void updateRecordRemaining(std::uint32_t subSize) { mRecordRemaining -= subSize; }
|
||||
|
||||
inline const SubRecordHeader& subRecordHeader() const { return mSubRecordHeader; }
|
||||
|
||||
// Skip the data part of a subrecord
|
||||
// Note: assumes the header was read correctly and nothing else was read
|
||||
void skipSubRecordData();
|
||||
|
||||
// Special for a subrecord following a XXXX subrecord
|
||||
void skipSubRecordData(std::uint32_t size);
|
||||
|
||||
// Get a subrecord of a particular type and data type
|
||||
template<typename T>
|
||||
bool getSubRecord(const ESM4::SubRecordTypes type, T& t)
|
||||
{
|
||||
ESM4::SubRecordHeader hdr;
|
||||
if (!get(hdr) || (hdr.typeId != type) || (hdr.dataSize != sizeof(T)))
|
||||
return false;
|
||||
|
||||
return get(t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool get(T& t) {
|
||||
return mStream->read(&t, sizeof(T)) == sizeof(T); // FIXME: try/catch block needed?
|
||||
}
|
||||
|
||||
// for arrays
|
||||
inline bool get(void* p, std::size_t size) {
|
||||
return mStream->read(p, size) == size; // FIXME: try/catch block needed?
|
||||
}
|
||||
|
||||
// ModIndex adjusted formId according to master file dependencies
|
||||
void adjustFormId(FormId& id);
|
||||
|
||||
bool getFormId(FormId& id);
|
||||
|
||||
void adjustGRUPFormId();
|
||||
|
||||
// Note: does not convert to UTF8
|
||||
// Note: assumes string size from the subrecord header
|
||||
bool getZString(std::string& str);
|
||||
bool getZString(std::string& str, Ogre::DataStreamPtr fileStream);
|
||||
|
||||
void checkGroupStatus();
|
||||
|
||||
void saveGroupStatus();
|
||||
|
||||
void registerForUpdates(ReaderObserver *observer);
|
||||
|
||||
// for debugging only
|
||||
size_t stackSize() const { return mCtx.groupStack.size(); }
|
||||
};
|
||||
|
||||
// An idea on extending the 254 mods limit
|
||||
// ---------------------------------------
|
||||
//
|
||||
// By using a 64bit formid internally it should be possible to extend the limit. However
|
||||
// saved games won't be compatible.
|
||||
//
|
||||
// One or two digits can be used, which will allow 4096-2=4094 or 65535-2=65533 mods.
|
||||
// With the remaining digits one can be used as a game index (e.g. TES3=0, TES4=1, etc).
|
||||
//
|
||||
// The remaining bits might still be useful for indicating something else about the object.
|
||||
//
|
||||
// game index
|
||||
// |
|
||||
// | mod index extend to 4 digits (or 3 digits?)
|
||||
// | +---+
|
||||
// | | |
|
||||
// v v v
|
||||
// 0xfffff f ff ff ffffff
|
||||
// ^^ ^ ^
|
||||
// || | |
|
||||
// || +----+
|
||||
// || 6 digit obj index
|
||||
// ++
|
||||
// 2 digit mod index
|
||||
//
|
||||
}
|
||||
|
||||
#endif // ESM4_READER_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue