1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-30 07:45:39 +00:00

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

Removed obsolete *.cpp files.
This commit is contained in:
Nikolay Kasyanov 2011-04-08 17:58:21 +04:00 committed by Pieter van der Kloet
parent 7168795ae6
commit fcfe267fc9
60 changed files with 1571 additions and 1325 deletions

View file

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

View file

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

View file

@ -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;
*/
}
}

View file

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

View file

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

View file

@ -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;
std::string name, model, script;
float weight; // Not sure, might be max total weight allowed?
int flags;
InventoryList inventory;
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");
script = esm.getHNOString("SCRI");
inventory.load(esm);
}
void load(ESMReader &esm);
};
}
#endif

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
std::string id, name;
struct FADTstruct
{
// Which attributes we like
int attribute1, attribute2;
struct FADTstruct
{
// Which attributes we like
int attribute1, attribute2;
RankData rankData[10];
RankData rankData[10];
int skillID[6]; // IDs of skills this faction require
int unknown; // Always -1?
int isHidden; // 1 - hidden from player
}; // 240 bytes
int skillID[6]; // IDs of skills this faction require
int unknown; // Always -1?
int isHidden; // 1 - hidden from player
}; // 240 bytes
FADTstruct data;
FADTstruct data;
struct Reaction
{
std::string faction;
int reaction;
};
struct Reaction
{
std::string faction;
int reaction;
};
std::vector<Reaction> reactions;
std::vector<Reaction> reactions;
// Name of faction ranks (may be empty for NPC factions)
std::string ranks[10];
// Name of faction ranks (may be empty for NPC factions)
std::string ranks[10];
void 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);
}
}
void load(ESMReader &esm);
};
}
#endif

View file

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

View file

@ -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;
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;
// Note: Both floats and longs are represented as floats.
esm.getHNT(value, "FLTV");
}
void load(ESMReader &esm);
};
}
#endif

172
components/esm/loadgmst.cpp Normal file
View file

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

View file

@ -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;
std::string id;
// One of these is used depending on the variable type
std::string str;
int i;
float f;
VarType type;
// 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;
// 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()
{
/*
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.
*/
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.
// 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"]
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.
// Strings that matches the id
cS("sEffectSummonFabricant", id);// 'Summon Fabricant'
return false;
}
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.
// 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.'
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!
// 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
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.
// Integers
cI("iWereWolfBounty", 10000); // 1000
cI("iWereWolfFightMod", 100); // same
cI("iWereWolfFleeMod", 100); // same
cI("iWereWolfLevelToAttack", 20); // same
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.
// 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;
}
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.
*/
#undef cI
#undef cF
#undef cS
/*
Checks for dirty tribunal values. These will be ignored if found
in any file except when they are found in "Tribunal.esm".
*/
bool isDirtyTribunal();
void load(ESMReader &esm)
{
assert(id != "");
// Bloodmoon variant
bool isDirtyBloodmoon();
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;
}
void load(ESMReader &esm);
};
}
#endif

133
components/esm/loadinfo.cpp Normal file
View file

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

View file

@ -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
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
{
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
struct DATAstruct
{
QS_None,
QS_Name,
QS_Finished,
QS_Restart,
QS_Deleted
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;
};
// 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,
// 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,
// 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;
// Status of this quest item
QuestStatus questStatus;
// Hexadecimal versions of the various subrecord names.
enum SubNames
// Journal quest indices (introduced with the quest system in Tribunal)
enum QuestStatus
{
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
QS_None,
QS_Name,
QS_Finished,
QS_Restart,
QS_Deleted
};
void load(ESMReader &esm);
// 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,
// 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,
// 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;
// Status of this quest item
QuestStatus questStatus;
// 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
};
void load(ESMReader &esm);
};
/*

View file

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

View file

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

View file

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

View file

@ -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?)
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;
// Record name used to read references. Must be set before load() is
// called.
const char *recName;
struct LevelItem
{
std::string id;
short level;
};
struct LevelItem
{
std::string id;
short level;
};
std::vector<LevelItem> list;
std::vector<LevelItem> list;
void 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");
}
}
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

View file

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

View file

@ -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
struct LHDTstruct
{
float weight;
int value;
int time; // Duration
int radius;
int color; // 4-byte rgba value
int flags;
}; // Size = 24 bytes
LHDTstruct data;
LHDTstruct data;
std::string sound, script, model, icon, name;
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");
}
void load(ESMReader &esm);
};
}
#endif

View file

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

View file

@ -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;
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
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;
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
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");
}
void load(ESMReader &esm);
};
struct Probe : Tool
struct Probe: Tool
{
};
struct Repair : Tool
struct Repair: Tool
{
};

View file

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

View file

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

View file

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

View file

@ -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
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;
MEDTstruct data;
std::string icon, particle, // Textures
casting, hit, area, // Statics
bolt, // Weapon
castSound, boltSound,
hitSound, areaSound, // Sounds
description;
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;
// 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");
}
void load(ESMReader &esm);
};
}
#endif

View file

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

View file

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

View file

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

View file

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

View file

@ -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
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
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");
// 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");
}
}
void load(ESMReader &esm);
};
}
#endif

View file

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

View file

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

View file

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

View file

@ -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
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
// 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
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;
// 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;
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");
sleepList = esm.getHNOString("BNAM");
esm.getHNT(mapColor, "CNAM");
while(esm.hasMoreSubs())
{
SoundRef sr;
esm.getHNT(sr, "SNAM", 33);
soundList.push_back(sr);
}
}
void load(ESMReader &esm);
};
}
#endif

View file

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

View file

@ -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.
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.)
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.
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.
*/
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;
NAME32 name;
// These describe the sizes we need to allocate for the script
// data.
int numShorts, numLongs, numFloats,
scriptDataSize, stringTableSize;
}; // 52 bytes
// These describe the sizes we need to allocate for the script
// data.
int numShorts, numLongs, numFloats, scriptDataSize, stringTableSize;
}; // 52 bytes
SCHDstruct data;
SCHDstruct data;
std::vector<std::string> varNames; // Variable names
std::vector<char> scriptData; // Compiled bytecode
std::string scriptText; // Uncompiled script
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");
}
void load(ESMReader &esm);
};
}
#endif

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
*/
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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