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.

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