Open Source Tomb Raider Engine
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

Script.cpp 8.9KB

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