mirror of https://github.com/OpenMW/openmw.git
TES4/TES5 ESM/ESP file reader.
To support the possibility of a standalone implementation of TES4, the ESM/ESP code is placed in the 'extern' folder. Much more work needs to be done.pull/1955/head^2
parent
15d5cdf3cf
commit
5ad440cb45
@ -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
|
@ -0,0 +1,269 @@
|
|||||||
|
/*
|
||||||
|
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 "refr.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <iostream> // FIXME: debug only
|
||||||
|
#include "formid.hpp" // FIXME: debug only
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
ESM4::Reference::Reference() : mFormId(0), mFlags(0), mDisabled(false), mBaseObj(0), mScale(1.f),
|
||||||
|
mOwner(0), mGlobal(0), mFactionRank(0), mCount(1)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
mFullName.clear();
|
||||||
|
|
||||||
|
mEsp.parent = 0;
|
||||||
|
mEsp.flags = 0;
|
||||||
|
|
||||||
|
mDoor.destDoor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::Reference::~Reference()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::Reference::load(ESM4::Reader& reader)
|
||||||
|
{
|
||||||
|
mFormId = reader.hdr().record.id;
|
||||||
|
reader.adjustFormId(mFormId);
|
||||||
|
mFlags = reader.hdr().record.flags;
|
||||||
|
// TODO: Let the engine apply this? Saved games?
|
||||||
|
//mDisabled = ((mFlags & ESM4::Rec_Disabled) != 0) ? true : false;
|
||||||
|
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 ("REFR FULL data read error");
|
||||||
|
#if 0
|
||||||
|
std::string padding = "";
|
||||||
|
padding.insert(0, reader.stackSize()*2, ' ');
|
||||||
|
std::cout << padding << "REFR Full Name: " << mFullName << std::endl;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_NAME:
|
||||||
|
{
|
||||||
|
reader.getFormId(mBaseObj);
|
||||||
|
#if 0
|
||||||
|
if (mFlags & ESM4::Rec_Disabled)
|
||||||
|
std::cout << "REFR disable at start " << formIdToString(mFormId) <<
|
||||||
|
" baseobj " << formIdToString(mBaseObj) <<
|
||||||
|
" " << (mEditorId.empty() ? "" : mEditorId) << std::endl; // FIXME
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_DATA: reader.get(mPosition); break;
|
||||||
|
case ESM4::SUB_XSCL: reader.get(mScale); break;
|
||||||
|
case ESM4::SUB_XOWN: reader.getFormId(mOwner); break;
|
||||||
|
case ESM4::SUB_XGLB: reader.getFormId(mGlobal); break;
|
||||||
|
case ESM4::SUB_XRNK: reader.get(mFactionRank); break;
|
||||||
|
case ESM4::SUB_XESP:
|
||||||
|
{
|
||||||
|
reader.get(mEsp);
|
||||||
|
reader.adjustFormId(mEsp.parent);
|
||||||
|
//std::cout << "REFR parent: " << formIdToString(mEsp.parent) << " ref " << formIdToString(mFormId)
|
||||||
|
//<< ", 0x" << std::hex << (mEsp.flags & 0xff) << std::endl;// FIXME
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_XTEL:
|
||||||
|
{
|
||||||
|
reader.get(mDoor.destDoor);
|
||||||
|
reader.get(mDoor.destPos);
|
||||||
|
if (esmVer == ESM4::VER_094 || esmVer == ESM4::VER_170 || isFONV)
|
||||||
|
reader.get(mDoor.flags); // not in Obvlivion
|
||||||
|
//std::cout << "REFR dest door: " << formIdToString(mDoor.destDoor) << std::endl;// FIXME
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_XSED:
|
||||||
|
{
|
||||||
|
// 1 or 4 bytes
|
||||||
|
if (subHdr.dataSize == 1)
|
||||||
|
{
|
||||||
|
uint8_t data = reader.get(data);
|
||||||
|
//std::cout << "REFR XSED " << std::hex << (int)data << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (subHdr.dataSize == 4)
|
||||||
|
{
|
||||||
|
uint32_t data = reader.get(data);
|
||||||
|
//std::cout << "REFR XSED " << std::hex << (int)data << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::cout << "REFR XSED dataSize: " << subHdr.dataSize << std::endl;// FIXME
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_XLOD:
|
||||||
|
{
|
||||||
|
// 12 bytes
|
||||||
|
if (subHdr.dataSize == 12)
|
||||||
|
{
|
||||||
|
uint32_t data = reader.get(data);
|
||||||
|
uint32_t data2 = reader.get(data);
|
||||||
|
uint32_t data3 = reader.get(data);
|
||||||
|
//std::cout << "REFR XLOD " << std::hex << (int)data << " " << (int)data2 << " " << (int)data3 << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//std::cout << "REFR XLOD dataSize: " << subHdr.dataSize << std::endl;// FIXME
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_XACT:
|
||||||
|
{
|
||||||
|
if (subHdr.dataSize == 4)
|
||||||
|
{
|
||||||
|
uint32_t data = reader.get(data);
|
||||||
|
//std::cout << "REFR XACT " << std::hex << (int)data << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::cout << "REFR XACT dataSize: " << subHdr.dataSize << std::endl;// FIXME
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// seems like another ref, e.g. 00064583 has base object 00000034 which is "XMarkerHeading"
|
||||||
|
case ESM4::SUB_XRTM: // formId
|
||||||
|
{
|
||||||
|
FormId id;
|
||||||
|
reader.get(id);
|
||||||
|
//std::cout << "REFR XRTM : " << formIdToString(id) << std::endl;// FIXME
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// lighting
|
||||||
|
case ESM4::SUB_LNAM: // lighting template formId
|
||||||
|
case ESM4::SUB_XLIG: // struct, FOV, fade, etc
|
||||||
|
case ESM4::SUB_XEMI: // LIGH formId
|
||||||
|
case ESM4::SUB_XRDS: // Radius or Radiance
|
||||||
|
case ESM4::SUB_XRGB:
|
||||||
|
case ESM4::SUB_XRGD: // tangent data?
|
||||||
|
case ESM4::SUB_XALP: // alpha cutoff
|
||||||
|
//
|
||||||
|
case ESM4::SUB_XLOC: // formId
|
||||||
|
case ESM4::SUB_XMRK:
|
||||||
|
case ESM4::SUB_FNAM:
|
||||||
|
case ESM4::SUB_XTRG: // formId
|
||||||
|
case ESM4::SUB_XPCI: // formId
|
||||||
|
case ESM4::SUB_XLCM:
|
||||||
|
case ESM4::SUB_XCNT:
|
||||||
|
case ESM4::SUB_TNAM:
|
||||||
|
case ESM4::SUB_ONAM:
|
||||||
|
case ESM4::SUB_VMAD:
|
||||||
|
case ESM4::SUB_XPRM:
|
||||||
|
case ESM4::SUB_INAM:
|
||||||
|
case ESM4::SUB_PDTO:
|
||||||
|
case ESM4::SUB_SCHR:
|
||||||
|
case ESM4::SUB_SCTX:
|
||||||
|
case ESM4::SUB_XAPD:
|
||||||
|
case ESM4::SUB_XAPR:
|
||||||
|
case ESM4::SUB_XCVL:
|
||||||
|
case ESM4::SUB_XCZA:
|
||||||
|
case ESM4::SUB_XCZC:
|
||||||
|
case ESM4::SUB_XEZN:
|
||||||
|
case ESM4::SUB_XFVC:
|
||||||
|
case ESM4::SUB_XHTW:
|
||||||
|
case ESM4::SUB_XIS2:
|
||||||
|
case ESM4::SUB_XLCN:
|
||||||
|
case ESM4::SUB_XLIB:
|
||||||
|
case ESM4::SUB_XLKR:
|
||||||
|
case ESM4::SUB_XLRM:
|
||||||
|
case ESM4::SUB_XLRT:
|
||||||
|
case ESM4::SUB_XLTW:
|
||||||
|
case ESM4::SUB_XMBO:
|
||||||
|
case ESM4::SUB_XMBP:
|
||||||
|
case ESM4::SUB_XMBR:
|
||||||
|
case ESM4::SUB_XNDP:
|
||||||
|
case ESM4::SUB_XOCP:
|
||||||
|
case ESM4::SUB_XPOD:
|
||||||
|
case ESM4::SUB_XPPA:
|
||||||
|
case ESM4::SUB_XPRD:
|
||||||
|
case ESM4::SUB_XPWR:
|
||||||
|
case ESM4::SUB_XRMR:
|
||||||
|
case ESM4::SUB_XSPC:
|
||||||
|
case ESM4::SUB_XTNM:
|
||||||
|
case ESM4::SUB_XTRI:
|
||||||
|
case ESM4::SUB_XWCN:
|
||||||
|
case ESM4::SUB_XWCU:
|
||||||
|
case ESM4::SUB_XATR: // Dawnguard only?
|
||||||
|
case ESM4::SUB_XHLT: // Unofficial Oblivion Patch
|
||||||
|
case ESM4::SUB_XCHG: // thievery.exp
|
||||||
|
case ESM4::SUB_XHLP: // FO3
|
||||||
|
case ESM4::SUB_XRDO: // FO3
|
||||||
|
case ESM4::SUB_XAMT: // FO3
|
||||||
|
case ESM4::SUB_XAMC: // FO3
|
||||||
|
case ESM4::SUB_XRAD: // FO3
|
||||||
|
case ESM4::SUB_XIBS: // FO3
|
||||||
|
case ESM4::SUB_XORD: // FO3
|
||||||
|
case ESM4::SUB_XCLP: // FO3
|
||||||
|
case ESM4::SUB_SCDA: // FO3
|
||||||
|
case ESM4::SUB_SCRO: // FO3
|
||||||
|
case ESM4::SUB_RCLR: // FO3
|
||||||
|
case ESM4::SUB_BNAM: // FONV
|
||||||
|
case ESM4::SUB_CNAM: // FONV
|
||||||
|
case ESM4::SUB_MMRK: // FONV
|
||||||
|
case ESM4::SUB_MNAM: // FONV
|
||||||
|
case ESM4::SUB_NNAM: // FONV
|
||||||
|
case ESM4::SUB_XATO: // FONV
|
||||||
|
case ESM4::SUB_SCRV: // FONV
|
||||||
|
case ESM4::SUB_SCVR: // FONV
|
||||||
|
case ESM4::SUB_SLSD: // FONV
|
||||||
|
case ESM4::SUB_XSRF: // FONV
|
||||||
|
case ESM4::SUB_XSRD: // FONV
|
||||||
|
case ESM4::SUB_WMI1: // FONV
|
||||||
|
case ESM4::SUB_XLRL: // Unofficial Skyrim Patch
|
||||||
|
{
|
||||||
|
//std::cout << "REFR " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::REFR::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::Reference::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
void ESM4::Reference::blank()
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
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_REFR_H
|
||||||
|
#define ESM4_REFR_H
|
||||||
|
|
||||||
|
#include "common.hpp" // Position
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
|
||||||
|
struct TeleportDest
|
||||||
|
{
|
||||||
|
FormId destDoor;
|
||||||
|
Position destPos;
|
||||||
|
std::uint32_t flags; // 0x01 no alarm (only in TES5)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unlike TES3, multiple cells can have the same exterior co-ordinates.
|
||||||
|
// The cells need to be organised under world spaces.
|
||||||
|
struct Reference
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
std::uint32_t mFactionRank;
|
||||||
|
|
||||||
|
bool mDisabled;
|
||||||
|
EnableParent mEsp; // TODO may need to check mFlags & 0x800 (initially disabled)
|
||||||
|
|
||||||
|
std::uint32_t mCount; // only if > 1 (default 1)
|
||||||
|
|
||||||
|
TeleportDest mDoor;
|
||||||
|
|
||||||
|
Reference();
|
||||||
|
virtual ~Reference();
|
||||||
|
|
||||||
|
virtual void load(ESM4::Reader& reader);
|
||||||
|
//virtual void save(ESM4::Writer& writer) const;
|
||||||
|
|
||||||
|
void blank();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_REFR_H
|
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
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 "regn.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::Region::Region() : mFormId(0), mFlags(0)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
mShader.clear();
|
||||||
|
mMapName.clear();
|
||||||
|
//mData.unknown = 1; // FIXME: temp use to indicate not loaded
|
||||||
|
mData.resize(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::Region::~Region()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::Region::load(ESM4::Reader& reader)
|
||||||
|
{
|
||||||
|
mFormId = reader.hdr().record.id;
|
||||||
|
reader.adjustFormId(mFormId);
|
||||||
|
mFlags = reader.hdr().record.flags;
|
||||||
|
|
||||||
|
RDAT_Types next = RDAT_None;
|
||||||
|
|
||||||
|
while (reader.getSubRecordHeader())
|
||||||
|
{
|
||||||
|
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||||
|
switch (subHdr.typeId)
|
||||||
|
{
|
||||||
|
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||||
|
case ESM4::SUB_RCLR: reader.get(mColour); break;
|
||||||
|
case ESM4::SUB_WNAM: reader.getFormId(mWorldId); break;
|
||||||
|
case ESM4::SUB_ICON: reader.getZString(mShader); break;
|
||||||
|
case ESM4::SUB_RPLI: reader.get(mEdgeFalloff); break;
|
||||||
|
case ESM4::SUB_RPLD:
|
||||||
|
{
|
||||||
|
mRPLD.resize(subHdr.dataSize/sizeof(std::uint32_t));
|
||||||
|
for (std::vector<std::uint32_t>::iterator it = mRPLD.begin(); it != mRPLD.end(); ++it)
|
||||||
|
{
|
||||||
|
reader.get(*it);
|
||||||
|
#if 0
|
||||||
|
std::string padding = "";
|
||||||
|
padding.insert(0, reader.stackSize()*2, ' ');
|
||||||
|
std::cout << padding << "RPLD: 0x" << std::hex << *it << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_RDAT:
|
||||||
|
{
|
||||||
|
RDAT rdat;
|
||||||
|
reader.get(rdat);
|
||||||
|
|
||||||
|
next = static_cast<RDAT_Types>(rdat.type);
|
||||||
|
|
||||||
|
mData[rdat.type].type = rdat.type;
|
||||||
|
mData[rdat.type].flag = rdat.flag;
|
||||||
|
mData[rdat.type].priority = rdat.priority;
|
||||||
|
mData[rdat.type].unknown = rdat.unknown;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_RDMP:
|
||||||
|
{
|
||||||
|
assert(next == RDAT_Map && "REGN unexpected data type");
|
||||||
|
next = RDAT_None;
|
||||||
|
|
||||||
|
if (reader.hasLocalizedStrings())
|
||||||
|
reader.getLocalizedString(mMapName);
|
||||||
|
else if (!reader.getZString(mMapName))
|
||||||
|
throw std::runtime_error ("REGN RDMP data read error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_RDMD: // Only in Oblivion?
|
||||||
|
case ESM4::SUB_RDSD: // Only in Oblivion? Possibly the same as RDSA // formId
|
||||||
|
case ESM4::SUB_RDGS: // Only in Oblivion? (ToddTestRegion1) // formId
|
||||||
|
case ESM4::SUB_RDMO:
|
||||||
|
case ESM4::SUB_RDSA:
|
||||||
|
case ESM4::SUB_RDWT: // formId
|
||||||
|
case ESM4::SUB_RDOT: // formId
|
||||||
|
case ESM4::SUB_RDID: // FONV
|
||||||
|
case ESM4::SUB_RDSB: // FONV
|
||||||
|
case ESM4::SUB_RDSI: // FONV
|
||||||
|
{
|
||||||
|
//RDAT skipping... following is a map
|
||||||
|
//RDMP skipping... map name
|
||||||
|
//
|
||||||
|
//RDAT skipping... following is weather
|
||||||
|
//RDWT skipping... weather data
|
||||||
|
//
|
||||||
|
//RDAT skipping... following is sound
|
||||||
|
//RDMD skipping... unknown, maybe music data
|
||||||
|
//
|
||||||
|
//RDSD skipping... unknown, maybe sound data
|
||||||
|
//
|
||||||
|
//RDAT skipping... following is grass
|
||||||
|
//RDGS skipping... unknown, maybe grass
|
||||||
|
|
||||||
|
//std::cout << "REGN " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData(); // FIXME: process the subrecord rather than skip
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::REGN::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::Region::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
void ESM4::Region::blank()
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
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_REGN_H
|
||||||
|
#define ESM4_REGN_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
typedef std::uint32_t FormId;
|
||||||
|
|
||||||
|
struct Region
|
||||||
|
{
|
||||||
|
enum RDAT_Types
|
||||||
|
{
|
||||||
|
RDAT_None = 0x00,
|
||||||
|
RDAT_Objects = 0x02,
|
||||||
|
RDAT_Weather = 0x03,
|
||||||
|
RDAT_Map = 0x04,
|
||||||
|
RDAT_Landscape = 0x05,
|
||||||
|
RDAT_Grass = 0x06,
|
||||||
|
RDAT_Sound = 0x07
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RDAT
|
||||||
|
{
|
||||||
|
std::uint32_t type;
|
||||||
|
std::uint8_t flag;
|
||||||
|
std::uint8_t priority;
|
||||||
|
std::uint16_t unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
FormId mFormId; // from the header
|
||||||
|
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||||
|
|
||||||
|
std::string mEditorId;
|
||||||
|
std::uint32_t mColour; // RGBA
|
||||||
|
FormId mWorldId; // worldspace formid
|
||||||
|
|
||||||
|
std::string mShader; //?? ICON
|
||||||
|
std::string mMapName;
|
||||||
|
std::uint32_t mEdgeFalloff;
|
||||||
|
std::vector<std::uint32_t> mRPLD; // unknown
|
||||||
|
std::vector<RDAT> mData; // indexed by the type value
|
||||||
|
|
||||||
|
Region();
|
||||||
|
virtual ~Region();
|
||||||
|
|
||||||
|
virtual void load(ESM4::Reader& reader);
|
||||||
|
//virtual void save(ESM4::Writer& writer) const;
|
||||||
|
|
||||||
|
void blank();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_REGN_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 "sbsp.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
ESM4::Subspace::Subspace() : mFormId(0), mFlags(0)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
|
||||||
|
mDimension.x = 0.f;
|
||||||
|
mDimension.y = 0.f;
|
||||||
|
mDimension.z = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::Subspace::~Subspace()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::Subspace::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.get(mDimension.x);
|
||||||
|
reader.get(mDimension.y);
|
||||||
|
reader.get(mDimension.z);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::SBSP::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::Subspace::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void ESM4::Subspace::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_SBSP_H
|
||||||
|
#define ESM4_SBSP_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
typedef std::uint32_t FormId;
|
||||||
|
|
||||||
|
struct Subspace
|
||||||
|
{
|
||||||
|
struct Dimension
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
};
|
||||||
|
|
||||||
|
FormId mFormId; // from the header
|
||||||
|
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||||
|
|
||||||
|
std::string mEditorId;
|
||||||
|
Dimension mDimension;
|
||||||
|
|
||||||
|
Subspace();
|
||||||
|
virtual ~Subspace();
|
||||||
|
|
||||||
|
virtual void load(Reader& reader);
|
||||||
|
//virtual void save(Writer& writer) const;
|
||||||
|
|
||||||
|
//void blank();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_SBSP_H
|
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
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 "sgst.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
ESM4::SigilStone::SigilStone() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
mFullName.clear();
|
||||||
|
mModel.clear();
|
||||||
|
mIcon.clear();
|
||||||
|
|
||||||
|
mData.uses = 0;
|
||||||
|
mData.value = 0;
|
||||||
|
mData.weight = 0.f;
|
||||||
|
|
||||||
|
std::memset(&mEffect, 0, sizeof(ScriptEffect));
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::SigilStone::~SigilStone()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::SigilStone::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.getZString(mFullName))
|
||||||
|
throw std::runtime_error ("SGST FULL data read error");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FIXME: should be part of a struct?
|
||||||
|
std::string scriptEffectName;
|
||||||
|
if (!reader.getZString(scriptEffectName))
|
||||||
|
throw std::runtime_error ("SGST FULL data read error");
|
||||||
|
mScriptEffect.push_back(scriptEffectName);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_DATA:
|
||||||
|
{
|
||||||
|
reader.get(mData.uses);
|
||||||
|
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_MODB: reader.get(mBoundRadius); break;
|
||||||
|
case ESM4::SUB_SCIT:
|
||||||
|
{
|
||||||
|
reader.get(mEffect);
|
||||||
|
reader.adjustFormId(mEffect.formId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_MODT:
|
||||||
|
case ESM4::SUB_EFID:
|
||||||
|
case ESM4::SUB_EFIT:
|
||||||
|
{
|
||||||
|
//std::cout << "SGST " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::SGST::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::SigilStone::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void ESM4::SigilStone::blank()
|
||||||
|
//{
|
||||||
|
//}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
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_SGST_H
|
||||||
|
#define ESM4_SGST_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
|
||||||
|
struct SigilStone
|
||||||
|
{
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
std::uint8_t uses;
|
||||||
|
std::uint32_t value; // gold
|
||||||
|
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;
|
||||||
|
std::string mIcon; // inventory
|
||||||
|
|
||||||
|
float mBoundRadius;
|
||||||
|
|
||||||
|
std::vector<std::string> mScriptEffect; // FIXME: prob. should be in a struct
|
||||||
|
FormId mScript;
|
||||||
|
ScriptEffect mEffect;
|
||||||
|
|
||||||
|
Data mData;
|
||||||
|
|
||||||
|
SigilStone();
|
||||||
|
virtual ~SigilStone();
|
||||||
|
|
||||||
|
virtual void load(ESM4::Reader& reader);
|
||||||
|
//virtual void save(ESM4::Writer& writer) const;
|
||||||
|
|
||||||
|
//void blank();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_SGST_H
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
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 "slgm.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
ESM4::SoulGem::SoulGem() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0), mSoul(0), mSoulCapacity(0)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
mFullName.clear();
|
||||||
|
mModel.clear();
|
||||||
|
mIcon.clear();
|
||||||
|
|
||||||
|
mData.value = 0;
|
||||||
|
mData.weight = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::SoulGem::~SoulGem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::SoulGem::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 ("SLGM 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_SOUL: reader.get(mSoul); break;
|
||||||
|
case ESM4::SUB_SLCP: reader.get(mSoulCapacity); break;
|
||||||
|
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||||
|
case ESM4::SUB_MODT:
|
||||||
|
case ESM4::SUB_KSIZ:
|
||||||
|
case ESM4::SUB_KWDA:
|
||||||
|
case ESM4::SUB_NAM0:
|
||||||
|
case ESM4::SUB_OBND:
|
||||||
|
{
|
||||||
|
//std::cout << "SLGM " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::SLGM::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::SoulGem::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void ESM4::SoulGem::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_SLGM_H
|
||||||
|
#define ESM4_SLGM_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
typedef std::uint32_t FormId;
|
||||||
|
|
||||||
|
struct SoulGem
|
||||||
|
{
|
||||||
|
#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;
|
||||||
|
std::uint8_t mSoul; // 0 = None, 1 = Petty, 2 = Lesser, 3 = Common, 4 = Greater, 5 = Grand
|
||||||
|
std::uint8_t mSoulCapacity; // 0 = None, 1 = Petty, 2 = Lesser, 3 = Common, 4 = Greater, 5 = Grand
|
||||||
|
|
||||||
|
Data mData;
|
||||||
|
|
||||||
|
SoulGem();
|
||||||
|
virtual ~SoulGem();
|
||||||
|
|
||||||
|
virtual void load(ESM4::Reader& reader);
|
||||||
|
//virtual void save(ESM4::Writer& writer) const;
|
||||||
|
|
||||||
|
//void blank();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_SLGM_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 "soun.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
ESM4::Sound::Sound() : mFormId(0), mFlags(0)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
mSoundFile.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::Sound::~Sound()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::Sound::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_FNAM: reader.getZString(mSoundFile); break;
|
||||||
|
case ESM4::SUB_SNDX: reader.get(mData); break;
|
||||||
|
case ESM4::SUB_SNDD:
|
||||||
|
case ESM4::SUB_OBND: // TES5 only
|
||||||
|
case ESM4::SUB_SDSC: // TES5 only
|
||||||
|
case ESM4::SUB_ANAM: // FO3
|
||||||
|
case ESM4::SUB_GNAM: // FO3
|
||||||
|
case ESM4::SUB_HNAM: // FO3
|
||||||
|
case ESM4::SUB_RNAM: // FONV
|
||||||
|
{
|
||||||
|
//std::cout << "SOUN " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::SOUN::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::Sound::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void ESM4::Sound::blank()
|
||||||
|
//{
|
||||||
|
//}
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
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_SOUN_H
|
||||||
|
#define ESM4_SOUN_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
typedef std::uint32_t FormId;
|
||||||
|
|
||||||
|
struct Sound
|
||||||
|
{
|
||||||
|
enum Flags
|
||||||
|
{
|
||||||
|
Flags_RandomFreqShift = 0x0001,
|
||||||
|
Flags_PlayAtRandom = 0x0002,
|
||||||
|
Flags_EnvIgnored = 0x0004,
|
||||||
|
Flags_RandomLocation = 0x0008,
|
||||||
|
Flags_Loop = 0x0010,
|
||||||
|
Flags_MenuSound = 0x0020,
|
||||||
|
Flags_2D = 0x0040,
|
||||||
|
Flags_360LFE = 0x0080
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct SNDX
|
||||||
|
{
|
||||||
|
std::uint8_t minAttenuation;
|
||||||
|
std::uint8_t maxAttenuation;
|
||||||
|
std::int8_t freqAdjustment; // %, signed
|
||||||
|
std::uint8_t unknown;
|
||||||
|
std::uint16_t flags;
|
||||||
|
std::uint16_t unknown2;
|
||||||
|
std::uint16_t staticAttenuation; // divide by 100 to get value in dB
|
||||||
|
std::uint8_t stopTime; // multipy vy 1440/256 to get value in minutes
|
||||||
|
std::uint8_t startTime; // multipy vy 1440/256 to get value in minutes
|
||||||
|
};
|
||||||
|
#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 mSoundFile;
|
||||||
|
SNDX mData;
|
||||||
|
|
||||||
|
Sound();
|
||||||
|
virtual ~Sound();
|
||||||
|
|
||||||
|
virtual void load(ESM4::Reader& reader);
|
||||||
|
//virtual void save(ESM4::Writer& writer) const;
|
||||||
|
|
||||||
|
//void blank();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_SOUN_H
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
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 "stat.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <iostream> // FIXME: debug only
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
ESM4::Static::Static() : mFormId(0), mFlags(0), mBoundRadius(0.f)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
mModel.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::Static::~Static()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::Static::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_MODB: reader.get(mBoundRadius); break;
|
||||||
|
case ESM4::SUB_MODT:
|
||||||
|
{
|
||||||
|
// version is only availabe in TES5 (seems to be 27 or 28?)
|
||||||
|
//if (reader.esmVersion() == ESM4::VER_094 || reader.esmVersion() == ESM4::VER_170)
|
||||||
|
//std::cout << "STAT MODT ver: " << std::hex << reader.hdr().record.version << std::endl;
|
||||||
|
|
||||||
|
// for TES4 these are just a sequence of bytes
|
||||||
|
mMODT.resize(subHdr.dataSize/sizeof(std::uint8_t));
|
||||||
|
for (std::vector<std::uint8_t>::iterator it = mMODT.begin(); it != mMODT.end(); ++it)
|
||||||
|
{
|
||||||
|
reader.get(*it);
|
||||||
|
#if 0
|
||||||
|
std::string padding = "";
|
||||||
|
padding.insert(0, reader.stackSize()*2, ' ');
|
||||||
|
std::cout << padding << "MODT: " << std::hex << *it << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_MODS:
|
||||||
|
case ESM4::SUB_OBND:
|
||||||
|
case ESM4::SUB_DNAM:
|
||||||
|
case ESM4::SUB_MNAM:
|
||||||
|
case ESM4::SUB_BRUS: // FONV
|
||||||
|
case ESM4::SUB_RNAM: // FONV
|
||||||
|
{
|
||||||
|
//std::cout << "STAT " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::STAT::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::Static::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void ESM4::Static::blank()
|
||||||
|
//{
|
||||||
|
//}
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
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_STAT_H
|
||||||
|
#define ESM4_STAT_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
typedef std::uint32_t FormId;
|
||||||
|
|
||||||
|
// Unlike TES3, multiple cells can have the same exterior co-ordinates.
|
||||||
|
// The cells need to be organised under world spaces.
|
||||||
|
struct Static
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
std::vector<std::uint8_t> mMODT; // FIXME texture hash
|
||||||
|
|
||||||
|
Static();
|
||||||
|
virtual ~Static();
|
||||||
|
|
||||||
|
virtual void load(ESM4::Reader& reader);
|
||||||
|
//virtual void save(ESM4::Writer& writer) const;
|
||||||
|
|
||||||
|
//void blank();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_STAT_H
|
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
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 "tes4.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <iostream> // FIXME: debugging only
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
#include "formid.hpp"
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
#ifdef NDEBUG // FIXME: debuggigng only
|
||||||
|
#undef NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ESM4::Header::load(ESM4::Reader& reader)
|
||||||
|
{
|
||||||
|
mFlags = reader.hdr().record.flags; // 0x01 = Rec_ESM, 0x80 = Rec_Localized
|
||||||
|
|
||||||
|
while (reader.getSubRecordHeader())
|
||||||
|
{
|
||||||
|
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||||
|
switch (subHdr.typeId)
|
||||||
|
{
|
||||||
|
case ESM4::SUB_HEDR:
|
||||||
|
{
|
||||||
|
if (!reader.get(mData.version) || !reader.get(mData.records) || !reader.get(mData.nextObjectId))
|
||||||
|
throw std::runtime_error("TES4 HEDR data read error");
|
||||||
|
|
||||||
|
assert((size_t)subHdr.dataSize == sizeof(mData.version)+sizeof(mData.records)+sizeof(mData.nextObjectId)
|
||||||
|
&& "TES4 HEDR data size mismatch");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_CNAM:
|
||||||
|
{
|
||||||
|
if (!reader.getZString(mAuthor))
|
||||||
|
throw std::runtime_error("TES4 CNAM data read error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_SNAM:
|
||||||
|
{
|
||||||
|
if (!reader.getZString(mDesc))
|
||||||
|
throw std::runtime_error("TES4 SNAM data read error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_MAST: // multiple
|
||||||
|
{
|
||||||
|
MasterData m;
|
||||||
|
if (!reader.getZString(m.name))
|
||||||
|
throw std::runtime_error("TES4 MAST data read error");
|
||||||
|
|
||||||
|
// NOTE: some mods do not have DATA following MAST so can't read DATA here
|
||||||
|
|
||||||
|
mMaster.push_back (m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_DATA:
|
||||||
|
{
|
||||||
|
// WARNING: assumes DATA always follows MAST
|
||||||
|
if (!reader.get(mMaster.back().size))
|
||||||
|
throw std::runtime_error("TES4 DATA data read error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_ONAM:
|
||||||
|
{
|
||||||
|
mOverrides.resize(subHdr.dataSize/sizeof(FormId));
|
||||||
|
for (std::vector<FormId>::iterator it = mOverrides.begin(); it != mOverrides.end(); ++it)
|
||||||
|
{
|
||||||
|
if (!reader.get(*it))
|
||||||
|
throw std::runtime_error("TES4 ONAM data read error");
|
||||||
|
#if 0
|
||||||
|
std::string padding = "";
|
||||||
|
padding.insert(0, reader.stackSize()*2, ' ');
|
||||||
|
std::cout << padding << "ESM4::Header::ONAM overrides: " << formIdToString(*it) << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_INTV:
|
||||||
|
case ESM4::SUB_INCC:
|
||||||
|
case ESM4::SUB_OFST: // Oblivion only?
|
||||||
|
case ESM4::SUB_DELE: // Oblivion only?
|
||||||
|
{
|
||||||
|
//std::cout << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::Header::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::Header::save(ESM4::Writer& writer)
|
||||||
|
//{
|
||||||
|
//}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
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_TES4_H
|
||||||
|
#define ESM4_TES4_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
typedef std::uint32_t FormId;
|
||||||
|
|
||||||
|
struct Header
|
||||||
|
{
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
union ESMVersion
|
||||||
|
{
|
||||||
|
float f;
|
||||||
|
unsigned int ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
// The supported versions are 0.80 = 0x3f800000, 0.94 = 0x3f70a3d7 and 1.7 = 0x3fd9999a
|
||||||
|
// (also 1.34 = 0x3fab851f eventually)
|
||||||
|
ESMVersion version; // File format version.
|
||||||
|
std::int32_t records; // Number of records
|
||||||
|
std::uint32_t nextObjectId;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
// Defines another files (esm or esp) that this file depends upon.
|
||||||
|
struct MasterData
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::uint64_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::uint32_t mFlags; // 0x01 esm, 0x80 localised strings
|
||||||
|
|
||||||
|
Data mData;
|
||||||
|
std::string mAuthor; // Author's name
|
||||||
|
std::string mDesc; // File description
|
||||||
|
std::vector<MasterData> mMaster;
|
||||||
|
|
||||||
|
std::vector<FormId> mOverrides; // Skyrim only, cell children (ACHR, LAND, NAVM, PGRE, PHZD, REFR)
|
||||||
|
|
||||||
|
// position in the vector = mod index of master files above
|
||||||
|
// value = adjusted mod index based on all the files loaded so far
|
||||||
|
std::vector<std::uint32_t> mModIndicies;
|
||||||
|
|
||||||
|
void load (Reader& reader);
|
||||||
|
//void save (Writer& writer);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_TES4_H
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
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 "tree.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
ESM4::Tree::Tree() : mFormId(0), mFlags(0), mBoundRadius(0.f)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
mModel.clear();
|
||||||
|
mLeafTexture.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::Tree::~Tree()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::Tree::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_ICON: reader.getZString(mLeafTexture); break;
|
||||||
|
case ESM4::SUB_MODB: reader.get(mBoundRadius); break;
|
||||||
|
case ESM4::SUB_MODT:
|
||||||
|
case ESM4::SUB_CNAM:
|
||||||
|
case ESM4::SUB_BNAM:
|
||||||
|
case ESM4::SUB_SNAM:
|
||||||
|
case ESM4::SUB_FULL:
|
||||||
|
case ESM4::SUB_OBND:
|
||||||
|
case ESM4::SUB_PFIG:
|
||||||
|
case ESM4::SUB_PFPC:
|
||||||
|
{
|
||||||
|
//std::cout << "TREE " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::TREE::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::Tree::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void ESM4::Tree::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_TREE_H
|
||||||
|
#define ESM4_TREE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
typedef std::uint32_t FormId;
|
||||||
|
|
||||||
|
struct Tree
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::string mLeafTexture;
|
||||||
|
|
||||||
|
Tree();
|
||||||
|
virtual ~Tree();
|
||||||
|
|
||||||
|
virtual void load(ESM4::Reader& reader);
|
||||||
|
//virtual void save(ESM4::Writer& writer) const;
|
||||||
|
|
||||||
|
//void blank();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_TREE_H
|
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
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 "weap.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
ESM4::Weapon::Weapon() : mFormId(0), mFlags(0), mBoundRadius(0.f), mScript(0),
|
||||||
|
mEnchantmentPoints(0), mEnchantment(0)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
mFullName.clear();
|
||||||
|
mModel.clear();
|
||||||
|
mIcon.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::Weapon::~Weapon()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::Weapon::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 ("WEAP FULL data read error");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_DATA:
|
||||||
|
{
|
||||||
|
//if (reader.esmVersion() == ESM4::VER_094 || reader.esmVersion() == ESM4::VER_170)
|
||||||
|
if (subHdr.dataSize == 10) // FO3 has 15 bytes even though VER_094
|
||||||
|
{
|
||||||
|
reader.get(mData.value);
|
||||||
|
reader.get(mData.weight);
|
||||||
|
reader.get(mData.damage);
|
||||||
|
}
|
||||||
|
else if (isFONV || subHdr.dataSize == 15)
|
||||||
|
{
|
||||||
|
reader.get(mData.value);
|
||||||
|
reader.get(mData.health);
|
||||||
|
reader.get(mData.weight);
|
||||||
|
reader.get(mData.damage);
|
||||||
|
reader.get(mData.clipSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reader.get(mData.type);
|
||||||
|
reader.get(mData.speed);
|
||||||
|
reader.get(mData.reach);
|
||||||
|
reader.get(mData.flags);
|
||||||
|
reader.get(mData.value);
|
||||||
|
reader.get(mData.health);
|
||||||
|
reader.get(mData.weight);
|
||||||
|
reader.get(mData.damage);
|
||||||
|
}
|
||||||
|
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_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_BAMT:
|
||||||
|
case ESM4::SUB_BIDS:
|
||||||
|
case ESM4::SUB_INAM:
|
||||||
|
case ESM4::SUB_CNAM:
|
||||||
|
case ESM4::SUB_CRDT:
|
||||||
|
case ESM4::SUB_DESC:
|
||||||
|
case ESM4::SUB_DNAM:
|
||||||
|
case ESM4::SUB_EAMT:
|
||||||
|
case ESM4::SUB_EITM:
|
||||||
|
case ESM4::SUB_ETYP:
|
||||||
|
case ESM4::SUB_KSIZ:
|
||||||
|
case ESM4::SUB_KWDA:
|
||||||
|
case ESM4::SUB_NAM8:
|
||||||
|
case ESM4::SUB_NAM9:
|
||||||
|
case ESM4::SUB_OBND:
|
||||||
|
case ESM4::SUB_SNAM:
|
||||||
|
case ESM4::SUB_TNAM:
|
||||||
|
case ESM4::SUB_UNAM:
|
||||||
|
case ESM4::SUB_VMAD:
|
||||||
|
case ESM4::SUB_VNAM:
|
||||||
|
case ESM4::SUB_WNAM:
|
||||||
|
case ESM4::SUB_XNAM: // Dawnguard only?
|
||||||
|
case ESM4::SUB_NNAM:
|
||||||
|
case ESM4::SUB_MODS:
|
||||||
|
case ESM4::SUB_NAM0: // FO3
|
||||||
|
case ESM4::SUB_MICO: // FO3
|
||||||
|
case ESM4::SUB_REPL: // FO3
|
||||||
|
case ESM4::SUB_YNAM: // FO3
|
||||||
|
case ESM4::SUB_ZNAM: // FO3
|
||||||
|
case ESM4::SUB_MOD2: // FO3
|
||||||
|
case ESM4::SUB_MO2T: // FO3
|
||||||
|
case ESM4::SUB_MO2S: // FO3
|
||||||
|
case ESM4::SUB_NAM6: // FO3
|
||||||
|
case ESM4::SUB_MOD4: // FO3
|
||||||
|
case ESM4::SUB_MO4T: // FO3
|
||||||
|
case ESM4::SUB_MO4S: // FO3
|
||||||
|
case ESM4::SUB_BIPL: // FO3
|
||||||
|
case ESM4::SUB_NAM7: // FO3
|
||||||
|
case ESM4::SUB_MOD3: // FO3
|
||||||
|
case ESM4::SUB_MO3T: // FO3
|
||||||
|
case ESM4::SUB_MO3S: // FO3
|
||||||
|
case ESM4::SUB_MODD: // FO3
|
||||||
|
//case ESM4::SUB_MOSD: // 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_VATS: // FONV
|
||||||
|
case ESM4::SUB_VANM: // FONV
|
||||||
|
case ESM4::SUB_MWD1: // FONV
|
||||||
|
case ESM4::SUB_MWD2: // FONV
|
||||||
|
case ESM4::SUB_MWD3: // FONV
|
||||||
|
case ESM4::SUB_MWD4: // FONV
|
||||||
|
case ESM4::SUB_MWD5: // FONV
|
||||||
|
case ESM4::SUB_MWD6: // FONV
|
||||||
|
case ESM4::SUB_MWD7: // FONV
|
||||||
|
case ESM4::SUB_WMI1: // FONV
|
||||||
|
case ESM4::SUB_WMI2: // FONV
|
||||||
|
case ESM4::SUB_WMI3: // FONV
|
||||||
|
case ESM4::SUB_WMS1: // FONV
|
||||||
|
case ESM4::SUB_WMS2: // FONV
|
||||||
|
case ESM4::SUB_WNM1: // FONV
|
||||||
|
case ESM4::SUB_WNM2: // FONV
|
||||||
|
case ESM4::SUB_WNM3: // FONV
|
||||||
|
case ESM4::SUB_WNM4: // FONV
|
||||||
|
case ESM4::SUB_WNM5: // FONV
|
||||||
|
case ESM4::SUB_WNM6: // FONV
|
||||||
|
case ESM4::SUB_WNM7: // FONV
|
||||||
|
case MKTAG('E','F','S','D'): // FONV DeadMoney
|
||||||
|
{
|
||||||
|
//std::cout << "WEAP " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::WEAP::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::Weapon::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void ESM4::Weapon::blank()
|
||||||
|
//{
|
||||||
|
//}
|
@ -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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef ESM4_WEAP_H
|
||||||
|
#define ESM4_WEAP_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
typedef std::uint32_t FormId;
|
||||||
|
|
||||||
|
struct Weapon
|
||||||
|
{
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
std::uint32_t type;
|
||||||
|
float speed;
|
||||||
|
float reach;
|
||||||
|
std::uint32_t flags;
|
||||||
|
std::uint32_t value; // gold
|
||||||
|
std::uint32_t health;
|
||||||
|
float weight;
|
||||||
|
std::uint16_t damage;
|
||||||
|
std::uint8_t clipSize; // FO3/FONV only
|
||||||
|
|
||||||
|
Data() : type(0), speed(0.f), reach(0.f), flags(0), value(0),
|
||||||
|
health(0), weight(0.f), damage(0), clipSize(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;
|
||||||
|
|
||||||
|
float mBoundRadius;
|
||||||
|
|
||||||
|
FormId mScript;
|
||||||
|
std::uint16_t mEnchantmentPoints;
|
||||||
|
FormId mEnchantment;
|
||||||
|
|
||||||
|
Data mData;
|
||||||
|
|
||||||
|
Weapon();
|
||||||
|
virtual ~Weapon();
|
||||||
|
|
||||||
|
virtual void load(ESM4::Reader& reader);
|
||||||
|
//virtual void save(ESM4::Writer& writer) const;
|
||||||
|
|
||||||
|
//void blank();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_WEAP_H
|
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
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 "wrld.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <iostream> // FIXME: debug only
|
||||||
|
|
||||||
|
#include "reader.hpp"
|
||||||
|
//#include "writer.hpp"
|
||||||
|
|
||||||
|
ESM4::World::World() : mFormId(0), mFlags(0), mParent(0), mWorldFlags(0), mClimate(0), mWater(0),
|
||||||
|
mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mSound(0)
|
||||||
|
{
|
||||||
|
mEditorId.clear();
|
||||||
|
mFullName.clear();
|
||||||
|
mMapFile.clear();
|
||||||
|
|
||||||
|
mMap.width = 0;
|
||||||
|
mMap.height = 0;
|
||||||
|
mMap.NWcellX = 0;
|
||||||
|
mMap.NWcellY = 0;
|
||||||
|
mMap.SEcellX = 0;
|
||||||
|
mMap.SEcellY = 0;
|
||||||
|
mMap.minHeight = 0.f;
|
||||||
|
mMap.maxHeight = 0.f;
|
||||||
|
mMap.initialPitch = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM4::World::~World()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4::World::load(ESM4::Reader& reader)
|
||||||
|
{
|
||||||
|
mFormId = reader.hdr().record.id;
|
||||||
|
reader.adjustFormId(mFormId);
|
||||||
|
mFlags = reader.hdr().record.flags;
|
||||||
|
|
||||||
|
// It should be possible to save the current world formId automatically while reading in
|
||||||
|
// the record header rather than doing it manually here but possibly less efficient (may
|
||||||
|
// need to check each record?).
|
||||||
|
//
|
||||||
|
// Alternatively it may be possible to figure it out by examining the group headers, but
|
||||||
|
// apparently the label field is not reliable so the parent world formid may have been
|
||||||
|
// corrupted by the use of ignore flag (TODO: should check to verify).
|
||||||
|
reader.setCurrWorld(mFormId); // save for CELL later
|
||||||
|
|
||||||
|
std::uint32_t subSize = 0; // for XXXX sub record
|
||||||
|
|
||||||
|
while (reader.getSubRecordHeader())
|
||||||
|
{
|
||||||
|
const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader();
|
||||||
|
switch (subHdr.typeId)
|
||||||
|
{
|
||||||
|
case ESM4::SUB_EDID: reader.getZString(mEditorId); break;
|
||||||
|
case ESM4::SUB_FULL: // Name of the worldspace
|
||||||
|
{
|
||||||
|
if (reader.hasLocalizedStrings())
|
||||||
|
reader.getLocalizedString(mFullName);
|
||||||
|
else if (!reader.getZString(mFullName))
|
||||||
|
throw std::runtime_error ("WRLD FULL data read error");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_WCTR: reader.get(mCenterCell); break; // Center cell, TES5 only
|
||||||
|
case ESM4::SUB_WNAM: reader.getFormId(mParent); break;
|
||||||
|
case ESM4::SUB_SNAM: reader.get(mSound); break; // sound, Oblivion only?
|
||||||
|
case ESM4::SUB_ICON: reader.getZString(mMapFile); break; // map filename, Oblivion only?
|
||||||
|
case ESM4::SUB_CNAM: reader.get(mClimate); break;
|
||||||
|
case ESM4::SUB_NAM2: reader.getFormId(mWater); break;
|
||||||
|
case ESM4::SUB_NAM0:
|
||||||
|
{
|
||||||
|
reader.get(mMinX);
|
||||||
|
reader.get(mMinY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_NAM9:
|
||||||
|
{
|
||||||
|
reader.get(mMaxX);
|
||||||
|
reader.get(mMaxY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_DATA: reader.get(mWorldFlags); break;
|
||||||
|
case ESM4::SUB_MNAM:
|
||||||
|
{
|
||||||
|
reader.get(mMap.width);
|
||||||
|
reader.get(mMap.height);
|
||||||
|
reader.get(mMap.NWcellX);
|
||||||
|
reader.get(mMap.NWcellY);
|
||||||
|
reader.get(mMap.SEcellX);
|
||||||
|
reader.get(mMap.SEcellY);
|
||||||
|
|
||||||
|
if (subHdr.dataSize == 28) // Skyrim?
|
||||||
|
{
|
||||||
|
reader.get(mMap.minHeight);
|
||||||
|
reader.get(mMap.maxHeight);
|
||||||
|
reader.get(mMap.initialPitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_RNAM: // multiple
|
||||||
|
case ESM4::SUB_MHDT:
|
||||||
|
case ESM4::SUB_LTMP:
|
||||||
|
case ESM4::SUB_XEZN:
|
||||||
|
case ESM4::SUB_XLCN:
|
||||||
|
case ESM4::SUB_NAM3:
|
||||||
|
case ESM4::SUB_NAM4:
|
||||||
|
case ESM4::SUB_DNAM:
|
||||||
|
case ESM4::SUB_MODL:
|
||||||
|
case ESM4::SUB_NAMA:
|
||||||
|
case ESM4::SUB_PNAM:
|
||||||
|
case ESM4::SUB_ONAM:
|
||||||
|
case ESM4::SUB_TNAM:
|
||||||
|
case ESM4::SUB_UNAM:
|
||||||
|
case ESM4::SUB_ZNAM:
|
||||||
|
case ESM4::SUB_XWEM:
|
||||||
|
case ESM4::SUB_MODT: // from Dragonborn onwards?
|
||||||
|
case ESM4::SUB_INAM: // FO3
|
||||||
|
case ESM4::SUB_NNAM: // FO3
|
||||||
|
case ESM4::SUB_XNAM: // FO3
|
||||||
|
case ESM4::SUB_IMPS: // FO3 Anchorage
|
||||||
|
case ESM4::SUB_IMPF: // FO3 Anchorage
|
||||||
|
{
|
||||||
|
//std::cout << "WRLD " << ESM4::printName(subHdr.typeId) << " skipping..." << std::endl;
|
||||||
|
reader.skipSubRecordData(); // FIXME: process the subrecord rather than skip
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_OFST:
|
||||||
|
{
|
||||||
|
if (subSize)
|
||||||
|
{
|
||||||
|
reader.skipSubRecordData(subSize); // special post XXXX
|
||||||
|
reader.updateRecordRemaining(subSize); // WARNING: manually update
|
||||||
|
subSize = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reader.skipSubRecordData(); // FIXME: process the subrecord rather than skip
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM4::SUB_XXXX:
|
||||||
|
{
|
||||||
|
reader.get(subSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("ESM4::WRLD::load - Unknown subrecord " + ESM4::printName(subHdr.typeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//void ESM4::World::save(ESM4::Writer& writer) const
|
||||||
|
//{
|
||||||
|
//}
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
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_WRLD_H
|
||||||
|
#define ESM4_WRLD_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
namespace ESM4
|
||||||
|
{
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
|
||||||
|
struct World
|
||||||
|
{
|
||||||
|
enum WorldFlags // TES4 TES5
|
||||||
|
{ // -------------------- -----------------
|
||||||
|
WLD_Small = 0x01, // Small World Small World
|
||||||
|
WLD_NoFastTravel = 0x02, // Can't Fast Travel Can't Fast Travel
|
||||||
|
WLD_Oblivion = 0x04, // Oblivion worldspace
|
||||||
|
WLD_NoLODWater = 0x08, // No LOD Water
|
||||||
|
WLD_NoLandscpe = 0x10, // No LOD Water No Landscape
|
||||||
|
WLD_NoSky = 0x20, // No Sky
|
||||||
|
wLD_FixedDimension = 0x40, // Fixed Dimensions
|
||||||
|
WLD_NoGrass = 0x80 // No Grass
|
||||||
|
};
|
||||||
|
|
||||||
|
struct REFRcoord
|
||||||
|
{
|
||||||
|
FormId formId;
|
||||||
|
std::int16_t unknown1;
|
||||||
|
std::int16_t unknown2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RNAMstruct
|
||||||
|
{
|
||||||
|
std::int16_t unknown1;
|
||||||
|
std::int16_t unknown2;
|
||||||
|
std::vector<REFRcoord> refrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Map size struct 16 or 28 byte structure
|
||||||
|
struct Map
|
||||||
|
{
|
||||||
|
std::uint32_t width; // usable width of the map
|
||||||
|
std::uint32_t height; // usable height of the map
|
||||||
|
std::int16_t NWcellX;
|
||||||
|
std::int16_t NWcellY;
|
||||||
|
std::int16_t SEcellX;
|
||||||
|
std::int16_t SEcellY;
|
||||||
|
float minHeight; // Camera Data (default 50000), new as of Skyrim 1.8, purpose is not yet known.
|
||||||
|
float maxHeight; // Camera Data (default 80000)
|
||||||
|
float initialPitch;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 mParent; // parent worldspace formid
|
||||||
|
std::uint8_t mWorldFlags;
|
||||||
|
FormId mClimate;
|
||||||
|
FormId mWater;
|
||||||
|
|
||||||
|
Map mMap;
|
||||||
|
|
||||||
|
std::int32_t mMinX;
|
||||||
|
std::int32_t mMinY;
|
||||||
|
std::int32_t mMaxX;
|
||||||
|
std::int32_t mMaxY;
|
||||||
|
|
||||||
|
// ------ TES4 only -----
|
||||||
|
|
||||||
|
std::int32_t mSound; // 0 = no record, 1 = Public, 2 = Dungeon
|
||||||
|
std::string mMapFile;
|
||||||
|
|
||||||
|
// ------ TES5 only -----
|
||||||
|
|
||||||
|
Grid mCenterCell;
|
||||||
|
RNAMstruct mData;
|
||||||
|
|
||||||
|
// ----------------------
|
||||||
|
|
||||||
|
// cache formId's of children (e.g. CELL, ROAD)
|
||||||
|
std::vector<FormId> mCells;
|
||||||
|
std::vector<FormId> mRoads;
|
||||||
|
|
||||||
|
World();
|
||||||
|
virtual ~World();
|
||||||
|
|
||||||
|
virtual void load(ESM4::Reader& reader);
|
||||||
|
//virtual void save(ESM4::Writer& writer) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESM4_WRLD_H
|
Loading…
Reference in New Issue