Refactored remaining headers in components/esm except defs.hpp.

Removed obsolete *.cpp files.
actorid
Nikolay Kasyanov 14 years ago
parent a2c42ab5a2
commit 1e5768170f

@ -127,10 +127,7 @@ source_group(components\\esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER})
file(GLOB ESM_HEADER ${COMP_DIR}/esm/*.hpp)
set(ESM
${COMP_DIR}/esm/load_impl.cpp
${COMP_DIR}/esm/skill.cpp
${COMP_DIR}/esm/attr.cpp
${COMP_DIR}/esm/class.cpp
${COMP_DIR}/esm/esm_reader.cpp
${COMP_DIR}/esm/loadland.cpp
${COMP_DIR}/esm/loadacti.cpp
@ -143,6 +140,34 @@ set(ESM
${COMP_DIR}/esm/loadcell.cpp
${COMP_DIR}/esm/loadclas.cpp
${COMP_DIR}/esm/loadclot.cpp
${COMP_DIR}/esm/loadcont.cpp
${COMP_DIR}/esm/loadcrea.cpp
${COMP_DIR}/esm/loaddial.cpp
${COMP_DIR}/esm/loaddoor.cpp
${COMP_DIR}/esm/loadench.cpp
${COMP_DIR}/esm/loadfact.cpp
${COMP_DIR}/esm/loadglob.cpp
${COMP_DIR}/esm/loadgmst.cpp
${COMP_DIR}/esm/loadinfo.cpp
${COMP_DIR}/esm/loadingr.cpp
${COMP_DIR}/esm/loadlevlist.cpp
${COMP_DIR}/esm/loadligh.cpp
${COMP_DIR}/esm/loadlocks.cpp
${COMP_DIR}/esm/loadltex.cpp
${COMP_DIR}/esm/loadmgef.cpp
${COMP_DIR}/esm/loadmisc.cpp
${COMP_DIR}/esm/loadnpc.cpp
${COMP_DIR}/esm/loadpgrd.cpp
${COMP_DIR}/esm/loadrace.cpp
${COMP_DIR}/esm/loadregn.cpp
${COMP_DIR}/esm/loadscpt.cpp
${COMP_DIR}/esm/loadskil.cpp
${COMP_DIR}/esm/loadsndg.cpp
${COMP_DIR}/esm/loadsoun.cpp
${COMP_DIR}/esm/loadspel.cpp
${COMP_DIR}/esm/loadsscr.cpp
${COMP_DIR}/esm/loadstat.cpp
${COMP_DIR}/esm/loadweap.cpp
)
source_group(components\\esm FILES ${ESM_HEADER} ${ESM})

@ -1,15 +0,0 @@
#include "loadclas.hpp"
using namespace ESM;
const Class::Specialization Class::specializationIds[3] = {
Class::Combat,
Class::Magic,
Class::Stealth
};
const char *Class::gmstSpecializationIds[3] = {
"sSpecializationCombat",
"sSpecializationMagic",
"sSpecializationStealth"
};

@ -1,175 +0,0 @@
#include "records.hpp"
/** Implementation for some of the load() functions. Most are found in
the header files themselves, but this is a bit irritating to
compile if you're changing the functions often, as virtually the
entire engine depends on these headers.
*/
/*
#include <iostream>
using namespace std;
*/
namespace ESM
{
void NPC::load(ESMReader &esm, const std::string& id)
{
mId = id;
npdt52.gold = -10;
model = esm.getHNOString("MODL");
name = esm.getHNOString("FNAM");
race = esm.getHNString("RNAM");
cls = esm.getHNString("CNAM");
faction = esm.getHNString("ANAM");
head = esm.getHNString("BNAM");
hair = esm.getHNString("KNAM");
script = esm.getHNOString("SCRI");
esm.getSubNameIs("NPDT");
esm.getSubHeader();
if(esm.getSubSize() == 52) esm.getExact(&npdt52, 52);
else if(esm.getSubSize() == 12) esm.getExact(&npdt12, 12);
else esm.fail("NPC_NPDT must be 12 or 52 bytes long");
esm.getHNT(flags, "FLAG");
inventory.load(esm);
spells.load(esm);
if(esm.isNextSub("AIDT"))
{
esm.getHExact(&AI, sizeof(AI));
hasAI = true;
}
else hasAI = false;
esm.skipRecord();
}
void DialInfo::load(ESMReader &esm)
{
id = esm.getHNString("INAM");
prev = esm.getHNString("PNAM");
next = esm.getHNString("NNAM");
// Not present if deleted
if(esm.isNextSub("DATA"))
esm.getHT(data, 12);
// What follows is somewhat spaghetti-ish, but it's worth if for
// an extra speedup. INFO is by far the most common record type.
// subName is a reference to the original, so it changes whenever
// a new sub name is read. esm.isEmptyOrGetName() will get the
// next name for us, or return true if there are no more records.
esm.getSubName();
const NAME &subName = esm.retSubName();
if(subName.val == REC_ONAM)
{
actor = esm.getHString();
if(esm.isEmptyOrGetName()) return;
}
if(subName.val == REC_RNAM)
{
race = esm.getHString();
if(esm.isEmptyOrGetName()) return;
}
if(subName.val == REC_CNAM)
{
clas = esm.getHString();
if(esm.isEmptyOrGetName()) return;
}
factionLess = false;
if(subName.val == REC_FNAM)
{
npcFaction = esm.getHString();
if(npcFaction == "FFFF") factionLess = true;
if(esm.isEmptyOrGetName()) return;
}
if(subName.val == REC_ANAM)
{
cell = esm.getHString();
if(esm.isEmptyOrGetName()) return;
}
if(subName.val == REC_DNAM)
{
pcFaction = esm.getHString();
if(esm.isEmptyOrGetName()) return;
}
if(subName.val == REC_SNAM)
{
sound = esm.getHString();
if(esm.isEmptyOrGetName()) return;
}
if(subName.val == REC_NAME)
{
response = esm.getHString();
if(esm.isEmptyOrGetName()) return;
}
while(subName.val == REC_SCVR)
{
SelectStruct ss;
ss.selectRule = esm.getHString();
esm.isEmptyOrGetName();
if(subName.val == REC_INTV)
{
ss.type = VT_Int;
esm.getHT(ss.i);
}
else if(subName.val == REC_FLTV)
{
ss.type = VT_Float;
esm.getHT(ss.f);
}
else
esm.fail("INFO.SCVR must precede INTV or FLTV, not "
+ subName.toString());
selects.push_back(ss);
if(esm.isEmptyOrGetName()) return;
}
if(subName.val == REC_BNAM)
{
resultScript = esm.getHString();
if(esm.isEmptyOrGetName()) return;
}
questStatus = QS_None;
if (subName.val == REC_QSTN) questStatus = QS_Name;
else if(subName.val == REC_QSTF) questStatus = QS_Finished;
else if(subName.val == REC_QSTR) questStatus = QS_Restart;
else if(subName.val == REC_DELE) questStatus = QS_Deleted;
else
esm.fail("Don't know what to do with " + subName.toString() + " in INFO " + id);
if(questStatus != QS_None)
// Skip rest of record
esm.skipRecord();
}
void Sound::load(ESMReader &esm)
{
sound = esm.getHNString("FNAM");
esm.getHNT(data, "DATA", 3);
/*
cout << "vol=" << (int)data.volume
<< " min=" << (int)data.minRange
<< " max=" << (int)data.maxRange
<< endl;
*/
}
}

@ -3,6 +3,18 @@
namespace ESM
{
const Class::Specialization Class::specializationIds[3] = {
Class::Combat,
Class::Magic,
Class::Stealth
};
const char *Class::gmstSpecializationIds[3] = {
"sSpecializationCombat",
"sSpecializationMagic",
"sSpecializationStealth"
};
void Class::load(ESMReader &esm)
{
name = esm.getHNString("FNAM");

@ -0,0 +1,33 @@
#include "loadcont.hpp"
namespace ESM
{
void InventoryList::load(ESMReader &esm)
{
ContItem ci;
while (esm.isNextSub("NPCO"))
{
esm.getHT(ci, 36);
list.push_back(ci);
}
}
void Container::load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
esm.getHNT(weight, "CNDT", 4);
esm.getHNT(flags, "FLAG", 4);
if (flags & 0xf4)
esm.fail("Unknown flags");
if (!(flags & 0x8))
esm.fail("Flag 8 not set");
script = esm.getHNOString("SCRI");
inventory.load(esm);
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Container definition
@ -11,54 +12,33 @@ namespace ESM {
struct ContItem
{
int count;
NAME32 item;
int count;
NAME32 item;
};
struct InventoryList
{
std::vector<ContItem> list;
std::vector<ContItem> list;
void load(ESMReader &esm)
{
ContItem ci;
while(esm.isNextSub("NPCO"))
{
esm.getHT(ci, 36);
list.push_back(ci);
}
}
void load(ESMReader &esm);
};
struct Container
{
enum Flags
enum Flags
{
Organic = 1, // Objects cannot be placed in this container
Respawn = 2, // Respawns after 4 months
Unknown = 8
Organic = 1, // Objects cannot be placed in this container
Respawn = 2, // Respawns after 4 months
Unknown = 8
};
std::string name, model, script;
float weight; // Not sure, might be max total weight allowed?
int flags;
InventoryList inventory;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
esm.getHNT(weight, "CNDT", 4);
esm.getHNT(flags, "FLAG", 4);
if(flags & 0xf4) esm.fail("Unknown flags");
if(!(flags & 0x8)) esm.fail("Flag 8 not set");
std::string name, model, script;
script = esm.getHNOString("SCRI");
float weight; // Not sure, might be max total weight allowed?
int flags;
InventoryList inventory;
inventory.load(esm);
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,40 @@
#include "loadcrea.hpp"
namespace ESM {
void Creature::load(ESMReader &esm, const std::string& id)
{
mId = id;
model = esm.getHNString("MODL");
original = esm.getHNOString("CNAM");
name = esm.getHNOString("FNAM");
script = esm.getHNOString("SCRI");
esm.getHNT(data, "NPDT", 96);
esm.getHNT(flags, "FLAG");
scale = 1.0;
esm.getHNOT(scale, "XSCL");
inventory.load(esm);
// More subrecords:
// AIDT - data (12 bytes, unknown)
// AI_W - wander (14 bytes, i don't understand it)
// short distance
// byte duration
// byte timeOfDay
// byte idle[10]
//
// Rest is optional:
// AI_T - travel?
// AI_F - follow?
// AI_E - escort?
// AI_A - activate?
esm.skipRecord();
}
}

@ -4,7 +4,8 @@
#include "esm_reader.hpp"
#include "loadcont.hpp"
namespace ESM {
namespace ESM
{
/*
* Creature definition
@ -13,91 +14,53 @@ namespace ESM {
struct Creature
{
// Default is 0x48?
enum Flags
// Default is 0x48?
enum Flags
{
Biped = 0x001,
Respawn = 0x002,
Weapon = 0x004, // Has weapon and shield
None = 0x008, // ??
Swims = 0x010,
Flies = 0x020, // Don't know what happens if several
Walks = 0x040, // of these are set
Essential = 0x080,
Skeleton = 0x400, // Does not have normal blood
Metal = 0x800 // Has 'golden' blood
Biped = 0x001, Respawn = 0x002, Weapon = 0x004, // Has weapon and shield
None = 0x008, // ??
Swims = 0x010,
Flies = 0x020, // Don't know what happens if several
Walks = 0x040, // of these are set
Essential = 0x080,
Skeleton = 0x400, // Does not have normal blood
Metal = 0x800
// Has 'golden' blood
};
enum Type
enum Type
{
Creatures = 0,
Deadra = 1,
Undead = 2,
Humanoid = 3
Creatures = 0, Deadra = 1, Undead = 2, Humanoid = 3
};
struct NPDTstruct
{
int type;
// For creatures we obviously have to use ints, not shorts and
// bytes like we use for NPCs.... this file format just makes so
// much sense! (Still, _much_ easier to decode than the NIFs.)
int level;
int strength, intelligence, willpower, agility, speed, endurance,
personality, luck, health, mana, fatigue; // Stats
int soul; // The creatures soul value (used with soul gems.)
int combat, magic, stealth; // Don't know yet.
int attack[6]; // AttackMin1, AttackMax1, ditto2, ditto3
int gold;
}; // 96 bytes
struct NPDTstruct
{
int type;
// For creatures we obviously have to use ints, not shorts and
// bytes like we use for NPCs.... this file format just makes so
// much sense! (Still, _much_ easier to decode than the NIFs.)
int level;
int strength, intelligence, willpower, agility, speed, endurance,
personality, luck, health, mana, fatigue; // Stats
int soul; // The creatures soul value (used with soul gems.)
int combat, magic, stealth; // Don't know yet.
int attack[6]; // AttackMin1, AttackMax1, ditto2, ditto3
int gold;
}; // 96 bytes
NPDTstruct data;
NPDTstruct data;
int flags;
float scale;
int flags;
float scale;
std::string model, name, script,
original; // Base creature that this is a modification of
std::string model, name, script, original; // Base creature that this is a modification of
// Defined in loadcont.hpp
InventoryList inventory;
// Defined in loadcont.hpp
InventoryList inventory;
std::string mId;
void load(ESMReader &esm, const std::string& id)
{
mId = id;
model = esm.getHNString("MODL");
original = esm.getHNOString("CNAM");
name = esm.getHNOString("FNAM");
script = esm.getHNOString("SCRI");
esm.getHNT(data, "NPDT", 96);
esm.getHNT(flags, "FLAG");
scale = 1.0;
esm.getHNOT(scale, "XSCL");
inventory.load(esm);
// More subrecords:
// AIDT - data (12 bytes, unknown)
// AI_W - wander (14 bytes, i don't understand it)
// short distance
// byte duration
// byte timeOfDay
// byte idle[10]
//
// Rest is optional:
// AI_T - travel?
// AI_F - follow?
// AI_E - escort?
// AI_A - activate?
esm.skipRecord();
}
void load(ESMReader &esm, const std::string& id);
};
}
#endif

@ -0,0 +1,25 @@
#include "loaddial.hpp"
namespace ESM
{
void Dialogue::load(ESMReader &esm)
{
esm.getSubNameIs("DATA");
esm.getSubHeader();
int si = esm.getSubSize();
if (si == 1)
esm.getT(type);
else if (si == 4)
{
// These are just markers, their values are not used.
int i;
esm.getT(i);
esm.getHNT(i, "DELE");
type = Deleted;
}
else
esm.fail("Unknown sub record size");
}
}

@ -6,7 +6,8 @@
#include "esm_reader.hpp"
#include "loadinfo.hpp"
namespace ESM {
namespace ESM
{
/*
* Dialogue topic and journal entries. The actual data is contained in
@ -15,36 +16,20 @@ namespace ESM {
struct Dialogue
{
enum Type
enum Type
{
Topic = 0,
Voice = 1,
Greeting = 2,
Persuasion = 3,
Journal = 4,
Deleted = -1
Topic = 0,
Voice = 1,
Greeting = 2,
Persuasion = 3,
Journal = 4,
Deleted = -1
};
char type;
std::vector<DialInfo> mInfo;
char type;
std::vector<DialInfo> mInfo;
void load(ESMReader &esm)
{
esm.getSubNameIs("DATA");
esm.getSubHeader();
int si = esm.getSubSize();
if(si == 1)
esm.getT(type);
else if(si == 4)
{
// These are just markers, their values are not used.
int i;
esm.getT(i);
esm.getHNT(i,"DELE");
type = Deleted;
}
else esm.fail("Unknown sub record size");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,15 @@
#include "loaddoor.hpp"
namespace ESM
{
void Door::load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
script = esm.getHNOString("SCRI");
openSound = esm.getHNOString("SNAM");
closeSound = esm.getHNOString("ANAM");
}
}

@ -3,20 +3,14 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
struct Door
{
std::string name, model, script, openSound, closeSound;
std::string name, model, script, openSound, closeSound;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
script = esm.getHNOString("SCRI");
openSound = esm.getHNOString("SNAM");
closeSound = esm.getHNOString("ANAM");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,12 @@
#include "loadench.hpp"
namespace ESM
{
void Enchantment::load(ESMReader &esm)
{
esm.getHNT(data, "ENDT", 16);
effects.load(esm);
}
}

@ -2,8 +2,10 @@
#define _ESM_ENCH_H
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
/*
* Enchantments
@ -11,31 +13,27 @@ namespace ESM {
struct Enchantment
{
enum Type
enum Type
{
CastOnce = 0,
WhenStrikes = 1,
WhenUsed = 2,
ConstantEffect = 3
CastOnce = 0,
WhenStrikes = 1,
WhenUsed = 2,
ConstantEffect = 3
};
struct ENDTstruct
{
int type;
int cost;
int charge;
int autocalc; // Guessing this is 1 if we are supposed to auto
// calculate
};
struct ENDTstruct
{
int type;
int cost;
int charge;
int autocalc; // Guessing this is 1 if we are supposed to auto
// calculate
};
ENDTstruct data;
EffectList effects;
ENDTstruct data;
EffectList effects;
void load(ESMReader &esm)
{
esm.getHNT(data, "ENDT", 16);
effects.load(esm);
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,31 @@
#include "loadfact.hpp"
namespace ESM
{
void Faction::load(ESMReader &esm)
{
name = esm.getHNString("FNAM");
// Read rank names. These are optional.
int i = 0;
while (esm.isNextSub("RNAM") && i < 10)
ranks[i++] = esm.getHString();
// Main data struct
esm.getHNT(data, "FADT", 240);
if (data.isHidden > 1)
esm.fail("Unknown flag!");
// Read faction response values
while (esm.hasMoreSubs())
{
Reaction r;
r.faction = esm.getHNString("ANAM");
esm.getHNT(r.reaction, "INTV");
reactions.push_back(r);
}
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Faction definitions
@ -12,67 +13,46 @@ namespace ESM {
// Requirements for each rank
struct RankData
{
int attribute1, attribute2; // Attribute level
int attribute1, attribute2; // Attribute level
int skill1, skill2; // Skill level (faction skills given in
// skillID below.) You need one skill at
// level 'skill1' and two skills at level
// 'skill2' to advance to this rank.
int skill1, skill2; // Skill level (faction skills given in
// skillID below.) You need one skill at
// level 'skill1' and two skills at level
// 'skill2' to advance to this rank.
int factReaction; // Reaction from faction members
int factReaction; // Reaction from faction members
};
struct Faction
{
std::string id, name;
struct FADTstruct
{
// Which attributes we like
int attribute1, attribute2;
RankData rankData[10];
int skillID[6]; // IDs of skills this faction require
int unknown; // Always -1?
int isHidden; // 1 - hidden from player
}; // 240 bytes
FADTstruct data;
std::string id, name;
struct Reaction
{
std::string faction;
int reaction;
};
struct FADTstruct
{
// Which attributes we like
int attribute1, attribute2;
std::vector<Reaction> reactions;
RankData rankData[10];
// Name of faction ranks (may be empty for NPC factions)
std::string ranks[10];
int skillID[6]; // IDs of skills this faction require
int unknown; // Always -1?
int isHidden; // 1 - hidden from player
}; // 240 bytes
void load(ESMReader &esm)
{
name = esm.getHNString("FNAM");
FADTstruct data;
// Read rank names. These are optional.
int i = 0;
while(esm.isNextSub("RNAM") && i<10) ranks[i++] = esm.getHString();
struct Reaction
{
std::string faction;
int reaction;
};
// Main data struct
esm.getHNT(data, "FADT", 240);
std::vector<Reaction> reactions;
if(data.isHidden > 1) esm.fail("Unknown flag!");
// Name of faction ranks (may be empty for NPC factions)
std::string ranks[10];
// Read faction response values
while(esm.hasMoreSubs())
{
Reaction r;
r.faction = esm.getHNString("ANAM");
esm.getHNT(r.reaction, "INTV");
reactions.push_back(r);
}
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,24 @@
#include "loadglob.hpp"
namespace ESM
{
void Global::load(ESMReader &esm)
{
VarType t;
std::string tmp = esm.getHNString("FNAM");
if (tmp == "s")
t = VT_Short;
else if (tmp == "l")
t = VT_Int;
else if (tmp == "f")
t = VT_Float;
else
esm.fail("Illegal global variable type " + tmp);
type = t;
// Note: Both floats and longs are represented as floats.
esm.getHNT(value, "FLTV");
}
}

@ -2,8 +2,10 @@
#define _ESM_GLOB_H
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
/*
* Global script variables
@ -11,22 +13,10 @@ namespace ESM {
struct Global
{
unsigned value;
VarType type;
void load(ESMReader &esm)
{
VarType t;
std::string tmp = esm.getHNString("FNAM");
if(tmp == "s") t = VT_Short;
else if(tmp == "l") t = VT_Int;
else if(tmp == "f") t = VT_Float;
else esm.fail("Illegal global variable type " + tmp);
type = t;
unsigned value;
VarType type;
// Note: Both floats and longs are represented as floats.
esm.getHNT(value, "FLTV");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,172 @@
#include "loadgmst.hpp"
namespace ESM
{
// Some handy macros
#define cI(s,x) { if(id == (s)) return (i == (x)); }
#define cF(s,x) { if(id == (s)) return (f == (x)); }
#define cS(s,x) { if(id == (s)) return (str == (x)); }
bool GameSetting::isDirtyTribunal()
{
/*
Here, id contains the game setting name, and we check the
setting for certain values. If it matches, this is a "dirty"
entry. The correct entry (as defined in Tribunal and Bloodmoon
esms) are given in the comments. Many of the values are correct,
and are marked as 'same'. We still ignore them though, as they
are still in the wrong file and might override custom values
from other mods.
*/
// Strings
cS("sProfitValue", "Profit Value"); // 'Profit:'
cS("sEditNote", "Edit Note"); // same
cS("sDeleteNote", "Delete Note?"); // same
cS("sMaxSale", "Max Sale"); // 'Seller Max'
cS("sMagicFabricantID", "Fabricant"); // 'Fabricant_summon'
cS("sTeleportDisabled",
"Teleportation magic does not work here.");// same
cS("sLevitateDisabled",
"Levitation magic does not work here."); // same
cS("sCompanionShare", "Companion Share"); // 'Share'
cS("sCompanionWarningButtonOne",
"Let the mercenary quit."); // same
cS("sCompanionWarningButtonTwo",
"Return to Companion Share display."); // same
cS("sCompanionWarningMessage",
"Your mercenary is poorer now than when he contracted with you. Your mercenary will quit if you do not give him gold or goods to bring his Profit Value to a positive value.");
// 'Your mercenary is poorer now than when he contracted with
// you. Your mercenary will quit if you do not give him gold
// or goods to bring his Profit to a positive value.'
// [The difference here is "Profit Value" -> "Profit"]
// Strings that matches the id
cS("sEffectSummonFabricant", id);// 'Summon Fabricant'
return false;
}
// Bloodmoon variant
bool GameSetting::isDirtyBloodmoon()
{
// Strings
cS("sWerewolfPopup", "Werewolf"); // same
cS("sWerewolfRestMessage",
"You cannot rest in werewolf form."); // same
cS("sWerewolfRefusal",
"You cannot do this as a werewolf."); // same
cS("sWerewolfAlarmMessage",
"You have been detected changing from a werewolf state.");
// 'You have been detected as a known werewolf.'
// Strings that matches the id
cS("sMagicCreature01ID", id); // 'BM_wolf_grey_summon'
cS("sMagicCreature02ID", id); // 'BM_bear_black_summon'
cS("sMagicCreature03ID", id); // 'BM_wolf_bone_summon'
cS("sMagicCreature04ID", id); // same
cS("sMagicCreature05ID", id); // same
cS("sEffectSummonCreature01", id); // 'Calf Wolf'
cS("sEffectSummonCreature02", id); // 'Calf Bear'
cS("sEffectSummonCreature03", id); // 'Summon Bonewolf'
cS("sEffectSummonCreature04", id); // same
cS("sEffectSummonCreature05", id); // same
// Integers
cI("iWereWolfBounty", 10000); // 1000
cI("iWereWolfFightMod", 100); // same
cI("iWereWolfFleeMod", 100); // same
cI("iWereWolfLevelToAttack", 20); // same
// Floats
cF("fFleeDistance", 3000); // same
cF("fCombatDistanceWerewolfMod", 0.3); // same
cF("fWereWolfFatigue", 400); // same
cF("fWereWolfEnchant", 1); // 0
cF("fWereWolfArmorer", 1); // 0
cF("fWereWolfBlock", 1); // 0
cF("fWereWolfSneak", 1); // 95
cF("fWereWolfDestruction", 1); // 0
cF("fWereWolfEndurance", 150); // same
cF("fWereWolfConjuration", 1); // 0
cF("fWereWolfRestoration", 1); // 0
cF("fWereWolfAthletics", 150); // 50
cF("fWereWolfLuck", 1); // 25
cF("fWereWolfSilverWeaponDamageMult", 1.5); // 2
cF("fWereWolfMediumArmor", 1); // 0
cF("fWereWolfShortBlade", 1); // 0
cF("fWereWolfAcrobatics", 150); // 80
cF("fWereWolfSpeechcraft", 1); // 0
cF("fWereWolfAlteration", 1); // 0
cF("fWereWolfIllusion", 1); // 0
cF("fWereWolfLongBlade", 1); // 0
cF("fWereWolfMarksman", 1); // 0
cF("fWereWolfHandtoHand", 100); // same
cF("fWereWolfIntellegence", 1); // 0
cF("fWereWolfAlchemy", 1); // 0
cF("fWereWolfUnarmored", 100); // same
cF("fWereWolfAxe", 1); // 0
cF("fWereWolfRunMult", 1.5); // 1.3
cF("fWereWolfMagicka", 100); // same
cF("fWereWolfAgility", 150); // same
cF("fWereWolfBluntWeapon", 1); // 0
cF("fWereWolfSecurity", 1); // 0
cF("fWereWolfPersonality", 1); // 0
cF("fWereWolfMerchantile", 1); // 0
cF("fWereWolfHeavyArmor", 1); // 0
cF("fWereWolfSpear", 1); // 0
cF("fWereWolfStrength", 150); // same
cF("fWereWolfHealth", 2); // same
cF("fWereWolfMysticism", 1); // 0
cF("fWereWolfLightArmor", 1); // 0
cF("fWereWolfWillPower", 1); // 0
cF("fWereWolfSpeed", 150); // 90
return false;
}
void GameSetting::load(ESMReader &esm)
{
assert(id != "");
dirty = false;
// We are apparently allowed to be empty
if (!esm.hasMoreSubs())
{
type = VT_None;
return;
}
// Load some data
esm.getSubName();
NAME n = esm.retSubName();
if (n == "STRV")
{
str = esm.getHString();
type = VT_String;
}
else if (n == "INTV")
{
esm.getHT(i);
type = VT_Int;
}
else if (n == "FLTV")
{
esm.getHT(f);
type = VT_Float;
}
else
esm.fail("Unwanted subrecord type");
int spf = esm.getSpecial();
// Check if this is one of the dirty values mentioned above. If it
// is, we set the dirty flag. This will ONLY work if you've set
// the 'id' string correctly before calling load().
if ((spf != SF_Tribunal && isDirtyTribunal()) || (spf != SF_Bloodmoon
&& isDirtyBloodmoon()))
dirty = true;
}
}

@ -4,7 +4,8 @@
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
/*
* Game setting, with automatic cleaning of "dirty" entries.
@ -13,238 +14,75 @@ namespace ESM {
struct GameSetting
{
std::string id;
// One of these is used depending on the variable type
std::string str;
int i;
float f;
VarType type;
// Set to true if this is a 'dirty' entry which should be ignored
bool dirty;
/*
These functions check if this game setting is one of the "dirty"
GMST records found in many mods. These are due to a serious bug in
the official TES3 editor. It only occurs in the newer editor
versions that came with Tribunal and Bloodmoon, and only if a
modder tries to make a mod without loading the corresponding
expansion master file. For example, if you have Tribunal installed
and try to make a mod without loading Tribunal.esm, the editor
will insert these GMST records as a replacement for the entries it
cannot find in the ESMs.
The values of these "dirty" records differ in general from their
values as defined in Tribunal.esm and Bloodmoon.esm, and are
always set to the same "default" values. Most of these values are
nonsensical, ie. changing the "Seller Max" string to "Max Sale",
or change the stats of werewolves to useless values like 1. Some
of them break certain spell effects.
It is most likely that these values are just leftover values from
an early stage of development that are inserted as default values
by the editor code. They are supposed to be overridden when the
correct esm file is loaded. When it isn't loaded however, you get
stuck with the initial value, and this gets written to every mod
by the editor, for some reason.
Bethesda themselves have fallen for this bug. If you install both
Tribunal and Bloodmoon, the updated Tribunal.esm will contain the
dirty GMST settings from Bloodmoon, and Bloodmoon.esm will contain
some of the dirty settings from Tribunal. In other words, this bug
affects the game EVEN IF YOU DO NOT USE ANY MODS!
The guys at Bethesda are well aware of this bug (and many others),
as the mod community and fan base complained about them for a long
time. But unfortunately it was never fixed.
There are several tools available to help modders remove these
records from their files, but not all modders use them, and they
really shouldn't have to. In this file we choose instead to reject
all the corrupt values at load time.
These functions checks if the current game setting is one of the
"dirty" ones as described above. TODO: I have not checked this
against other sources yet, do that later. Currently recognizes 22
values for tribunal and 50 for bloodmoon. Legitimate GMSTs in mods
(setting values other than the default "dirty" ones) are not
affected and will work correctly.
*/
// Some handy macros
#define cI(s,x) { if(id == (s)) return (i == (x)); }
#define cF(s,x) { if(id == (s)) return (f == (x)); }
#define cS(s,x) { if(id == (s)) return (str == (x)); }
/*
Checks for dirty tribunal values. These will be ignored if found
in any file except when they are found in "Tribunal.esm".
*/
bool isDirtyTribunal()
{
std::string id;
// One of these is used depending on the variable type
std::string str;
int i;
float f;
VarType type;
// Set to true if this is a 'dirty' entry which should be ignored
bool dirty;
/*
Here, id contains the game setting name, and we check the
setting for certain values. If it matches, this is a "dirty"
entry. The correct entry (as defined in Tribunal and Bloodmoon
esms) are given in the comments. Many of the values are correct,
and are marked as 'same'. We still ignore them though, as they
are still in the wrong file and might override custom values
from other mods.
*/
// Strings
cS("sProfitValue", "Profit Value"); // 'Profit:'
cS("sEditNote", "Edit Note"); // same
cS("sDeleteNote", "Delete Note?"); // same
cS("sMaxSale", "Max Sale"); // 'Seller Max'
cS("sMagicFabricantID", "Fabricant"); // 'Fabricant_summon'
cS("sTeleportDisabled",
"Teleportation magic does not work here.");// same
cS("sLevitateDisabled",
"Levitation magic does not work here."); // same
cS("sCompanionShare", "Companion Share"); // 'Share'
cS("sCompanionWarningButtonOne",
"Let the mercenary quit."); // same
cS("sCompanionWarningButtonTwo",
"Return to Companion Share display."); // same
cS("sCompanionWarningMessage",
"Your mercenary is poorer now than when he contracted with you. Your mercenary will quit if you do not give him gold or goods to bring his Profit Value to a positive value.");
// 'Your mercenary is poorer now than when he contracted with
// you. Your mercenary will quit if you do not give him gold
// or goods to bring his Profit to a positive value.'
// [The difference here is "Profit Value" -> "Profit"]
// Strings that matches the id
cS("sEffectSummonFabricant", id);// 'Summon Fabricant'
return false;
}
// Bloodmoon variant
bool isDirtyBloodmoon()
{
// Strings
cS("sWerewolfPopup", "Werewolf"); // same
cS("sWerewolfRestMessage",
"You cannot rest in werewolf form."); // same
cS("sWerewolfRefusal",
"You cannot do this as a werewolf."); // same
cS("sWerewolfAlarmMessage",
"You have been detected changing from a werewolf state.");
// 'You have been detected as a known werewolf.'
// Strings that matches the id
cS("sMagicCreature01ID", id); // 'BM_wolf_grey_summon'
cS("sMagicCreature02ID", id); // 'BM_bear_black_summon'
cS("sMagicCreature03ID", id); // 'BM_wolf_bone_summon'
cS("sMagicCreature04ID", id); // same
cS("sMagicCreature05ID", id); // same
cS("sEffectSummonCreature01", id); // 'Calf Wolf'
cS("sEffectSummonCreature02", id); // 'Calf Bear'
cS("sEffectSummonCreature03", id); // 'Summon Bonewolf'
cS("sEffectSummonCreature04", id); // same
cS("sEffectSummonCreature05", id); // same
// Integers
cI("iWereWolfBounty", 10000); // 1000
cI("iWereWolfFightMod", 100); // same
cI("iWereWolfFleeMod", 100); // same
cI("iWereWolfLevelToAttack", 20); // same
// Floats
cF("fFleeDistance", 3000); // same
cF("fCombatDistanceWerewolfMod", 0.3); // same
cF("fWereWolfFatigue", 400); // same
cF("fWereWolfEnchant", 1); // 0
cF("fWereWolfArmorer", 1); // 0
cF("fWereWolfBlock", 1); // 0
cF("fWereWolfSneak", 1); // 95
cF("fWereWolfDestruction", 1); // 0
cF("fWereWolfEndurance", 150); // same
cF("fWereWolfConjuration", 1); // 0
cF("fWereWolfRestoration", 1); // 0
cF("fWereWolfAthletics", 150); // 50
cF("fWereWolfLuck", 1); // 25
cF("fWereWolfSilverWeaponDamageMult", 1.5); // 2
cF("fWereWolfMediumArmor", 1); // 0
cF("fWereWolfShortBlade", 1); // 0
cF("fWereWolfAcrobatics", 150); // 80
cF("fWereWolfSpeechcraft", 1); // 0
cF("fWereWolfAlteration", 1); // 0
cF("fWereWolfIllusion", 1); // 0
cF("fWereWolfLongBlade", 1); // 0
cF("fWereWolfMarksman", 1); // 0
cF("fWereWolfHandtoHand", 100); // same
cF("fWereWolfIntellegence", 1); // 0
cF("fWereWolfAlchemy", 1); // 0
cF("fWereWolfUnarmored", 100); // same
cF("fWereWolfAxe", 1); // 0
cF("fWereWolfRunMult", 1.5); // 1.3
cF("fWereWolfMagicka", 100); // same
cF("fWereWolfAgility", 150); // same
cF("fWereWolfBluntWeapon", 1); // 0
cF("fWereWolfSecurity", 1); // 0
cF("fWereWolfPersonality", 1); // 0
cF("fWereWolfMerchantile", 1); // 0
cF("fWereWolfHeavyArmor", 1); // 0
cF("fWereWolfSpear", 1); // 0
cF("fWereWolfStrength", 150); // same
cF("fWereWolfHealth", 2); // same
cF("fWereWolfMysticism", 1); // 0
cF("fWereWolfLightArmor", 1); // 0
cF("fWereWolfWillPower", 1); // 0
cF("fWereWolfSpeed", 150); // 90
return false;
}
#undef cI
#undef cF
#undef cS
void load(ESMReader &esm)
{
assert(id != "");
dirty = false;
// We are apparently allowed to be empty
if(!esm.hasMoreSubs())
{
type = VT_None;
return;
}
// Load some data
esm.getSubName();
NAME n = esm.retSubName();
if(n == "STRV")
{
str = esm.getHString();
type = VT_String;
}
else if(n == "INTV")
{
esm.getHT(i);
type = VT_Int;
}
else if(n == "FLTV")
{
esm.getHT(f);
type = VT_Float;
}
else
esm.fail("Unwanted subrecord type");
int spf = esm.getSpecial();
// Check if this is one of the dirty values mentioned above. If it
// is, we set the dirty flag. This will ONLY work if you've set
// the 'id' string correctly before calling load().
if( ( spf != SF_Tribunal && isDirtyTribunal() ) ||
( spf != SF_Bloodmoon && isDirtyBloodmoon() ) )
dirty = true;
}
These functions check if this game setting is one of the "dirty"
GMST records found in many mods. These are due to a serious bug in
the official TES3 editor. It only occurs in the newer editor
versions that came with Tribunal and Bloodmoon, and only if a
modder tries to make a mod without loading the corresponding
expansion master file. For example, if you have Tribunal installed
and try to make a mod without loading Tribunal.esm, the editor
will insert these GMST records as a replacement for the entries it
cannot find in the ESMs.
The values of these "dirty" records differ in general from their
values as defined in Tribunal.esm and Bloodmoon.esm, and are
always set to the same "default" values. Most of these values are
nonsensical, ie. changing the "Seller Max" string to "Max Sale",
or change the stats of werewolves to useless values like 1. Some
of them break certain spell effects.
It is most likely that these values are just leftover values from
an early stage of development that are inserted as default values
by the editor code. They are supposed to be overridden when the
correct esm file is loaded. When it isn't loaded however, you get
stuck with the initial value, and this gets written to every mod
by the editor, for some reason.
Bethesda themselves have fallen for this bug. If you install both
Tribunal and Bloodmoon, the updated Tribunal.esm will contain the
dirty GMST settings from Bloodmoon, and Bloodmoon.esm will contain
some of the dirty settings from Tribunal. In other words, this bug
affects the game EVEN IF YOU DO NOT USE ANY MODS!
The guys at Bethesda are well aware of this bug (and many others),
as the mod community and fan base complained about them for a long
time. But unfortunately it was never fixed.
There are several tools available to help modders remove these
records from their files, but not all modders use them, and they
really shouldn't have to. In this file we choose instead to reject
all the corrupt values at load time.
These functions checks if the current game setting is one of the
"dirty" ones as described above. TODO: I have not checked this
against other sources yet, do that later. Currently recognizes 22
values for tribunal and 50 for bloodmoon. Legitimate GMSTs in mods
(setting values other than the default "dirty" ones) are not
affected and will work correctly.
*/
/*
Checks for dirty tribunal values. These will be ignored if found
in any file except when they are found in "Tribunal.esm".
*/
bool isDirtyTribunal();
// Bloodmoon variant
bool isDirtyBloodmoon();
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,133 @@
#include "loadinfo.hpp"
namespace ESM
{
void DialInfo::load(ESMReader &esm)
{
id = esm.getHNString("INAM");
prev = esm.getHNString("PNAM");
next = esm.getHNString("NNAM");
// Not present if deleted
if (esm.isNextSub("DATA"))
esm.getHT(data, 12);
// What follows is somewhat spaghetti-ish, but it's worth if for
// an extra speedup. INFO is by far the most common record type.
// subName is a reference to the original, so it changes whenever
// a new sub name is read. esm.isEmptyOrGetName() will get the
// next name for us, or return true if there are no more records.
esm.getSubName();
const NAME &subName = esm.retSubName();
if (subName.val == REC_ONAM)
{
actor = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_RNAM)
{
race = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_CNAM)
{
clas = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
factionLess = false;
if (subName.val == REC_FNAM)
{
npcFaction = esm.getHString();
if (npcFaction == "FFFF")
factionLess = true;
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_ANAM)
{
cell = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_DNAM)
{
pcFaction = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_SNAM)
{
sound = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_NAME)
{
response = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
while (subName.val == REC_SCVR)
{
SelectStruct ss;
ss.selectRule = esm.getHString();
esm.isEmptyOrGetName();
if (subName.val == REC_INTV)
{
ss.type = VT_Int;
esm.getHT(ss.i);
}
else if (subName.val == REC_FLTV)
{
ss.type = VT_Float;
esm.getHT(ss.f);
}
else
esm.fail(
"INFO.SCVR must precede INTV or FLTV, not "
+ subName.toString());
selects.push_back(ss);
if (esm.isEmptyOrGetName())
return;
}
if (subName.val == REC_BNAM)
{
resultScript = esm.getHString();
if (esm.isEmptyOrGetName())
return;
}
questStatus = QS_None;
if (subName.val == REC_QSTN)
questStatus = QS_Name;
else if (subName.val == REC_QSTF)
questStatus = QS_Finished;
else if (subName.val == REC_QSTR)
questStatus = QS_Restart;
else if (subName.val == REC_DELE)
questStatus = QS_Deleted;
else
esm.fail(
"Don't know what to do with " + subName.toString()
+ " in INFO " + id);
if (questStatus != QS_None)
// Skip rest of record
esm.skipRecord();
}
}

@ -4,7 +4,8 @@
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
// NOT DONE
@ -15,88 +16,88 @@ namespace ESM {
struct DialInfo
{
enum Gender
enum Gender
{
Male = 0,
Female = 1,
NA = -1
};
struct DATAstruct
{
int unknown1;
int disposition;
char rank; // Rank of NPC
char gender; // See Gender enum
char PCrank; // Player rank
char unknown2;
}; // 12 bytes
DATAstruct data;
// The rules for whether or not we will select this dialog item.
struct SelectStruct
{
Male = 0,
Female = 1,
NA = -1
std::string selectRule; // This has a complicated format
float f; // Only one of 'f' or 'i' is used
int i;
VarType type;
};
struct DATAstruct
{
int unknown1;
int disposition;
char rank; // Rank of NPC
char gender; // See Gender enum
char PCrank; // Player rank
char unknown2;
}; // 12 bytes
DATAstruct data;
// The rules for whether or not we will select this dialog item.
struct SelectStruct
{
std::string selectRule; // This has a complicated format
float f; // Only one of 'f' or 'i' is used
int i;
VarType type;
};
// Journal quest indices (introduced with the quest system in Tribunal)
enum QuestStatus
// Journal quest indices (introduced with the quest system in Tribunal)
enum QuestStatus
{
QS_None,
QS_Name,
QS_Finished,
QS_Restart,
QS_Deleted
QS_None,
QS_Name,
QS_Finished,
QS_Restart,
QS_Deleted
};
// Rules for when to include this item in the final list of options
// visible to the player.
std::vector<SelectStruct> selects;
// Rules for when to include this item in the final list of options
// visible to the player.
std::vector<SelectStruct> selects;
// Id of this, previous and next INFO items
std::string id, prev, next,
// Id of this, previous and next INFO items
std::string id, prev, next,
// Various references used in determining when to select this item.
actor, race, clas, npcFaction, pcFaction, cell,
// Various references used in determining when to select this item.
actor, race, clas, npcFaction, pcFaction, cell,
// Sound and text associated with this item
sound, response,
// Sound and text associated with this item
sound, response,
// Result script (uncomiled) to run whenever this dialog item is
// selected
resultScript;
// Result script (uncomiled) to run whenever this dialog item is
// selected
resultScript;
// ONLY include this item the NPC is not part of any faction.
bool factionLess;
// ONLY include this item the NPC is not part of any faction.
bool factionLess;
// Status of this quest item
QuestStatus questStatus;
// Status of this quest item
QuestStatus questStatus;
// Hexadecimal versions of the various subrecord names.
enum SubNames
// Hexadecimal versions of the various subrecord names.
enum SubNames
{
REC_ONAM = 0x4d414e4f,
REC_RNAM = 0x4d414e52,
REC_CNAM = 0x4d414e43,
REC_FNAM = 0x4d414e46,
REC_ANAM = 0x4d414e41,
REC_DNAM = 0x4d414e44,
REC_SNAM = 0x4d414e53,
REC_NAME = 0x454d414e,
REC_SCVR = 0x52564353,
REC_INTV = 0x56544e49,
REC_FLTV = 0x56544c46,
REC_BNAM = 0x4d414e42,
REC_QSTN = 0x4e545351,
REC_QSTF = 0x46545351,
REC_QSTR = 0x52545351,
REC_DELE = 0x454c4544
REC_ONAM = 0x4d414e4f,
REC_RNAM = 0x4d414e52,
REC_CNAM = 0x4d414e43,
REC_FNAM = 0x4d414e46,
REC_ANAM = 0x4d414e41,
REC_DNAM = 0x4d414e44,
REC_SNAM = 0x4d414e53,
REC_NAME = 0x454d414e,
REC_SCVR = 0x52564353,
REC_INTV = 0x56544e49,
REC_FLTV = 0x56544c46,
REC_BNAM = 0x4d414e42,
REC_QSTN = 0x4e545351,
REC_QSTF = 0x46545351,
REC_QSTR = 0x52545351,
REC_DELE = 0x454c4544
};
void load(ESMReader &esm);
void load(ESMReader &esm);
};
/*

@ -0,0 +1,15 @@
#include "loadingr.hpp"
namespace ESM
{
void Ingredient::load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNString("FNAM");
esm.getHNT(data, "IRDT", 56);
script = esm.getHNOString("SCRI");
icon = esm.getHNOString("ITEX");
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Alchemy ingredient
@ -11,26 +12,19 @@ namespace ESM {
struct Ingredient
{
struct IRDTstruct
{
float weight;
int value;
int effectID[4]; // Effect, 0 or -1 means none
int skills[4]; // SkillEnum related to effect
int attributes[4]; // Attribute related to effect
};
struct IRDTstruct
{
float weight;
int value;
int effectID[4]; // Effect, 0 or -1 means none
int skills[4]; // SkillEnum related to effect
int attributes[4]; // Attribute related to effect
};
IRDTstruct data;
std::string name, model, icon, script;
IRDTstruct data;
std::string name, model, icon, script;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNString("FNAM");
esm.getHNT(data, "IRDT", 56);
script = esm.getHNOString("SCRI");
icon = esm.getHNOString("ITEX");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,34 @@
#include "loadlevlist.hpp"
namespace ESM
{
void LeveledListBase::load(ESMReader &esm)
{
esm.getHNT(flags, "DATA");
esm.getHNT(chanceNone, "NNAM");
if (esm.isNextSub("INDX"))
{
int len;
esm.getHT(len);
list.resize(len);
}
else
return;
// TODO: Merge with an existing lists here. This can be done
// simply by adding the lists together, making sure that they are
// sorted by level. A better way might be to exclude repeated
// items. Also, some times we don't want to merge lists, just
// overwrite. Figure out a way to give the user this option.
for (size_t i = 0; i < list.size(); i++)
{
LevelItem &li = list[i];
li.id = esm.getHNString(recName);
esm.getHNT(li.level, "INTV");
}
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Leveled lists. Since these have identical layout, I only bothered
@ -15,65 +16,50 @@ namespace ESM {
struct LeveledListBase
{
enum Flags
enum Flags
{
AllLevels = 0x01, // Calculate from all levels <= player
// level, not just the closest below
// player.
Each = 0x02 // Select a new item each time this
// list is instantiated, instead of
// giving several identical items
}; // (used when a container has more
// than one instance of one leveled
// list.)
int flags;
unsigned char chanceNone; // Chance that none are selected (0-255?)
// Record name used to read references. Must be set before load() is
// called.
const char *recName;
struct LevelItem
{
std::string id;
short level;
};
AllLevels = 0x01, // Calculate from all levels <= player
// level, not just the closest below
// player.
Each = 0x02 // Select a new item each time this
// list is instantiated, instead of
// giving several identical items
}; // (used when a container has more
// than one instance of one leveled
// list.)
int flags;
unsigned char chanceNone; // Chance that none are selected (0-255?)
std::vector<LevelItem> list;
// Record name used to read references. Must be set before load() is
// called.
const char *recName;
void load(ESMReader &esm)
{
esm.getHNT(flags, "DATA");
esm.getHNT(chanceNone, "NNAM");
struct LevelItem
{
std::string id;
short level;
};
if(esm.isNextSub("INDX"))
{
int len;
esm.getHT(len);
list.resize(len);
}
else return;
std::vector<LevelItem> list;
// TODO: Merge with an existing lists here. This can be done
// simply by adding the lists together, making sure that they are
// sorted by level. A better way might be to exclude repeated
// items. Also, some times we don't want to merge lists, just
// overwrite. Figure out a way to give the user this option.
for(size_t i=0; i<list.size(); i++)
{
LevelItem &li = list[i];
li.id = esm.getHNString(recName);
esm.getHNT(li.level, "INTV");
}
}
void load(ESMReader &esm);
};
struct CreatureLevList : LeveledListBase
{ CreatureLevList() { recName = "CNAM"; } };
struct CreatureLevList: LeveledListBase
{
CreatureLevList()
{
recName = "CNAM";
}
};
struct ItemLevList : LeveledListBase
{ ItemLevList() { recName = "INAM"; } };
struct ItemLevList: LeveledListBase
{
ItemLevList()
{
recName = "INAM";
}
};
}
#endif

@ -0,0 +1,17 @@
#include "loadligh.hpp"
namespace ESM
{
void Light::load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
icon = esm.getHNOString("ITEX");
assert(sizeof(data) == 24);
esm.getHNT(data, "LHDT", 24);
script = esm.getHNOString("SCRI");
sound = esm.getHNOString("SNAM");
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Lights. Includes static light sources and also carryable candles
@ -12,43 +13,34 @@ namespace ESM {
struct Light
{
enum Flags
enum Flags
{
Dynamic = 0x001,
Carry = 0x002, // Can be carried
Negative = 0x004, // Negative light?
Flicker = 0x008,
Fire = 0x010,
OffDefault = 0x020, // Off by default
FlickerSlow = 0x040,
Pulse = 0x080,
PulseSlow = 0x100
Dynamic = 0x001,
Carry = 0x002, // Can be carried
Negative = 0x004, // Negative light?
Flicker = 0x008,
Fire = 0x010,
OffDefault = 0x020, // Off by default
FlickerSlow = 0x040,
Pulse = 0x080,
PulseSlow = 0x100
};
struct LHDTstruct
{
float weight;
int value;
int time; // Duration
int radius;
int color; // 4-byte rgba value
int flags;
}; // Size = 24 bytes
LHDTstruct data;
std::string sound, script, model, icon, name;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
icon = esm.getHNOString("ITEX");
assert(sizeof(data) == 24);
esm.getHNT(data, "LHDT", 24);
script = esm.getHNOString("SCRI");
sound = esm.getHNOString("SNAM");
}
struct LHDTstruct
{
float weight;
int value;
int time; // Duration
int radius;
int color; // 4-byte rgba value
int flags;
}; // Size = 24 bytes
LHDTstruct data;
std::string sound, script, model, icon, name;
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,30 @@
#include "loadlocks.hpp"
namespace ESM
{
void Tool::load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNString("FNAM");
esm.getSubName();
NAME n = esm.retSubName();
// The data name varies, RIDT for repair items, LKDT for lock
// picks, PBDT for probes
esm.getHT(data, 16);
if (n == "RIDT")
{
// Swap t.data.quality and t.data.uses for repair items (sigh)
float tmp = *((float*) &data.uses);
data.uses = *((int*) &data.quality);
data.quality = tmp;
}
script = esm.getHNOString("SCRI");
icon = esm.getHNOString("ITEX");
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* This file covers lockpicks (LOCK), probes (PROB) and armor repair
@ -12,51 +13,29 @@ namespace ESM {
struct Tool
{
struct Data
{
float weight;
int value;
float quality; // And when I say nearly identical structure, I
int uses; // mean perfectly identical except that these two
// variables are swaped for repair items. Don't ask
// me why.
}; // Size = 16
Data data;
std::string name, model, icon, script;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNString("FNAM");
esm.getSubName();
NAME n = esm.retSubName();
// The data name varies, RIDT for repair items, LKDT for lock
// picks, PBDT for probes
struct Data
{
float weight;
int value;
esm.getHT(data, 16);
float quality; // And when I say nearly identical structure, I
int uses; // mean perfectly identical except that these two
// variables are swaped for repair items. Don't ask
// me why.
}; // Size = 16
if(n == "RIDT")
{
// Swap t.data.quality and t.data.uses for repair items (sigh)
float tmp = *((float*)&data.uses);
data.uses = *((int*)&data.quality);
data.quality = tmp;
}
Data data;
std::string name, model, icon, script;
script = esm.getHNOString("SCRI");
icon = esm.getHNOString("ITEX");
}
void load(ESMReader &esm);
};
struct Probe : Tool
struct Probe: Tool
{
};
struct Repair : Tool
struct Repair: Tool
{
};

@ -0,0 +1,12 @@
#include "loadltex.hpp"
namespace ESM
{
void LandTexture::load(ESMReader &esm)
{
esm.getHNT(index, "INTV");
texture = esm.getHNString("DATA");
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Texture used for texturing landscape.
@ -23,14 +24,10 @@ namespace ESM {
struct LandTexture
{
std::string id, texture;
int index;
std::string id, texture;
int index;
void load(ESMReader &esm)
{
esm.getHNT(index, "INTV");
texture = esm.getHNString("DATA");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,27 @@
#include "loadmgef.hpp"
namespace ESM
{
void MagicEffect::load(ESMReader &esm)
{
esm.getHNT(index, "INDX");
esm.getHNT(data, "MEDT", 36);
icon = esm.getHNOString("ITEX");
particle = esm.getHNOString("PTEX");
boltSound = esm.getHNOString("BSND");
castSound = esm.getHNOString("CSND");
hitSound = esm.getHNOString("HSND");
areaSound = esm.getHNOString("ASND");
casting = esm.getHNOString("CVFX");
bolt = esm.getHNOString("BVFX");
hit = esm.getHNOString("HVFX");
area = esm.getHNOString("AVFX");
description = esm.getHNOString("DESC");
}
}

@ -3,68 +3,49 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
struct MagicEffect
{
enum Flags
enum Flags
{
SpellMaking = 0x0200,
Enchanting = 0x0400,
Negative = 0x0800 // A harmful effect. Will determine whether
// eg. NPCs regard this spell as an attack.
SpellMaking = 0x0200,
Enchanting = 0x0400,
Negative = 0x0800 // A harmful effect. Will determine whether
// eg. NPCs regard this spell as an attack.
};
struct MEDTstruct
{
int school; // SpellSchool, see defs.hpp
float baseCost;
int flags;
// Properties of the fired magic 'ball' I think
int red, blue, green;
float speed, size, sizeCap;
}; // 36 bytes
MEDTstruct data;
std::string icon, particle, // Textures
casting, hit, area, // Statics
bolt, // Weapon
castSound, boltSound,
hitSound, areaSound, // Sounds
description;
// Index of this magical effect. Corresponds to one of the
// hard-coded effects in the original engine:
// 0-136 in Morrowind
// 137 in Tribunal
// 138-140 in Bloodmoon (also changes 64?)
// 141-142 are summon effects introduced in bloodmoon, but not used
// there. They can be redefined in mods by setting the name in GMST
// sEffectSummonCreature04/05 creature id in
// sMagicCreature04ID/05ID.
int index;
void load(ESMReader &esm)
{
esm.getHNT(index, "INDX");
esm.getHNT(data, "MEDT", 36);
icon = esm.getHNOString("ITEX");
particle = esm.getHNOString("PTEX");
boltSound = esm.getHNOString("BSND");
castSound = esm.getHNOString("CSND");
hitSound = esm.getHNOString("HSND");
areaSound = esm.getHNOString("ASND");
casting = esm.getHNOString("CVFX");
bolt = esm.getHNOString("BVFX");
hit = esm.getHNOString("HVFX");
area = esm.getHNOString("AVFX");
description = esm.getHNOString("DESC");
}
struct MEDTstruct
{
int school; // SpellSchool, see defs.hpp
float baseCost;
int flags;
// Properties of the fired magic 'ball' I think
int red, blue, green;
float speed, size, sizeCap;
}; // 36 bytes
MEDTstruct data;
std::string icon, particle, // Textures
casting, hit, area, // Statics
bolt, // Weapon
castSound, boltSound, hitSound, areaSound, // Sounds
description;
// Index of this magical effect. Corresponds to one of the
// hard-coded effects in the original engine:
// 0-136 in Morrowind
// 137 in Tribunal
// 138-140 in Bloodmoon (also changes 64?)
// 141-142 are summon effects introduced in bloodmoon, but not used
// there. They can be redefined in mods by setting the name in GMST
// sEffectSummonCreature04/05 creature id in
// sMagicCreature04ID/05ID.
int index;
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,15 @@
#include "loadmisc.hpp"
namespace ESM
{
void Misc::load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
esm.getHNT(data, "MCDT", 12);
script = esm.getHNOString("SCRI");
icon = esm.getHNOString("ITEX");
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Misc inventory items, basically things that have no use but can be
@ -12,26 +13,19 @@ namespace ESM {
struct Misc
{
struct MCDTstruct
{
float weight;
int value;
int isKey; // There are many keys in Morrowind.esm that has this
// set to 0. TODO: Check what this field corresponds to
// in the editor.
};
MCDTstruct data;
struct MCDTstruct
{
float weight;
int value;
int isKey; // There are many keys in Morrowind.esm that has this
// set to 0. TODO: Check what this field corresponds to
// in the editor.
};
MCDTstruct data;
std::string name, model, icon, script;
std::string name, model, icon, script;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
esm.getHNT(data, "MCDT", 12);
script = esm.getHNOString("SCRI");
icon = esm.getHNOString("ITEX");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,48 @@
#include "loadnpc.hpp"
namespace ESM
{
void NPC::load(ESMReader &esm, const std::string& id)
{
mId = id;
npdt52.gold = -10;
model = esm.getHNOString("MODL");
name = esm.getHNOString("FNAM");
race = esm.getHNString("RNAM");
cls = esm.getHNString("CNAM");
faction = esm.getHNString("ANAM");
head = esm.getHNString("BNAM");
hair = esm.getHNString("KNAM");
script = esm.getHNOString("SCRI");
esm.getSubNameIs("NPDT");
esm.getSubHeader();
if (esm.getSubSize() == 52)
esm.getExact(&npdt52, 52);
else if (esm.getSubSize() == 12)
esm.getExact(&npdt12, 12);
else
esm.fail("NPC_NPDT must be 12 or 52 bytes long");
esm.getHNT(flags, "FLAG");
inventory.load(esm);
spells.load(esm);
if (esm.isNextSub("AIDT"))
{
esm.getHExact(&AI, sizeof(AI));
hasAI = true;
}
else
hasAI = false;
esm.skipRecord();
}
}

@ -0,0 +1,35 @@
#include "loadpgrd.hpp"
namespace ESM
{
void PathGrid::load(ESMReader &esm)
{
esm.getHNT(data, "DATA", 12);
cell = esm.getHNString("NAME");
// Remember this file position
context = esm.getContext();
// Check that the sizes match up. Size = 16 * s2 (path points?)
if (esm.isNextSub("PGRP"))
{
esm.skipHSub();
int size = esm.getSubSize();
if (size != 16 * data.s2)
esm.fail("Path grid table size mismatch");
}
// Size varies. Path grid chances? Connections? Multiples of 4
// suggest either int or two shorts, or perhaps a float. Study
// it later.
if (esm.isNextSub("PGRC"))
{
esm.skipHSub();
int size = esm.getSubSize();
if (size % 4 != 0)
esm.fail("PGRC size not a multiple of 4");
}
}
}

@ -3,54 +3,28 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Path grid.
*/
struct PathGrid
{
struct DATAstruct
{
int x, y; // Grid location, matches cell for exterior cells
short s1; // ?? Usually but not always a power of 2. Doesn't seem
// to have any relation to the size of PGRC.
short s2; // Number of path points? Size of PGRP block is always 16 * s2;
}; // 12 bytes
std::string cell; // Cell name
DATAstruct data;
ESM_Context context; // Context so we can return here later and
// finish the job
void load(ESMReader &esm)
{
esm.getHNT(data, "DATA", 12);
cell = esm.getHNString("NAME");
struct DATAstruct
{
int x, y; // Grid location, matches cell for exterior cells
short s1; // ?? Usually but not always a power of 2. Doesn't seem
// to have any relation to the size of PGRC.
short s2; // Number of path points? Size of PGRP block is always 16 * s2;
}; // 12 bytes
// Remember this file position
context = esm.getContext();
// Check that the sizes match up. Size = 16 * s2 (path points?)
if(esm.isNextSub("PGRP"))
{
esm.skipHSub();
int size = esm.getSubSize();
if(size != 16*data.s2)
esm.fail("Path grid table size mismatch");
}
std::string cell; // Cell name
DATAstruct data;
ESM_Context context; // Context so we can return here later and
// finish the job
// Size varies. Path grid chances? Connections? Multiples of 4
// suggest either int or two shorts, or perhaps a float. Study
// it later.
if(esm.isNextSub("PGRC"))
{
esm.skipHSub();
int size = esm.getSubSize();
if(size % 4 != 0)
esm.fail("PGRC size not a multiple of 4");
}
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,14 @@
#include "loadrace.hpp"
namespace ESM
{
void Race::load(ESMReader &esm)
{
name = esm.getHNString("FNAM");
esm.getHNT(data, "RADT", 140);
powers.load(esm);
description = esm.getHNOString("DESC");
}
}

@ -2,8 +2,10 @@
#define _ESM_RACE_H
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
/*
* Race definition
@ -11,58 +13,51 @@ namespace ESM {
struct Race
{
struct SkillBonus
{
int skill; // SkillEnum
int bonus;
};
struct SkillBonus
{
int skill; // SkillEnum
int bonus;
};
struct MaleFemale
{
int male, female;
};
struct MaleFemale
{
int male, female;
};
struct MaleFemaleF
{
float male, female;
};
struct MaleFemaleF
{
float male, female;
};
enum Flags
enum Flags
{
Playable = 0x01,
Beast = 0x02
Playable = 0x01,
Beast = 0x02
};
struct RADTstruct
{
// List of skills that get a bonus
SkillBonus bonus[7];
struct RADTstruct
{
// List of skills that get a bonus
SkillBonus bonus[7];
// Attribute values for male/female
MaleFemale strength, intelligence, willpower, agility,
speed, endurance, personality, luck;
// Attribute values for male/female
MaleFemale strength, intelligence, willpower, agility, speed,
endurance, personality, luck;
// The actual eye level height (in game units) is (probably) given
// as 'height' times 128. This has not been tested yet.
MaleFemaleF height, weight;
// The actual eye level height (in game units) is (probably) given
// as 'height' times 128. This has not been tested yet.
MaleFemaleF height, weight;
int flags; // 0x1 - playable, 0x2 - beast race
int flags; // 0x1 - playable, 0x2 - beast race
// Size = 140 bytes
};
}; // Size = 140 bytes
RADTstruct data;
RADTstruct data;
std::string name, description;
SpellList powers;
std::string name, description;
SpellList powers;
void load(ESMReader &esm)
{
name = esm.getHNString("FNAM");
esm.getHNT(data, "RADT", 140);
powers.load(esm);
description = esm.getHNOString("DESC");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,29 @@
#include "loadregn.hpp"
namespace ESM
{
void Region::load(ESMReader &esm)
{
name = esm.getHNString("FNAM");
if (esm.getVer() == VER_12)
esm.getHNExact(&data, sizeof(data) - 2, "WEAT");
else if (esm.getVer() == VER_13)
esm.getHNExact(&data, sizeof(data), "WEAT");
else
esm.fail("Don't know what to do in this version");
sleepList = esm.getHNOString("BNAM");
esm.getHNT(mapColor, "CNAM");
while (esm.hasMoreSubs())
{
SoundRef sr;
esm.getHNT(sr, "SNAM", 33);
soundList.push_back(sr);
}
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Region data
@ -13,54 +14,33 @@ struct Region
{
#pragma pack(push)
#pragma pack(1)
struct WEATstruct
{
// I guess these are probabilities
char clear, cloudy, foggy, overcast, rain, thunder, ash,
blight,
// Unknown weather, probably snow and something. Only
// present in file version 1.3.
a,b;
}; // 10 bytes
// Reference to a sound that is played randomly in this region
struct SoundRef
{
NAME32 sound;
char chance;
}; // 33 bytes
struct WEATstruct
{
// I guess these are probabilities
char clear, cloudy, foggy, overcast, rain, thunder, ash, blight,
// Unknown weather, probably snow and something. Only
// present in file version 1.3.
a, b;
}; // 10 bytes
// Reference to a sound that is played randomly in this region
struct SoundRef
{
NAME32 sound;
char chance;
}; // 33 bytes
#pragma pack(pop)
WEATstruct data;
int mapColor; // RGBA
// sleepList refers to a eveled list of creatures you can meet if
// you sleep outside in this region.
std::string name, sleepList;
std::vector<SoundRef> soundList;
void load(ESMReader &esm)
{
name = esm.getHNString("FNAM");
if(esm.getVer() == VER_12)
esm.getHNExact(&data, sizeof(data)-2, "WEAT");
else if(esm.getVer() == VER_13)
esm.getHNExact(&data, sizeof(data), "WEAT");
else esm.fail("Don't know what to do in this version");
WEATstruct data;
int mapColor; // RGBA
sleepList = esm.getHNOString("BNAM");
// sleepList refers to a eveled list of creatures you can meet if
// you sleep outside in this region.
std::string name, sleepList;
esm.getHNT(mapColor, "CNAM");
std::vector<SoundRef> soundList;
while(esm.hasMoreSubs())
{
SoundRef sr;
esm.getHNT(sr, "SNAM", 33);
soundList.push_back(sr);
}
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,42 @@
#include "loadscpt.hpp"
namespace ESM
{
void Script::load(ESMReader &esm)
{
esm.getHNT(data, "SCHD", 52);
// List of local variables
if (esm.isNextSub("SCVR"))
{
int s = data.stringTableSize;
char* tmp = new char[s];
esm.getHExact(tmp, s);
// Set up the list of variable names
varNames.resize(data.numShorts + data.numLongs + data.numFloats);
// The tmp buffer is a null-byte separated string list, we
// just have to pick out one string at a time.
char* str = tmp;
for (size_t i = 0; i < varNames.size(); i++)
{
varNames[i] = std::string(str);
str += varNames[i].size() + 1;
if (str - tmp > s)
esm.fail("String table overflow");
}
delete[] tmp;
}
// Script data
scriptData.resize(data.scriptDataSize);
esm.getHNExact(&scriptData[0], scriptData.size(), "SCDT");
// Script text
scriptText = esm.getHNOString("SCTX");
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Script definitions
@ -12,80 +13,43 @@ namespace ESM {
class Script
{
public:
struct SCHDstruct
{
/* Script name.
NOTE: You should handle the name "Main" (case insensitive) with
care. With tribunal, modders got the ability to add 'start
scripts' to their mods, which is a script that is run at
startup and which runs throughout the game (I think.)
However, before Tribunal, there was only one startup script,
called "Main". If mods wanted to make their own start scripts,
they had to overwrite Main. This is obviously problem if
multiple mods to this at the same time.
Although most mods have switched to using Trib-style startup
scripts, some legacy mods might still overwrite Main, and this
can cause problems if several mods do it. I think the best
course of action is to NEVER overwrite main, but instead add
each with a separate unique name and add them to the start
script list. But there might be other problems with this
approach though.
*/
NAME32 name;
// These describe the sizes we need to allocate for the script
// data.
int numShorts, numLongs, numFloats,
scriptDataSize, stringTableSize;
}; // 52 bytes
SCHDstruct data;
std::vector<std::string> varNames; // Variable names
std::vector<char> scriptData; // Compiled bytecode
std::string scriptText; // Uncompiled script
void load(ESMReader &esm)
{
esm.getHNT(data, "SCHD", 52);
// List of local variables
if(esm.isNextSub("SCVR"))
{
int s = data.stringTableSize;
char* tmp = new char[s];
esm.getHExact(tmp, s);
// Set up the list of variable names
varNames.resize(data.numShorts +
data.numLongs +
data.numFloats);
// The tmp buffer is a null-byte separated string list, we
// just have to pick out one string at a time.
char* str = tmp;
for(size_t i=0; i< varNames.size(); i++)
{
varNames[i] = std::string(str);
str += varNames[i].size()+1;
if(str - tmp > s)
esm.fail("String table overflow");
}
delete[] tmp;
}
// Script data
scriptData.resize(data.scriptDataSize);
esm.getHNExact(&scriptData[0], scriptData.size(), "SCDT");
// Script text
scriptText = esm.getHNOString("SCTX");
}
struct SCHDstruct
{
/* Script name.
NOTE: You should handle the name "Main" (case insensitive) with
care. With tribunal, modders got the ability to add 'start
scripts' to their mods, which is a script that is run at
startup and which runs throughout the game (I think.)
However, before Tribunal, there was only one startup script,
called "Main". If mods wanted to make their own start scripts,
they had to overwrite Main. This is obviously problem if
multiple mods to this at the same time.
Although most mods have switched to using Trib-style startup
scripts, some legacy mods might still overwrite Main, and this
can cause problems if several mods do it. I think the best
course of action is to NEVER overwrite main, but instead add
each with a separate unique name and add them to the start
script list. But there might be other problems with this
approach though.
*/
NAME32 name;
// These describe the sizes we need to allocate for the script
// data.
int numShorts, numLongs, numFloats, scriptDataSize, stringTableSize;
}; // 52 bytes
SCHDstruct data;
std::vector<std::string> varNames; // Variable names
std::vector<char> scriptData; // Compiled bytecode
std::string scriptText; // Uncompiled script
void load(ESMReader &esm);
};
}
#endif

@ -1,33 +1,70 @@
#include "loadskil.hpp"
namespace ESMS
namespace ESM
{
const std::string Skill::sSkillNames[Length] = {
"Block",
"Armorer",
"Medium Armor",
"Heavy Armor",
"Blunt Weapon",
"Long Blade",
"Axe",
"Spear",
"Athletics",
"Enchant",
"Destruction",
"Alteration",
"Illusion",
"Conjuration",
"Mysticism",
"Restoration",
"Alchemy",
"Unarmored",
"Security",
"Sneak",
"Acrobatics",
"Light Armor",
"Short Blade",
"Marksman",
"Speechcraft",
"Hand To Hand",
const std::string Skill::sSkillNameIds[Length] = {
"sSkillBlock",
"sSkillArmorer",
"sSkillMediumarmor",
"sSkillHeavyarmor",
"sSkillBluntweapon",
"sSkillLongblade",
"sSkillAxe",
"sSkillSpear",
"sSkillAthletics",
"sSkillEnchant",
"sSkillDestruction",
"sSkillAlteration",
"sSkillIllusion",
"sSkillConjuration",
"sSkillMysticism",
"sSkillRestoration",
"sSkillAlchemy",
"sSkillUnarmored",
"sSkillSecurity",
"sSkillSneak",
"sSkillAcrobatics",
"sSkillLightarmor",
"sSkillShortblade",
"sSkillMarksman",
"sSkillMercantile",
"sSkillSpeechcraft",
"sSkillHandtohand",
};
const boost::array<Skill::SkillEnum, Skill::Length> Skill::skillIds = {{
Block,
Armorer,
MediumArmor,
HeavyArmor,
BluntWeapon,
LongBlade,
Axe,
Spear,
Athletics,
Enchant,
Destruction,
Alteration,
Illusion,
Conjuration,
Mysticism,
Restoration,
Alchemy,
Unarmored,
Security,
Sneak,
Acrobatics,
LightArmor,
ShortBlade,
Marksman,
Mercantile,
Speechcraft,
HandToHand
}};
void Skill::load(ESMReader &esm)
{
esm.getHNT(index, "INDX");
esm.getHNT(data, "SKDT", 24);
description = esm.getHNOString("DESC");
}
}

@ -66,12 +66,7 @@ struct Skill
static const std::string sSkillNameIds[Length];
static const boost::array<SkillEnum, Length> skillIds;
void load(ESMReader &esm)
{
esm.getHNT(index, "INDX");
esm.getHNT(data, "SKDT", 24);
description = esm.getHNOString("DESC");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,14 @@
#include "loadsndg.hpp"
namespace ESM
{
void SoundGenerator::load(ESMReader &esm)
{
esm.getHNT(type, "DATA", 4);
creature = esm.getHNOString("CNAM");
sound = esm.getHNOString("SNAM");
}
}

@ -28,13 +28,7 @@ struct SoundGenerator
std::string creature, sound;
void load(ESMReader &esm)
{
esm.getHNT(type, "DATA", 4);
creature = esm.getHNOString("CNAM");
sound = esm.getHNOString("SNAM");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,18 @@
#include "loadsoun.hpp"
namespace ESM
{
void Sound::load(ESMReader &esm)
{
sound = esm.getHNString("FNAM");
esm.getHNT(data, "DATA", 3);
/*
cout << "vol=" << (int)data.volume
<< " min=" << (int)data.minRange
<< " max=" << (int)data.maxRange
<< endl;
*/
}
}

@ -3,20 +3,20 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
struct SOUNstruct
{
unsigned char volume, minRange, maxRange;
unsigned char volume, minRange, maxRange;
};
struct Sound
{
SOUNstruct data;
std::string sound;
SOUNstruct data;
std::string sound;
// Body moved to load_impl.cpp
void load(ESMReader &esm);
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,13 @@
#include "loadspel.hpp"
namespace ESM
{
void Spell::load(ESMReader &esm)
{
name = esm.getHNOString("FNAM");
esm.getHNT(data, "SPDT", 12);
effects.load(esm);
}
}

@ -2,45 +2,42 @@
#define _ESM_SPEL_H
#include "esm_reader.hpp"
#include "defs.hpp"
namespace ESM {
namespace ESM
{
struct Spell
{
enum SpellType
enum SpellType
{
ST_Spell = 0, // Normal spell, must be cast and costs mana
ST_Ability = 1, // Inert ability, always in effect
ST_Blight = 2, // Blight disease
ST_Disease = 3, // Common disease
ST_Curse = 4, // Curse (?)
ST_Power = 5 // Power, can use once a day
ST_Spell = 0, // Normal spell, must be cast and costs mana
ST_Ability = 1, // Inert ability, always in effect
ST_Blight = 2, // Blight disease
ST_Disease = 3, // Common disease
ST_Curse = 4, // Curse (?)
ST_Power = 5 // Power, can use once a day
};
enum Flags
enum Flags
{
F_Autocalc = 1,
F_PCStart = 2,
F_Always = 4 // Casting always succeeds
F_Autocalc = 1,
F_PCStart = 2,
F_Always = 4 // Casting always succeeds
};
struct SPDTstruct
{
int type; // SpellType
int cost; // Mana cost
int flags; // Flags
};
struct SPDTstruct
{
int type; // SpellType
int cost; // Mana cost
int flags; // Flags
};
SPDTstruct data;
std::string name;
EffectList effects;
SPDTstruct data;
std::string name;
EffectList effects;
void load(ESMReader &esm)
{
name = esm.getHNOString("FNAM");
esm.getHNT(data, "SPDT", 12);
effects.load(esm);
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,13 @@
#include "loadsscr.hpp"
namespace ESM
{
void StartScript::load(ESMReader &esm)
{
esm.getSubNameIs("DATA");
esm.skipHSub();
script = esm.getHNString("NAME");
}
}

@ -3,27 +3,23 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
Startup script. I think this is simply a 'main' script that is run
from the begining. The SSCR records contain a DATA identifier which
is totally useless (TODO: don't remember what it contains exactly,
document it below later.), and a NAME which is simply a script
reference.
Startup script. I think this is simply a 'main' script that is run
from the begining. The SSCR records contain a DATA identifier which
is totally useless (TODO: don't remember what it contains exactly,
document it below later.), and a NAME which is simply a script
reference.
*/
struct StartScript
{
std::string script;
std::string script;
// Load a record and add it to the list
void load(ESMReader &esm)
{
esm.getSubNameIs("DATA");
esm.skipHSub();
script = esm.getHNString("NAME");
}
// Load a record and add it to the list
void load(ESMReader &esm);
};
}

@ -0,0 +1,11 @@
#include "loadstat.hpp"
namespace ESM
{
void Static::load(ESMReader &esm)
{
model = esm.getHNString("MODL");
}
}

@ -21,10 +21,7 @@ struct Static
{
std::string model;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
}
void load(ESMReader &esm);
};
}
#endif

@ -0,0 +1,16 @@
#include "loadweap.hpp"
namespace ESM
{
void Weapon::load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
esm.getHNT(data, "WPDT", 32);
script = esm.getHNOString("SCRI");
icon = esm.getHNOString("ITEX");
enchant = esm.getHNOString("ENAM");
}
}

@ -3,7 +3,8 @@
#include "esm_reader.hpp"
namespace ESM {
namespace ESM
{
/*
* Weapon definition
@ -11,58 +12,50 @@ namespace ESM {
struct Weapon
{
enum Type
enum Type
{
ShortBladeOneHand = 0,
LongBladeOneHand = 1,
LongBladeTwoHand = 2,
BluntOneHand = 3,
BluntTwoClose = 4,
BluntTwoWide = 5,
SpearTwoWide = 6,
AxeOneHand = 7,
AxeTwoHand = 8,
MarksmanBow = 9,
MarksmanCrossbow = 10,
MarksmanThrown = 11,
Arrow = 12,
Bolt = 13
ShortBladeOneHand = 0,
LongBladeOneHand = 1,
LongBladeTwoHand = 2,
BluntOneHand = 3,
BluntTwoClose = 4,
BluntTwoWide = 5,
SpearTwoWide = 6,
AxeOneHand = 7,
AxeTwoHand = 8,
MarksmanBow = 9,
MarksmanCrossbow = 10,
MarksmanThrown = 11,
Arrow = 12,
Bolt = 13
};
enum Flags
enum Flags
{
Magical = 0x01,
Silver = 0x02
Magical = 0x01,
Silver = 0x02
};
#pragma pack(push)
#pragma pack(1)
struct WPDTstruct
{
float weight;
int value;
short type;
short health;
float speed, reach;
short enchant; // Enchantment points
unsigned char chop[2], slash[2], thrust[2]; // Min and max
int flags;
}; // 32 bytes
struct WPDTstruct
{
float weight;
int value;
short type;
short health;
float speed, reach;
short enchant; // Enchantment points
unsigned char chop[2], slash[2], thrust[2]; // Min and max
int flags;
}; // 32 bytes
#pragma pack(pop)
WPDTstruct data;
WPDTstruct data;
std::string name, model, icon, enchant, script;
std::string name, model, icon, enchant, script;
void load(ESMReader &esm)
{
model = esm.getHNString("MODL");
name = esm.getHNOString("FNAM");
esm.getHNT(data, "WPDT", 32);
script = esm.getHNOString("SCRI");
icon = esm.getHNOString("ITEX");
enchant = esm.getHNOString("ENAM");
}
void load(ESMReader &esm);
};
}
#endif

@ -1,63 +0,0 @@
#include "loadskil.hpp"
namespace ESM
{
const std::string Skill::sSkillNameIds[Length] = {
"sSkillBlock",
"sSkillArmorer",
"sSkillMediumarmor",
"sSkillHeavyarmor",
"sSkillBluntweapon",
"sSkillLongblade",
"sSkillAxe",
"sSkillSpear",
"sSkillAthletics",
"sSkillEnchant",
"sSkillDestruction",
"sSkillAlteration",
"sSkillIllusion",
"sSkillConjuration",
"sSkillMysticism",
"sSkillRestoration",
"sSkillAlchemy",
"sSkillUnarmored",
"sSkillSecurity",
"sSkillSneak",
"sSkillAcrobatics",
"sSkillLightarmor",
"sSkillShortblade",
"sSkillMarksman",
"sSkillMercantile",
"sSkillSpeechcraft",
"sSkillHandtohand",
};
const boost::array<Skill::SkillEnum, Skill::Length> Skill::skillIds = {{
Block,
Armorer,
MediumArmor,
HeavyArmor,
BluntWeapon,
LongBlade,
Axe,
Spear,
Athletics,
Enchant,
Destruction,
Alteration,
Illusion,
Conjuration,
Mysticism,
Restoration,
Alchemy,
Unarmored,
Security,
Sneak,
Acrobatics,
LightArmor,
ShortBlade,
Marksman,
Mercantile,
Speechcraft,
HandToHand
}};
}
Loading…
Cancel
Save