Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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. }