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 9.6KB

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