-
Notifications
You must be signed in to change notification settings - Fork 933
/
esmmain.d
167 lines (139 loc) · 5.07 KB
/
esmmain.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (esmmain.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.esmmain;
public import esm.records;
import ogre.ogre;
/* This file is the main module for loading from ESM, ESP and ESS
files. It stores all the data in the appropriate data structures
for later referal. TODO: Put this in a class or whatever? Nah, we
definately only need one structure like this at any one
time. However, we have to deal with unloading and reloading it,
even though that should be the exceptional case (change of plugins,
etc), not the rule (loading a savegame should not alter the base
data set, I think, but it's to early do decide.)*/
// Load a set of esm and esp files. For now, we just traverse in the
// order given. Later, we should sort these into 'masters' and
// 'plugins', because esms are always supposed to be loaded
// first. TODO: I'm not sure if I should load all these in one
// function. Do we need to be able to respond to errors in each file?
// Nah, if anything fails, give a general error message, remove the
// file from the list and try again. We have to be able to get a list
// of which files depend upon which, though... this can be done before
// this function is called.
void loadTESFiles(char[][] files)
{
// Set up all the lists to hold our data
initializeLists();
foreach(char[] filename; files)
{
esFile.open(filename, esmRegion);
while(esFile.hasMoreRecs())
{
uint flags;
// Read record header
char[] recName = esFile.getRecName();
esFile.getRecHeader(flags);
if(flags & RecordFlags.Unknown)
esFile.fail(format("UNKNOWN record flags: %xh", flags));
loadRecord(recName);
}
// We have to loop through the lists and check for broken
// references at this point, and if all forward references were
// loaded. There might be other end-of-file things to do also.
endFiles();
}
esFile.close();
// Put all inventory items into one list
items.addList(appas, ItemType.Apparatus);
items.addList(lockpicks, ItemType.Pick);
items.addList(probes, ItemType.Probe);
items.addList(repairs, ItemType.Repair);
items.addList(lights, ItemType.Light);
items.addList(ingreds, ItemType.Ingredient);
items.addList(potions, ItemType.Potion);
items.addList(armors, ItemType.Armor);
items.addList(weapons, ItemType.Weapon);
items.addList(books, ItemType.Book);
items.addList(clothes, ItemType.Clothing);
items.addList(miscItems, ItemType.Misc);
items.addList(itemLists, ItemType.ItemList); // Leveled item lists
// Same with all actors
actors.addList(creatures, ItemType.Creature);
actors.addList(creatureLists, ItemType.CreatureList);
actors.addList(npcs, ItemType.NPC);
// Finally, add everything that might be looked up in a cell into
// one list
cellRefs.addList(items);
cellRefs.addList(actors);
cellRefs.addList(doors, ItemType.Door);
cellRefs.addList(activators, ItemType.Activator);
cellRefs.addList(statics, ItemType.Static);
cellRefs.addList(containers, ItemType.Container);
// Check that all references are resolved
items.endMerge();
actors.endMerge();
cellRefs.endMerge();
// Put all NPC dialogues into the hyperlink list
foreach(char[] id, ref Dialogue dl; dialogues.names)
hyperlinks.add(id, &dl);
// Finally, sort the hyperlink lists
hyperlinks.sort();
}
// Contains the small bits of information that we currently extract
// from savegames.
struct PlayerSaveInfo
{
char[] cellName;
char[] playerName;
Placement pos;
}
// Load a TES savegame file (.ess). Currently VERY limited, reads the
// player's cell name and position
PlayerSaveInfo importSavegame(char[] file)
{
PlayerSaveInfo pi;
esFile.open(file, esmRegion);
scope(exit) esFile.close();
if(esFile.getFileType != FileType.Ess)
throw new TES3FileException(file ~ " is not a savegame");
with(esFile.saveData)
{
pi.cellName = stripz(cell);
pi.playerName = stripz(player);
}
with(esFile)
{
while(hasMoreRecs())
{
if(isNextHRec("REFR"))
{
while(hasMoreSubs())
{
getSubName();
if(retSubName() == "DATA")
readHExact(&pi.pos, pi.pos.sizeof);
else
skipHSub();
}
}
else
skipHRecord();
}
}
return pi;
}