OpenRaider  0.1.4-dev
Open Source Tomb Raider Game Engine implementation
Script.cpp
Go to the documentation of this file.
1 
8 #include "global.h"
9 #include "Script.h"
10 
11 const bool Script::opcodeHasOperand[OP_UNKNOWN] {
12  true, true, true, true, true, true,
13  false, true, true, false, true, false,
14  true, false, false, false, true, true,
15  true, true, true, false, false
16 };
17 
18 Script::Script() : puzzles(4), pickups(2), keys(4) {
19  version = 0;
20  firstOption = 0;
21  titleReplace = 0;
22  onDeathDemoMode = 0;
23  onDeathInGame = 0;
24  noInputTime = 0;
25  onDemoInterrupt = 0;
26  onDemoEnd = 0;
27  numLevels = 0;
28  numPictures = 0;
29  numTitles = 0;
30  numFMVs = 0;
31  numCutscenes = 0;
32  numDemos = 0;
33  titleTrack = 0;
34  singleLevel = 0;
35  flags = 0;
36  cypherCode = 0;
37  language = 0;
38  secretTrack = 0;
39  numPCStrings = 41;
40  numGameStrings = 0;
41 }
42 
43 int Script::load(std::string file) {
44  BinaryFile f;
45 
46  if (f.open(file) != 0)
47  return 1;
48 
49  version = f.readU32();
50 
51  char desc[256];
52  for (int i = 0; i < 256; i++)
53  desc[i] = f.read8();
54  description = desc;
55 
56  uint16_t gameflowSize = f.readU16();
57  assertEqual(gameflowSize, 128);
58 
59  firstOption = f.readU32();
60  titleReplace = f.read32();
62  onDeathInGame = f.readU32();
63  noInputTime = f.readU32(); // Scaled *100 in TR3
65  onDemoEnd = f.readU32();
66 
67  // Filler 1 (36 bytes)
68  f.seek(f.tell() + 36);
69 
70  numLevels = f.readU16();
71  numPictures = f.readU16();
72  numTitles = f.readU16();
73  numFMVs = f.readU16();
74  numCutscenes = f.readU16();
75  numDemos = f.readU16();
76  titleTrack = f.readU16();
77  singleLevel = f.read16();
78 
79  // Filler 2 (32 bytes)
80  f.seek(f.tell() + 32);
81 
82  flags = f.readU16();
83 
84  // Filler 3 (6 bytes)
85  f.seek(f.tell() + 6);
86 
87  cypherCode = f.readU8();
88  language = f.readU8();
89  secretTrack = f.readU16(); // Zero in TR3, Part of filler or real number?
90 
91  // Filler 4 (4 bytes)
92  f.seek(f.tell() + 4);
93 
94  // Strings
101 
102  // Level Scripts
104 
105  numGameStrings = f.readU16();
106 
107  // More strings...
120 
121  return 0;
122 }
123 
124 void Script::readStringPackage(BinaryFile& f, std::vector<std::string>& v, unsigned int n) {
125  uint16_t* offset = new uint16_t[n];
126  for (unsigned int i = 0; i < n; i++)
127  offset[i] = f.readU16();
128 
129  uint16_t numBytes = f.readU16();
130 
131  char* list = new char[numBytes];
132  for (uint16_t i = 0; i < numBytes; i++) {
133  list[i] = f.read8();
134  if (flags & S_UseSecurityTag) {
135  list[i] ^= cypherCode;
136  }
137  }
138 
139  for (unsigned int i = 0; i < n; i++) {
140  std::string tmp(list + offset[i]);
141  v.push_back(tmp);
142  }
143 
144  delete [] list;
145  delete [] offset;
146 }
147 
148 void Script::readScriptPackage(BinaryFile& f, std::vector<std::vector<uint16_t>>& v,
149  unsigned int n) {
150  uint16_t* offset = new uint16_t[n];
151  for (unsigned int i = 0; i < n; i++) {
152  offset[i] = f.readU16();
153  assertEqual(offset[i] % 2, 0);
154  }
155 
156  uint16_t numBytes = f.readU16();
157  assertEqual(numBytes % 2, 0); // 16 bit opcodes and operands
158 
159  uint16_t* list = new uint16_t[(numBytes + 6) / 2];
160  for (uint16_t i = 0; i < (numBytes / 2); i++) {
161  list[i] = f.readU16();
162  }
163 
164  // TR2 for PC and PSX has 6 "filler bytes" hex 13 00 14 00 15 00
165  // (for TR3 for PSX, the filler is hex 15 00 16 00 17 00 instead)
166  // at the end of the script block. We need to skip these...
167  uint16_t hack[3];
168  hack[0] = f.readU16();
169  hack[1] = f.readU16();
170  hack[2] = f.readU16();
171  if (((hack[0] == 19) && (hack[1] == 20) && (hack[2] == 21))
172  || ((hack[0] == 21) && (hack[1] == 22) && (hack[2] == 23))) {
173  list[numBytes / 2] = hack[0];
174  list[(numBytes / 2) + 1] = hack[1];
175  list[(numBytes / 2) + 2] = hack[2];
176  } else {
177  f.seek(f.tell() - 6);
178  }
179 
180  // TR2 for PSX has 64 bytes with unknown content (not zero!) here,
181  // TR3 for PSX has 40 bytes. We try to identify and skip them...
182  // This is also currently used to set the platform specific string count
183  hack[0] = f.readU16();
184  hack[1] = f.readU16();
185  hack[2] = f.readU16();
186  if ((hack[0] == 1) && (hack[1] == 0) && (hack[2] == 864)) {
187  f.seek(f.tell() + 58);
188  numPCStrings = 80; // TR2 has 80 PSX Strings
189  } else if ((hack[0] == 1) && (hack[1] == 0) && (hack[2] == 817)) {
190  f.seek(f.tell() + 34);
191  numPCStrings = 80; // TR3 also has 80 PSX Strings
192  } else {
193  f.seek(f.tell() - 6);
194  numPCStrings = 41;
195  }
196 
197  for (unsigned int i = 0; i < n; i++) {
198  unsigned int end = offset[i] / 2;
199 
200  // We need to detect the OP_END opcode marking the end of a
201  // script sequence (like the '\0' for the strings).
202  // However, the numerical value of OP_END could also be used
203  // as an operand for another opcode, so we have to check for this
204  bool readingOperand = false;
205  while (readingOperand || (list[end] != OP_END)) {
206  if (readingOperand) {
207  readingOperand = false;
208  end++;
209  } else {
210  if (opcodeHasOperand[list[end]]) {
211  readingOperand = true;
212  }
213  end++;
214  }
215  }
216  end++;
217 
218  std::vector<uint16_t> tmp;
219  for (unsigned int a = (offset[i] / 2); a < end; a++)
220  tmp.push_back(list[a]);
221 
222  v.push_back(tmp);
223  }
224 
225  delete [] list;
226  delete [] offset;
227 }
228 
229 unsigned int Script::levelCount() {
230  return numLevels;
231 }
232 
233 std::string Script::getLevelName(unsigned int i) {
235  return levelNames.at(i);
236 }
237 
238 std::string Script::getLevelFilename(unsigned int i) {
240  return levelFilenames.at(i);
241 }
242 
243 unsigned int Script::pictureCount() {
244  return numPictures;
245 }
246 
247 std::string Script::getPictureFilename(unsigned int i) {
249  return pictureFilenames.at(i);
250 }
251 
252 unsigned int Script::cutsceneCount() {
253  return numCutscenes;
254 }
255 
256 std::string Script::getCutsceneFilename(unsigned int i) {
258  return cutsceneFilenames.at(i);
259 }
260 
261 unsigned int Script::titleCount() {
262  return numTitles;
263 }
264 
265 std::string Script::getTitleFilename(unsigned int i) {
267  return titleFilenames.at(i);
268 }
269 
270 unsigned int Script::videoCount() {
271  return numFMVs;
272 }
273 
274 std::string Script::getVideoFilename(unsigned int i) {
276  return fmvFilenames.at(i);
277 }
278 
279 unsigned int Script::gameStringCount() {
280  return numGameStrings;
281 }
282 
283 std::string Script::getGameString(unsigned int i) {
285  return gameStrings.at(i);
286 }
287 
288 unsigned int Script::pcStringCount() {
289  return numPCStrings;
290 }
291 
292 std::string Script::getPCString(unsigned int i) {
294  return pcStrings.at(i);
295 }
296 
297 std::string Script::getPuzzleString(unsigned int i, unsigned int j) {
298  assertLessThan(i, 4);
300  return puzzles.at(i).at(j);
301 }
302 
303 std::string Script::getPickupString(unsigned int i, unsigned int j) {
304  assertLessThan(i, 2);
306  return pickups.at(i).at(j);
307 }
308 
309 std::string Script::getKeyString(unsigned int i, unsigned int j) {
310  assertLessThan(i, 4);
312  return keys.at(i).at(j);
313 }
314 
315 void Script::registerScriptHandler(ScriptOpCode op, std::function<int (bool, uint16_t)> func) {
317  scriptHandlers[op] = func;
318 }
319 
320 int Script::runScript(unsigned int level) {
321  assertLessThan(level, (numLevels + 1));
322  std::vector<uint16_t> s = script.at(level);
323 
324  for (unsigned int i = 0; i < s.size(); i++) {
325  uint16_t opcode = s.at(i);
326  if (opcode >= OP_UNKNOWN) {
327  return 1;
328  }
329 
330  uint16_t operand = 0;
331  if (opcodeHasOperand[opcode]) {
332  if ((i + 1) >= s.size())
333  return 2; // Can't read operand!
334 
335  operand = s.at(++i);
336  }
337 
338  if (scriptHandlers[opcode]) {
339  int error = scriptHandlers[opcode](opcodeHasOperand[opcode], operand);
340  if (error != 0)
341  return error;
342  } else {
343  return 3;
344  }
345  }
346 
347  return 0;
348 }
349 
350 std::string Script::getLanguage() {
351  if (language == S_English) {
352  return "English (UK)";
353  } else if (language == S_French) {
354  return "French";
355  } else if (language == S_German) {
356  return "German";
357  } else if (language == S_American) {
358  return "English (US)";
359  } else if (language == S_Japanese) {
360  return "Japanese";
361  } else {
362  return "Unknown";
363  }
364 }
365 
int32_t titleReplace
Definition: Script.h:157
int runScript(unsigned int level)
Definition: Script.cpp:320
unsigned int titleCount()
Definition: Script.cpp:261
uint32_t firstOption
Definition: Script.h:156
uint16_t numCutscenes
Definition: Script.h:167
uint32_t noInputTime
Definition: Script.h:160
std::vector< std::string > gameStrings
Definition: Script.h:187
std::string getTitleFilename(unsigned int i)
Definition: Script.cpp:265
virtual uint8_t readU8()
Definition: binary.cpp:14
virtual int8_t read8()
Definition: binary.cpp:70
uint16_t flags
Definition: Script.h:171
uint32_t onDemoInterrupt
Definition: Script.h:161
uint16_t numGameStrings
Definition: Script.h:177
Strings XORed with cypherCode.
Definition: Script.h:140
uint32_t version
Definition: Script.h:152
Closes script sequence.
Definition: Script.h:42
std::string getLevelFilename(unsigned int i)
Definition: Script.cpp:238
uint16_t numLevels
Definition: Script.h:163
std::string getLevelName(unsigned int i)
Definition: Script.cpp:233
virtual long long tell()
Definition: binary.cpp:123
std::vector< std::vector< std::string > > keys
Definition: Script.h:191
static const bool opcodeHasOperand[OP_UNKNOWN]
Definition: Script.h:149
Included everywhere.
virtual void seek(long long pos=0)
Definition: binary.cpp:128
uint32_t onDeathInGame
Definition: Script.h:159
std::vector< std::string > pcStrings
Definition: Script.h:188
virtual int16_t read16()
Definition: binary.cpp:77
std::function< int(bool, uint16_t)> scriptHandlers[OP_UNKNOWN]
Definition: Script.h:193
uint16_t titleTrack
Definition: Script.h:169
static void error(char *msg)
Definition: commander.c:19
unsigned int gameStringCount()
Definition: Script.cpp:279
unsigned int pictureCount()
Definition: Script.cpp:243
Tomb Raider 2/3 Script Loader.
uint16_t numTitles
Definition: Script.h:165
std::vector< std::string > titleFilenames
Definition: Script.h:182
std::vector< std::string > pictureFilenames
Definition: Script.h:181
int16_t singleLevel
Definition: Script.h:170
uint32_t onDeathDemoMode
Definition: Script.h:158
void readScriptPackage(BinaryFile &f, std::vector< std::vector< uint16_t >> &v, unsigned int n)
Definition: Script.cpp:148
virtual uint16_t readU16()
Definition: binary.cpp:21
std::string getPickupString(unsigned int i, unsigned int j)
Definition: Script.cpp:303
std::vector< std::string > cutsceneFilenames
Definition: Script.h:185
uint16_t numFMVs
Definition: Script.h:166
std::string description
Definition: Script.h:153
std::string getPuzzleString(unsigned int i, unsigned int j)
Definition: Script.cpp:297
unsigned int videoCount()
Definition: Script.cpp:270
std::string getLanguage()
Definition: Script.cpp:350
uint16_t secretTrack
Definition: Script.h:174
std::vector< std::string > levelFilenames
Definition: Script.h:184
std::vector< std::string > levelNames
Definition: Script.h:180
std::vector< std::vector< uint16_t > > script
Definition: Script.h:186
#define assertEqual(x, y)
Definition: global.h:130
virtual uint32_t readU32()
Definition: binary.cpp:27
int load(std::string file)
Definition: Script.cpp:43
uint8_t cypherCode
Definition: Script.h:172
std::string getKeyString(unsigned int i, unsigned int j)
Definition: Script.cpp:309
std::vector< std::vector< std::string > > pickups
Definition: Script.h:190
virtual int32_t read32()
Definition: binary.cpp:85
void readStringPackage(BinaryFile &f, std::vector< std::string > &v, unsigned int n)
Definition: Script.cpp:124
std::string getGameString(unsigned int i)
Definition: Script.cpp:283
unsigned int pcStringCount()
Definition: Script.cpp:288
std::vector< std::string > fmvFilenames
Definition: Script.h:183
unsigned int cutsceneCount()
Definition: Script.cpp:252
std::string getPictureFilename(unsigned int i)
Definition: Script.cpp:247
std::vector< std::vector< std::string > > puzzles
Definition: Script.h:189
#define assertLessThan(x, y)
Definition: global.h:146
Script()
Definition: Script.cpp:18
unsigned int levelCount()
Definition: Script.cpp:229
uint16_t numPCStrings
Definition: Script.h:176
uint8_t language
Definition: Script.h:173
std::string getCutsceneFilename(unsigned int i)
Definition: Script.cpp:256
std::string getPCString(unsigned int i)
Definition: Script.cpp:292
uint32_t onDemoEnd
Definition: Script.h:162
std::string getVideoFilename(unsigned int i)
Definition: Script.cpp:274
void registerScriptHandler(ScriptOpCode op, std::function< int(bool, uint16_t)> func)
Definition: Script.cpp:315
int open(std::string f="")
Definition: binary.cpp:112
ScriptOpCode
Definition: Script.h:32
uint16_t numPictures
Definition: Script.h:164
uint16_t numDemos
Definition: Script.h:168