Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Script.cpp 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*!
  2. * \file src/Script.cpp
  3. * \brief Game script loader
  4. *
  5. * \author xythobuz
  6. */
  7. #include "global.h"
  8. #include "Script.h"
  9. Script::Script() : puzzles(4), pickups(2), keys(4) {
  10. }
  11. Script::~Script() {
  12. }
  13. int Script::load(const char *file) {
  14. BinaryFile f;
  15. if (f.open(file) != 0)
  16. return 1;
  17. version = f.readU32();
  18. char desc[256];
  19. for (int i = 0; i < 256; i++)
  20. desc[i] = f.read8();
  21. description = desc;
  22. uint16_t gameflowSize = f.readU16();
  23. assertEqual(gameflowSize, 128);
  24. firstOption = f.readU32();
  25. titleReplace = f.read32();
  26. onDeathDemoMode = f.readU32();
  27. onDeathInGame = f.readU32();
  28. noInputTime = f.readU32(); // Scaled *100 in TR3
  29. onDemoInterrupt = f.readU32();
  30. onDemoEnd = f.readU32();
  31. // Filler 1 (36 bytes)
  32. f.seek(f.tell() + 36);
  33. numLevels = f.readU16();
  34. numPictures = f.readU16();
  35. numTitles = f.readU16();
  36. numFMVs = f.readU16();
  37. numCutscenes = f.readU16();
  38. numDemos = f.readU16();
  39. titleTrack = f.readU16();
  40. singleLevel = f.read16();
  41. // Filler 2 (32 bytes)
  42. f.seek(f.tell() + 32);
  43. flags = f.readU16();
  44. // Filler 3 (6 bytes)
  45. f.seek(f.tell() + 6);
  46. cypherCode = f.readU8();
  47. language = f.readU8();
  48. secretTrack = f.readU16(); // Zero in TR3, Part of filler or real number?
  49. // Filler 4 (4 bytes)
  50. f.seek(f.tell() + 4);
  51. // Strings
  52. readStringPackage(f, levelNames, numLevels);
  53. readStringPackage(f, pictureFilenames, numPictures);
  54. readStringPackage(f, titleFilenames, numTitles);
  55. readStringPackage(f, fmvFilenames, numFMVs);
  56. readStringPackage(f, levelFilenames, numLevels);
  57. readStringPackage(f, cutsceneFilenames, numCutscenes);
  58. // Level Scripts
  59. readScriptPackage(f, script, numLevels + 1);
  60. numGameStrings = f.readU16();
  61. // More strings...
  62. readStringPackage(f, gameStrings, numGameStrings);
  63. readStringPackage(f, pcStrings, numPCStrings);
  64. readStringPackage(f, puzzles[0], numLevels);
  65. readStringPackage(f, puzzles[1], numLevels);
  66. readStringPackage(f, puzzles[2], numLevels);
  67. readStringPackage(f, puzzles[3], numLevels);
  68. readStringPackage(f, pickups[0], numLevels);
  69. readStringPackage(f, pickups[1], numLevels);
  70. readStringPackage(f, keys[0], numLevels);
  71. readStringPackage(f, keys[1], numLevels);
  72. readStringPackage(f, keys[2], numLevels);
  73. readStringPackage(f, keys[3], numLevels);
  74. return 0;
  75. }
  76. void Script::readStringPackage(BinaryFile &f, std::vector<std::string> &v, unsigned int n) {
  77. uint16_t *offset = new uint16_t[n];
  78. for (unsigned int i = 0; i < n; i++)
  79. offset[i] = f.readU16();
  80. uint16_t numBytes = f.readU16();
  81. char *list = new char[numBytes];
  82. for (uint16_t i = 0; i < numBytes; i++) {
  83. list[i] = f.read8();
  84. if (flags & S_UseSecurityTag) {
  85. list[i] ^= cypherCode;
  86. }
  87. }
  88. for (unsigned int i = 0; i < n; i++) {
  89. std::string tmp(list + offset[i]);
  90. v.push_back(tmp);
  91. }
  92. delete [] list;
  93. delete [] offset;
  94. }
  95. void Script::readScriptPackage(BinaryFile &f, std::vector<std::vector<uint16_t>> &v, unsigned int n) {
  96. uint16_t *offset = new uint16_t[n];
  97. for (unsigned int i = 0; i < n; i++) {
  98. offset[i] = f.readU16();
  99. assertEqual(offset[i] % 2, 0);
  100. }
  101. uint16_t numBytes = f.readU16();
  102. assertEqual(numBytes % 2, 0); // 16 bit opcodes and operands
  103. uint16_t *list = new uint16_t[(numBytes + 6) / 2];
  104. for (uint16_t i = 0; i < (numBytes / 2); i++) {
  105. list[i] = f.readU16();
  106. }
  107. // TR2 for PC and PSX has 6 "filler bytes" hex 13 00 14 00 15 00
  108. // (for TR3 for PSX, the filler is hex 15 00 16 00 17 00 instead)
  109. // at the end of the script block. We need to skip these...
  110. uint16_t hack[3];
  111. hack[0] = f.readU16();
  112. hack[1] = f.readU16();
  113. hack[2] = f.readU16();
  114. if (((hack[0] == 19) && (hack[1] == 20) && (hack[2] == 21))
  115. || ((hack[0] == 21) && (hack[1] == 22) && (hack[2] == 23))) {
  116. list[numBytes / 2] = hack[0];
  117. list[(numBytes / 2) + 1] = hack[1];
  118. list[(numBytes / 2) + 2] = hack[2];
  119. } else {
  120. f.seek(f.tell() - 6);
  121. }
  122. // TR2 for PSX has 64 bytes with unknown content (not zero!) here,
  123. // TR3 for PSX has 40 bytes. We try to identify and skip them...
  124. // This is also currently used to set the platform specific string count
  125. hack[0] = f.readU16();
  126. hack[1] = f.readU16();
  127. hack[2] = f.readU16();
  128. if ((hack[0] == 1) && (hack[1] == 0) && (hack[2] == 864)) {
  129. f.seek(f.tell() + 58);
  130. numPCStrings = 80; // TR2 has 80 PSX Strings
  131. } else if ((hack[0] == 1) && (hack[1] == 0) && (hack[2] == 817)) {
  132. f.seek(f.tell() + 34);
  133. numPCStrings = 80; // TR3 also has 80 PSX Strings
  134. } else {
  135. f.seek(f.tell() - 6);
  136. numPCStrings = 41;
  137. }
  138. for (unsigned int i = 0; i < n; i++) {
  139. unsigned int end = offset[i] / 2;
  140. // We need to detect the OP_END opcode marking the end of a
  141. // script sequence (like the '\0' for the strings).
  142. // However, the numerical value of OP_END could also be used
  143. // as an operand for another opcode, so we have to check for this
  144. bool readingOperand = false;
  145. while (readingOperand || (list[end] != OP_END)) {
  146. if (readingOperand) {
  147. readingOperand = false;
  148. end++;
  149. } else {
  150. if (opcodeHasOperand[list[end]]) {
  151. readingOperand = true;
  152. }
  153. end++;
  154. }
  155. }
  156. end++;
  157. std::vector<uint16_t> tmp;
  158. for (unsigned int a = (offset[i] / 2); a < end; a++)
  159. tmp.push_back(list[a]);
  160. v.push_back(tmp);
  161. }
  162. delete [] list;
  163. delete [] offset;
  164. }
  165. unsigned int Script::levelCount() {
  166. return numLevels;
  167. }
  168. std::string Script::getLevelName(unsigned int i) {
  169. assert(i < numLevels);
  170. return levelNames.at(i);
  171. }
  172. std::string Script::getLevelFilename(unsigned int i) {
  173. assert(i < numLevels);
  174. return levelFilenames.at(i);
  175. }
  176. unsigned int Script::pictureCount() {
  177. return numPictures;
  178. }
  179. std::string Script::getPictureFilename(unsigned int i) {
  180. assert(i < numPictures);
  181. return pictureFilenames.at(i);
  182. }
  183. unsigned int Script::cutsceneCount() {
  184. return numCutscenes;
  185. }
  186. std::string Script::getCutsceneFilename(unsigned int i) {
  187. assert(i < numCutscenes);
  188. return cutsceneFilenames.at(i);
  189. }
  190. unsigned int Script::titleCount() {
  191. return numTitles;
  192. }
  193. std::string Script::getTitleFilename(unsigned int i) {
  194. assert(i < numTitles);
  195. return titleFilenames.at(i);
  196. }
  197. unsigned int Script::videoCount() {
  198. return numFMVs;
  199. }
  200. std::string Script::getVideoFilename(unsigned int i) {
  201. assert(i < numFMVs);
  202. return fmvFilenames.at(i);
  203. }
  204. unsigned int Script::gameStringCount() {
  205. return numGameStrings;
  206. }
  207. std::string Script::getGameString(unsigned int i) {
  208. assert(i < numGameStrings);
  209. return gameStrings.at(i);
  210. }
  211. unsigned int Script::pcStringCount() {
  212. return numPCStrings;
  213. }
  214. std::string Script::getPCString(unsigned int i) {
  215. assert(i < numPCStrings);
  216. return pcStrings.at(i);
  217. }
  218. std::string Script::getPuzzleString(unsigned int i, unsigned int j) {
  219. assert(i < 4);
  220. assert(j < numLevels);
  221. return puzzles.at(i).at(j);
  222. }
  223. std::string Script::getPickupString(unsigned int i, unsigned int j) {
  224. assert(i < 2);
  225. assert(j < numLevels);
  226. return pickups.at(i).at(j);
  227. }
  228. std::string Script::getKeyString(unsigned int i, unsigned int j) {
  229. assert(i < 4);
  230. assert(j < numLevels);
  231. return keys.at(i).at(j);
  232. }
  233. void Script::registerScriptHandler(ScriptOpCode op, std::function<int (bool, uint16_t)> func) {
  234. assert(op < OP_UNKNOWN);
  235. scriptHandlers[op] = func;
  236. }
  237. int Script::runScript(unsigned int level) {
  238. assert(level < (numLevels + 1));
  239. std::vector<uint16_t> s = script.at(level);
  240. for (unsigned int i = 0; i < s.size(); i++) {
  241. uint16_t opcode = s.at(i);
  242. if (opcode >= OP_UNKNOWN) {
  243. return 1;
  244. }
  245. uint16_t operand = 0;
  246. if (opcodeHasOperand[opcode]) {
  247. if ((i + 1) >= s.size())
  248. return 2; // Can't read operand!
  249. operand = s.at(++i);
  250. }
  251. if (scriptHandlers[opcode]) {
  252. int error = scriptHandlers[opcode](opcodeHasOperand[opcode], operand);
  253. if (error != 0)
  254. return error;
  255. } else {
  256. return 3;
  257. }
  258. }
  259. return 0;
  260. }