forked from mirror/openmw-tes3mp
Converted loadinfo.d
This commit is contained in:
parent
e5a64eeb5e
commit
2302e1f712
5 changed files with 274 additions and 267 deletions
|
@ -68,7 +68,7 @@ union NAME_T
|
||||||
bool operator==(int v) { return v == val; }
|
bool operator==(int v) { return v == val; }
|
||||||
bool operator!=(int v) { return v != val; }
|
bool operator!=(int v) { return v != val; }
|
||||||
|
|
||||||
std::string toString() { return std::string(name, strnlen(name, LEN)); }
|
std::string toString() const { return std::string(name, strnlen(name, LEN)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef NAME_T<4> NAME;
|
typedef NAME_T<4> NAME;
|
||||||
|
@ -156,7 +156,7 @@ public:
|
||||||
const std::string getDesc() { return c.header.desc.toString(); }
|
const std::string getDesc() { return c.header.desc.toString(); }
|
||||||
const SaveData &getSaveData() { return saveData; }
|
const SaveData &getSaveData() { return saveData; }
|
||||||
const MasterList &getMasters() { return masters; }
|
const MasterList &getMasters() { return masters; }
|
||||||
NAME retSubName() { return c.subName; }
|
const NAME &retSubName() { return c.subName; }
|
||||||
uint32_t getSubSize() { return c.leftSub; }
|
uint32_t getSubSize() { return c.leftSub; }
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
@ -446,6 +446,18 @@ public:
|
||||||
c.leftRec -= 4;
|
c.leftRec -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is specially optimized for LoadINFO.
|
||||||
|
bool isEmptyOrGetName()
|
||||||
|
{
|
||||||
|
if(c.leftRec)
|
||||||
|
{
|
||||||
|
esm->read(c.subName.name, 4);
|
||||||
|
c.leftRec -= 4;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip current sub record, including header (but not including
|
// Skip current sub record, including header (but not including
|
||||||
// name.)
|
// name.)
|
||||||
void skipHSub()
|
void skipHSub()
|
||||||
|
|
|
@ -6,12 +6,16 @@
|
||||||
namespace ESM {
|
namespace ESM {
|
||||||
|
|
||||||
/* Cells hold data about objects, creatures, statics (rocks, walls,
|
/* Cells hold data about objects, creatures, statics (rocks, walls,
|
||||||
* buildings) and landscape (for exterior cells). Cells frequently
|
buildings) and landscape (for exterior cells). Cells frequently
|
||||||
* also has other associated LAND and PGRD records. Combined, all this
|
also has other associated LAND and PGRD records. Combined, all this
|
||||||
* data can be huge, and we cannot load it all at startup. Instead,
|
data can be huge, and we cannot load it all at startup. Instead,
|
||||||
* the strategy we use is to remember the file position of each cell
|
the strategy we use is to remember the file position of each cell
|
||||||
* (using ESMReader::getContext()) and jumping back into place
|
(using ESMReader::getContext()) and jumping back into place
|
||||||
* whenever we need to load a given cell.
|
whenever we need to load a given cell.
|
||||||
|
|
||||||
|
TODO: We should handle the actual cell content loading in this file
|
||||||
|
too, although the solution should be as open as possible and let
|
||||||
|
the user handle all data storage.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct Cell
|
struct Cell
|
||||||
|
@ -48,7 +52,8 @@ struct Cell
|
||||||
// This is implicit?
|
// This is implicit?
|
||||||
//name = esm.getHNString("NAME");
|
//name = esm.getHNString("NAME");
|
||||||
|
|
||||||
// Ignore this for now, I assume it might mean we delete the entire cell?
|
// Ignore this for now, it might mean we should delete the entire
|
||||||
|
// cell?
|
||||||
if(esm.isNextSub("DELE")) esm.skipHSub();
|
if(esm.isNextSub("DELE")) esm.skipHSub();
|
||||||
|
|
||||||
esm.getHNT(data, "DATA", 12);
|
esm.getHNT(data, "DATA", 12);
|
||||||
|
|
247
esm/loadinfo.hpp
Normal file
247
esm/loadinfo.hpp
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
#ifndef _ESM_INFO_H
|
||||||
|
#define _ESM_INFO_H
|
||||||
|
|
||||||
|
#include "esm_reader.hpp"
|
||||||
|
#include "defs.hpp"
|
||||||
|
|
||||||
|
namespace ESM {
|
||||||
|
|
||||||
|
// NOT DONE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dialogue information. A series of these follow after DIAL records,
|
||||||
|
* and form a linked list of dialogue items.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct DialInfo
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
int skip = 1;
|
||||||
|
|
||||||
|
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; skip = 4;}
|
||||||
|
else
|
||||||
|
esm.fail("Don't know what to do with " + subName.toString() + " in INFO " + id);
|
||||||
|
|
||||||
|
if(questStatus != QS_None)
|
||||||
|
esm.skip(skip);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Some old and unused D code and comments, that might be useful later:
|
||||||
|
--------
|
||||||
|
|
||||||
|
// We only need to put each item in ONE list. For if your NPC
|
||||||
|
// matches this response, then it must match ALL criteria, thus it
|
||||||
|
// will have to look up itself in all the lists. I think the order
|
||||||
|
// is well optimized in making the lists as small as possible.
|
||||||
|
if(this.actor.index != -1) actorDial[this.actor][parent]++;
|
||||||
|
else if(cell != "") cellDial[cell][parent]++;
|
||||||
|
else if(this.Class != -1) classDial[this.Class][parent]++;
|
||||||
|
else if(this.npcFaction != -1)
|
||||||
|
factionDial[this.npcFaction][parent]++;
|
||||||
|
else if(this.race != -1) raceDial[this.race][parent]++;
|
||||||
|
else allDial[parent]++; // Lists dialogues that might
|
||||||
|
// apply to all npcs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// List of dialogue topics (and greetings, voices, etc.) that
|
||||||
|
// reference other objects. Eg. raceDial is indexed by the indices of
|
||||||
|
// all races referenced. The value of raceDial is a new AA, which is
|
||||||
|
// basically used as a map (the int value is just a count and isn't
|
||||||
|
// used for anything important.) The indices (or elements of the map)
|
||||||
|
// are the dialogues that reference the given race. I use an AA
|
||||||
|
// instead of a list or array, since each dialogue can be added lots
|
||||||
|
// of times.
|
||||||
|
|
||||||
|
/*
|
||||||
|
int allDial[Dialogue*];
|
||||||
|
int classDial[int][Dialogue*];
|
||||||
|
int factionDial[int][Dialogue*];
|
||||||
|
int actorDial[Item][Dialogue*];
|
||||||
|
// If I look up cells on cell load, I don't have to resolve these
|
||||||
|
// names into anything!
|
||||||
|
int cellDial[char[]][Dialogue*];
|
||||||
|
int raceDial[int][Dialogue*];
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -19,6 +19,7 @@
|
||||||
#include "loadfact.hpp"
|
#include "loadfact.hpp"
|
||||||
#include "loadglob.hpp"
|
#include "loadglob.hpp"
|
||||||
#include "loadgmst.hpp"
|
#include "loadgmst.hpp"
|
||||||
|
#include "loadinfo.hpp"
|
||||||
#include "loadingr.hpp"
|
#include "loadingr.hpp"
|
||||||
#include "loadland.hpp"
|
#include "loadland.hpp"
|
||||||
#include "loadlevlist.hpp"
|
#include "loadlevlist.hpp"
|
||||||
|
|
|
@ -1,258 +0,0 @@
|
||||||
/*
|
|
||||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
||||||
Copyright (C) 2008 Nicolay Korslund
|
|
||||||
Email: < korslund@gmail.com >
|
|
||||||
WWW: http://openmw.snaptoad.com/
|
|
||||||
|
|
||||||
This file (loadinfo.d) is part of the OpenMW package.
|
|
||||||
|
|
||||||
OpenMW is distributed as free software: you can redistribute it
|
|
||||||
and/or modify it under the terms of the GNU General Public License
|
|
||||||
version 3, as published by the Free Software Foundation.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
version 3 along with this program. If not, see
|
|
||||||
http://www.gnu.org/licenses/ .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
module esm.loadinfo;
|
|
||||||
|
|
||||||
import esm.imports;
|
|
||||||
import esm.loaddial;
|
|
||||||
import esm.loadrace;
|
|
||||||
import esm.loadclas;
|
|
||||||
import esm.loadfact;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dialogue information. These always follow a DIAL record and form a
|
|
||||||
* linked list
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct DialInfo
|
|
||||||
{
|
|
||||||
enum Gender : byte
|
|
||||||
{
|
|
||||||
Male = 0,
|
|
||||||
Female = 1,
|
|
||||||
NA = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
align(1) struct DATAstruct
|
|
||||||
{
|
|
||||||
uint unknown1;
|
|
||||||
uint disposition;
|
|
||||||
byte rank; // Rank of NPC
|
|
||||||
Gender gender; // 0 - male, 1 - female, 0xff - none
|
|
||||||
byte PCrank; // Player rank
|
|
||||||
byte unknown2;
|
|
||||||
|
|
||||||
static assert(DATAstruct.sizeof==12);
|
|
||||||
}
|
|
||||||
DATAstruct data;
|
|
||||||
|
|
||||||
// The rules for whether or not we will select this dialog item.
|
|
||||||
struct SelectStruct
|
|
||||||
{
|
|
||||||
char[] selectRule; // This has a complicated format
|
|
||||||
union { float f; int i; }
|
|
||||||
VarType type;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Id of prevous and next in linked list
|
|
||||||
char[] id, prev, next;
|
|
||||||
|
|
||||||
// Various references used in determining when to select this item.
|
|
||||||
Item actor;
|
|
||||||
Race *race;
|
|
||||||
Class *cls;
|
|
||||||
Faction* npcFaction, pcFaction;
|
|
||||||
bool factionLess; // ONLY select this item the NPC is not part of any faction.
|
|
||||||
char[] cell; // Use this to compare with current cell name
|
|
||||||
RegionBuffer!(SelectStruct) selects; // Selection rules
|
|
||||||
|
|
||||||
SoundIndex sound; // Sound to play when this is selected.
|
|
||||||
char[] response; // The text content of this info item.
|
|
||||||
|
|
||||||
// TODO: This should probably be compiled at load time?
|
|
||||||
char[] resultScript; // Result script (uncompiled) - is run if this
|
|
||||||
// dialog item is selected.
|
|
||||||
|
|
||||||
// Journal quest indices (introduced with the quest system in tribunal)
|
|
||||||
enum Quest
|
|
||||||
{
|
|
||||||
None, Name, Finished, Restart
|
|
||||||
}
|
|
||||||
|
|
||||||
bool deleted;
|
|
||||||
|
|
||||||
Quest questStatus;
|
|
||||||
|
|
||||||
void load(DialogueType tp)
|
|
||||||
{with(esFile){
|
|
||||||
id = getHNString("INAM");
|
|
||||||
prev = getHNString("PNAM");
|
|
||||||
next = getHNString("NNAM");
|
|
||||||
|
|
||||||
// Not present if deleted
|
|
||||||
if(isNextSub("DATA"))
|
|
||||||
readHExact(&data, data.sizeof);
|
|
||||||
|
|
||||||
// What follows is terrible spaghetti code, but I like it! ;-) In
|
|
||||||
// all seriousness, it's an attempt to make things faster, since
|
|
||||||
// INFO is by far the most common record type.
|
|
||||||
|
|
||||||
// subName is a slice of the original, so it changes when new sub
|
|
||||||
// names are read.
|
|
||||||
getSubName();
|
|
||||||
char[] subName = retSubName();
|
|
||||||
|
|
||||||
if(subName == "ONAM")
|
|
||||||
{
|
|
||||||
actor = actors.lookup(tmpHString());
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
} else actor.i = null;
|
|
||||||
if(subName == "RNAM")
|
|
||||||
{
|
|
||||||
race = cast(Race*)races.lookup(tmpHString());
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
} else race = null;
|
|
||||||
if(subName == "CNAM")
|
|
||||||
{
|
|
||||||
cls = cast(Class*)classes.lookup(tmpHString());
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
} else cls = null;
|
|
||||||
|
|
||||||
npcFaction = null;
|
|
||||||
factionLess = false;
|
|
||||||
if(subName == "FNAM")
|
|
||||||
{
|
|
||||||
char[] tmp = tmpHString();
|
|
||||||
if(tmp == "FFFF") factionLess = true;
|
|
||||||
else npcFaction = cast(Faction*)factions.lookup(tmp);
|
|
||||||
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
}
|
|
||||||
if(subName == "ANAM")
|
|
||||||
{
|
|
||||||
cell = getHString();
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
} else cell = null;
|
|
||||||
if(subName == "DNAM")
|
|
||||||
{
|
|
||||||
pcFaction = cast(Faction*)factions.lookup(tmpHString());
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
} else pcFaction = null;
|
|
||||||
if(subName == "SNAM")
|
|
||||||
{
|
|
||||||
sound = resources.lookupSound(tmpHString());
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
} else sound = SoundIndex.init;
|
|
||||||
if(subName == "NAME")
|
|
||||||
{
|
|
||||||
response = getHString();
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
} else response = null;
|
|
||||||
|
|
||||||
selects = null;
|
|
||||||
while(subName == "SCVR")
|
|
||||||
{
|
|
||||||
if(selects is null) selects = esmRegion.getBuffer!(SelectStruct)(1,1);
|
|
||||||
else selects.length = selects.length + 1;
|
|
||||||
with(selects.array()[$-1])
|
|
||||||
{
|
|
||||||
selectRule = getHString();
|
|
||||||
isEmptyOrGetName();
|
|
||||||
if(subName == "INTV") type = VarType.Int;
|
|
||||||
else if(subName == "FLTV") type = VarType.Float;
|
|
||||||
else
|
|
||||||
fail("INFO.SCVR must precede INTV or FLTV, not "
|
|
||||||
~ subName);
|
|
||||||
readHExact(&i, 4);
|
|
||||||
}
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(subName == "BNAM")
|
|
||||||
{
|
|
||||||
resultScript = getHString();
|
|
||||||
if(isEmptyOrGetName) return;
|
|
||||||
} else resultScript = null;
|
|
||||||
|
|
||||||
deleted = false;
|
|
||||||
questStatus = Quest.None;
|
|
||||||
|
|
||||||
if(subName == "QSTN") questStatus = Quest.Name;
|
|
||||||
else if(subName == "QSTF") questStatus = Quest.Finished;
|
|
||||||
else if(subName == "QSTR") questStatus = Quest.Restart;
|
|
||||||
else if(subName == "DELE") {getHInt(); deleted = true;}
|
|
||||||
else
|
|
||||||
fail("Don't know what to do with " ~ subName ~ " in INFO " ~ id);
|
|
||||||
|
|
||||||
if(questStatus != Quest.None)
|
|
||||||
{
|
|
||||||
getHByte();
|
|
||||||
// The Quest markers should only appear in journal INFOs, but
|
|
||||||
// sometime the appear outside it. We could issue a warning,
|
|
||||||
// but lets just ignore it instead.
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(tp != Dialogue.Type.Journal)
|
|
||||||
writefln("WARNING: Found INFO quest marker in INFO %s type %s",
|
|
||||||
id, cast(int)tp);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// We only need to put each item in ONE list. For if your NPC
|
|
||||||
// matches this response, then it must match ALL criteria, thus it
|
|
||||||
// will have to look up itself in all the lists. I think the order
|
|
||||||
// is well optimized in making the lists as small as possible.
|
|
||||||
if(this.actor.index != -1) actorDial[this.actor][parent]++;
|
|
||||||
else if(cell != "") cellDial[cell][parent]++;
|
|
||||||
else if(this.Class != -1) classDial[this.Class][parent]++;
|
|
||||||
else if(this.npcFaction != -1)
|
|
||||||
factionDial[this.npcFaction][parent]++;
|
|
||||||
else if(this.race != -1) raceDial[this.race][parent]++;
|
|
||||||
else allDial[parent]++; // Lists dialogues that might
|
|
||||||
// apply to all npcs.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct DialInfoList
|
|
||||||
{
|
|
||||||
LoadState state;
|
|
||||||
|
|
||||||
DialInfo d;
|
|
||||||
|
|
||||||
void load(DialogueType type)
|
|
||||||
{
|
|
||||||
d.load(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// List of dialogue topics (and greetings, voices, etc.) that
|
|
||||||
// reference other objects. Eg. raceDial is indexed by the indices of
|
|
||||||
// all races referenced. The value of raceDial is a new AA, which is
|
|
||||||
// basically used as a map (the int value is just a count and isn't
|
|
||||||
// used for anything important.) The indices (or elements of the map)
|
|
||||||
// are the dialogues that reference the given race. I use an AA
|
|
||||||
// instead of a list or array, since each dialogue can be added lots
|
|
||||||
// of times.
|
|
||||||
|
|
||||||
/*
|
|
||||||
int allDial[Dialogue*];
|
|
||||||
int classDial[int][Dialogue*];
|
|
||||||
int factionDial[int][Dialogue*];
|
|
||||||
int actorDial[Item][Dialogue*];
|
|
||||||
// If I look up cells on cell load, I don't have to resolve these
|
|
||||||
// names into anything!
|
|
||||||
int cellDial[char[]][Dialogue*];
|
|
||||||
int raceDial[int][Dialogue*];
|
|
||||||
*/
|
|
Loading…
Reference in a new issue