OpenRaider  0.1.4-dev
Open Source Tomb Raider Game Engine implementation
Script.cpp
Go to the documentation of this file.
1 
8 #include <iostream>
9 #include <cstdlib>
10 #include <cstring>
11 #include <zlib.h>
12 
13 #include "global.h"
14 #include "Script.h"
15 #include "ScriptTest.h"
16 
17 #define printStrings(cnt, acc, name) { \
18  std::cout << name << " (" << cnt << ")" << std::endl; \
19  for (unsigned int i = 0; i < cnt; i++) { \
20  std::cout << " " << acc(i) << std::endl; \
21  } \
22  std::cout << std::endl; \
23 }
24 
25 #define printStrings2D(c, cnt, acc, name) { \
26  std::cout << name << " (" << c << "*" << cnt << ")" << std::endl; \
27  for (unsigned int a = 0; a < cnt; a++) { \
28  std::cout << " "; \
29  for (unsigned int i = 0; i < c; i++) { \
30  std::cout << acc(i, a); \
31  if (i < (c - 1)) \
32  std::cout << " | "; \
33  } \
34  std::cout << std::endl; \
35  } \
36  std::cout << std::endl; \
37 }
38 
39 #define registerLambda(x, y) { \
40  s.registerScriptHandler(x, [](bool hasOperand, uint16_t operand) { \
41  std::cout << "\t" << y; \
42  if (hasOperand) \
43  std::cout << " (" << operand << ")"; \
44  std::cout << std::endl; \
45  return 0; \
46  }); \
47 }
48 
49 static int printDataScript(Script& s, bool strings) {
50  if (strings) {
51  printStrings(s.levelCount(), s.getLevelName, "Level Names");
52  printStrings(s.levelCount(), s.getLevelFilename, "Level Filenames");
53  printStrings(s.pictureCount(), s.getPictureFilename, "Picture Filenames");
54  printStrings(s.cutsceneCount(), s.getCutsceneFilename, "Cutscenes");
55  printStrings(s.titleCount(), s.getTitleFilename, "Titles");
56  printStrings(s.videoCount(), s.getVideoFilename, "Videos");
57  printStrings(s.gameStringCount(), s.getGameString, "Game Strings");
58  printStrings(s.pcStringCount(), s.getPCString, "PC Strings");
59 
60  printStrings2D(4, s.levelCount(), s.getPuzzleString, "Puzzles");
61  printStrings2D(2, s.levelCount(), s.getPickupString, "Pickups");
62  printStrings2D(4, s.levelCount(), s.getKeyString, "Keys");
63  } else {
67  registerLambda(Script::OP_FMV, "Show FMV");
68  registerLambda(Script::OP_GAME, "Load level");
69  registerLambda(Script::OP_CUT, "Cutscene");
70  registerLambda(Script::OP_COMPLETE, "Level finished");
71  registerLambda(Script::OP_DEMO, "Demo sequence");
73  registerLambda(Script::OP_END, "End of script");
74  registerLambda(Script::OP_TRACK, "Sound Track");
76  registerLambda(Script::OP_LOAD_PIC, "Load picture");
77  registerLambda(Script::OP_DEADLY_WATER, "Deadly water");
78  registerLambda(Script::OP_REMOVE_WEAPONS, "Remove weapons");
79  registerLambda(Script::OP_GAMECOMPLETE, "End of game!");
80  registerLambda(Script::OP_CUTANGLE, "Cutscene angle");
81  registerLambda(Script::OP_NOFLOOR, "No floor, fall death");
82  registerLambda(Script::OP_STARTINV, "Inventory/Bonus");
83  registerLambda(Script::OP_STARTANIM, "Start animation");
85  registerLambda(Script::OP_KILLTOCOMPLETE, "Kill to complete level");
86  registerLambda(Script::OP_REMOVE_AMMO, "Remove ammo");
87 
88  for (unsigned int i = 0; i < (s.levelCount() + 1); i++) {
89  if (i == 0)
90  std::cout << "Script for Title:" << std::endl;
91  else
92  std::cout << "Script for \"" << s.getLevelName(i - 1) << "\" (" << i - 1 << "):" << std::endl;
93  int error = s.runScript(i);
94  if (error != 0) {
95  std::cout << "Returned " << error << "..." << std::endl;
96  return error;
97  }
98  std::cout << std::endl;
99  }
100  }
101 
102  return 0;
103 }
104 
105 static int test(const char* file, unsigned int n) {
106  Script s;
107 
108  std::cout << "Testing " << testDescription[n] << std::endl;
109 
110  if (s.load(file) != 0) {
111  std::cout << "Could not open file " << file << std::endl;
112  return 1;
113  }
114 
116  std::cout << "Game String Count " << s.gameStringCount() << " != " << testExpectedGameStringCount[n]
117  << std::endl;
118  return 2;
119  }
120 
122  std::cout << "Platform String Count " << s.pcStringCount() << " != " <<
123  testExpectedPlatformStringCount[n] << std::endl;
124  return 3;
125  }
126 
127  std::cout << "Success!" << std::endl << std::endl;
128  return 0;
129 }
130 
131 static int readPayloadChunk(const unsigned char* data, unsigned int size, const char* file) {
132  static const unsigned int bufferSize = 16384; // 16K should be enough for everybody :)
133  unsigned char buffer[bufferSize];
134 
135  // Initialize decompression
136  z_stream stream;
137  stream.zalloc = Z_NULL;
138  stream.zfree = Z_NULL;
139  stream.opaque = Z_NULL;
140  int error = inflateInit(&stream);
141  if (error != Z_OK) {
142  std::cout << "inflateInit() Error " << error << std::endl;
143  return 1;
144  }
145 
146  // Inflate data in one go
147  stream.avail_in = size;
148  stream.next_in = const_cast<unsigned char*>(data);
149  stream.avail_out = bufferSize;
150  stream.next_out = buffer;
151  error = inflate(&stream, Z_FINISH);
152  if (error != Z_STREAM_END) {
153  std::cout << "inflate() Error " << error << std::endl;
154  return 2;
155  }
156  inflateEnd(&stream);
157 
158  // Write buffer to file
159  std::ofstream s(file, std::ios_base::out | std::ios_base::binary);
160  s.write(reinterpret_cast<const char*>(buffer), bufferSize - stream.avail_out);
161 
162  return 0;
163 }
164 
165 static int runForPayload(unsigned int n, bool print, bool printData) {
167  // Get temp file name
168  char tmpFile[] = "/tmp/openraider_unit_test_0";
169  FILE* f;
170  while ((f = fopen(tmpFile, "r")) != NULL) {
171  fclose(f);
172  tmpFile[26]++;
173  }
174 
175  std::cout << "Temporary test file: " << tmpFile << std::endl;
176 
177  int error = readPayloadChunk(testPayloads[n], testSizes[n], tmpFile);
178  if (error == 0) {
179  if (print) {
180  Script s;
181  error = s.load(tmpFile);
182  if (error == 0)
183  error = printDataScript(s, printData);
184  else
185  std::cout << "Error loading script!" << std::endl;
186  } else {
187  error = test(tmpFile, n);
188  }
189  }
190 
191  remove(tmpFile);
192  return error;
193 }
194 
195 int main(int argc, char* argv[]) {
196  bool printHelp = false;
197  bool print = false;
198  bool printData = true;
199  int whichFile = -1;
200 
201  if (argc == 3) {
202  if ((strcmp(argv[1], "--printData") == 0)
203  || (strcmp(argv[1], "--printScript") == 0)) {
204  print = true;
205  if (strcmp(argv[1], "--printScript") == 0) {
206  printData = false;
207  }
208  assert(testPayloadCount < 10);
209  if ((argv[2][0] >= '0')
210  && (static_cast<unsigned int>(argv[2][0]) <= (testPayloadCount + '0'))) {
211  whichFile = argv[2][0] - '0';
212  }
213  } else {
214  printHelp = true;
215  }
216  } else if (argc != 1) {
217  printHelp = true;
218  }
219 
220  if (printHelp) {
221  std::cout << "Usage:" << std::endl;
222  std::cout << "\t" << argv[0] << " [--printData | --printScript] [N | /path]" << std::endl;
223  return 1;
224  }
225 
226  if (print) {
227  // Print single script
228  if (whichFile == -1) {
229  // From given path
230  Script s;
231  assertEqual(s.load(argv[2]), 0);
232  return printDataScript(s, printData);
233  } else {
234  // From payload
235  return runForPayload(static_cast<unsigned int>(whichFile), true, printData);
236  }
237  } else {
238  // Run test on all scripts in payload
239  for (unsigned int i = 0; i < testPayloadCount; i++) {
240  int error = runForPayload(i, false, false);
241  if (error != 0)
242  return error;
243  }
244  return 0;
245  }
246 }
247 
int runScript(unsigned int level)
Definition: Script.cpp:320
unsigned int titleCount()
Definition: Script.cpp:261
static int printDataScript(Script &s, bool strings)
Definition: Script.cpp:49
Start level without weapons.
Definition: Script.h:47
std::string getTitleFilename(unsigned int i)
Definition: Script.cpp:265
Unknown, nothing changes in TR2.
Definition: Script.h:46
Unknown, nothing changes in TR2. Start in Motorboat?
Definition: Script.h:44
static const unsigned int testSizes[testPayloadCount]
Definition: ScriptTest.h:23
Display FMV.
Definition: Script.h:36
Does not compile. PSX?
Definition: Script.h:41
Closes script sequence.
Definition: Script.h:42
std::string getLevelFilename(unsigned int i)
Definition: Script.cpp:238
std::string getLevelName(unsigned int i)
Definition: Script.cpp:233
Lara dies when her feet reach given depth.
Definition: Script.h:50
Included everywhere.
#define registerLambda(x, y)
Definition: Script.cpp:39
static const unsigned int testExpectedPlatformStringCount[testPayloadCount]
Definition: ScriptTest.h:31
Play soundtrack (precedes level opcode)
Definition: Script.h:43
#define assert(x)
Definition: global.h:124
static void error(char *msg)
Definition: commander.c:19
#define printStrings2D(c, cnt, acc, name)
Definition: Script.cpp:25
unsigned int gameStringCount()
Definition: Script.cpp:279
unsigned int pictureCount()
Definition: Script.cpp:243
Tomb Raider 2/3 Script Loader.
Display demo sequence.
Definition: Script.h:40
Display level-completion stats.
Definition: Script.h:39
std::string getPickupString(unsigned int i, unsigned int j)
Definition: Script.cpp:303
Match N-S orientation of Room and animated characters.
Definition: Script.h:49
static const char * testDescription[testPayloadCount]
Definition: ScriptTest.h:15
std::string getPuzzleString(unsigned int i, unsigned int j)
Definition: Script.cpp:297
unsigned int videoCount()
Definition: Script.cpp:270
Kill all enemies to finish the level.
Definition: Script.h:54
#define assertEqual(x, y)
Definition: global.h:130
int load(std::string file)
Definition: Script.cpp:43
Display a cutscene.
Definition: Script.h:38
static int runForPayload(unsigned int n, bool print, bool printData)
Definition: Script.cpp:165
std::string getKeyString(unsigned int i, unsigned int j)
Definition: Script.cpp:309
std::string getGameString(unsigned int i)
Definition: Script.cpp:283
unsigned int pcStringCount()
Definition: Script.cpp:288
Tomb Raider Script Loader Unit Test Header.
Unused in TR2. Or PSX? Used in TR3.
Definition: Script.h:33
If zero, level does not account for secrets.
Definition: Script.h:53
unsigned int cutsceneCount()
Definition: Script.cpp:252
std::string getPictureFilename(unsigned int i)
Definition: Script.cpp:247
Does not compile. PSX?
Definition: Script.h:34
static int readPayloadChunk(const unsigned char *data, unsigned int size, const char *file)
Definition: Script.cpp:131
unsigned int levelCount()
Definition: Script.cpp:229
static const unsigned int testExpectedGameStringCount[testPayloadCount]
Definition: ScriptTest.h:27
Lara starts level without ammo or medi packs.
Definition: Script.h:55
Does not compile. PSX? Used in TR3.
Definition: Script.h:45
std::string getCutsceneFilename(unsigned int i)
Definition: Script.cpp:256
static const unsigned char * testPayloads[testPayloadCount]
Definition: ScriptTest.h:19
Special animation of Lara when level starts.
Definition: Script.h:52
End of game. Show stats, start credits sequence, music ID 52 in TR2.
Definition: Script.h:48
static const unsigned int testPayloadCount
Definition: ScriptTest.h:13
std::string getPCString(unsigned int i)
Definition: Script.cpp:292
Does not compile. PSX?
Definition: Script.h:35
static int test(const char *file, unsigned int n)
Definition: Script.cpp:105
#define printStrings(cnt, acc, name)
Definition: Script.cpp:17
std::string getVideoFilename(unsigned int i)
Definition: Script.cpp:274
Items given to Lara at level start (+1000), or at all secrets found (+0)
Definition: Script.h:51
Start a playable level.
Definition: Script.h:37
Game script loader.
Definition: Script.h:21
int main(int argc, char *argv[])
Definition: Script.cpp:195