ff7_world_engine.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. #include "ff7_world_engine.h"
  2. #include "ff7_world_disassembler.h"
  3. #include "ff7_world_codegen.h"
  4. #include <iostream>
  5. #include <sstream>
  6. #include <boost/format.hpp>
  7. #include "make_unique.h"
  8. #define GET(vertex) (boost::get(boost::vertex_name, g, vertex))
  9. std::unique_ptr<Disassembler> FF7::FF7WorldEngine::getDisassembler(InstVec &insts)
  10. {
  11. return std::make_unique<FF7WorldDisassembler>(this, insts, mScriptNumber);
  12. }
  13. std::unique_ptr<CodeGenerator> FF7::FF7WorldEngine::getCodeGenerator(const InstVec& /*insts*/, std::ostream &output)
  14. {
  15. return std::make_unique<FF7WorldCodeGenerator>(this, output);
  16. }
  17. void FF7::FF7WorldEngine::postCFG(InstVec&, Graph g)
  18. {
  19. /*
  20. VertexRange vr = boost::vertices(g);
  21. for (VertexIterator v = vr.first; v != vr.second; ++v)
  22. {
  23. GroupPtr gr = GET(*v);
  24. // If this group is the last instruction and its an unconditional jump
  25. if ((*gr->_start)->_address == insts.back()->_address && insts.back()->isUncondJump())
  26. {
  27. // Then assume its an infinite do { } while(true) loop that wraps part of the script
  28. gr->_type = kDoWhileCondGroupType;
  29. }
  30. }*/
  31. }
  32. void FF7::FF7WorldEngine::getVariants(std::vector<std::string>&) const
  33. {
  34. }
  35. void FF7::FF7WorldLoadBankInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator*)
  36. {
  37. stack.push(new BankValue("Read(" + _params[0]->getString() + ")"));
  38. }
  39. void FF7::FF7WorldLoadInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator*)
  40. {
  41. stack.push(new VarValue(_params[0]->getString()));
  42. }
  43. void FF7::FF7SubStackInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator*)
  44. {
  45. std::string op;
  46. switch (_opcode)
  47. {
  48. case 0x41:
  49. op = "-";
  50. break;
  51. case 0x40:
  52. op = "+";
  53. break;
  54. case 0x80:
  55. op = "&&";
  56. break;
  57. case 0xa0:
  58. op = "||";
  59. break;
  60. case 0xc0:
  61. op = "|";
  62. break;
  63. case 0x15: // neg
  64. case 0x17: // not
  65. stack.push(stack.pop()->negate());
  66. return;
  67. case 0x30:
  68. op = "*";
  69. break;
  70. case 0x60:
  71. op = "<";
  72. break;
  73. case 0x61:
  74. op = ">";
  75. break;
  76. case 0x62:
  77. op = "<=";
  78. break;
  79. case 0x63:
  80. op = ">=";
  81. break;
  82. case 0x0b0:
  83. op = "&";
  84. break;
  85. case 0x51:
  86. op = "<<";
  87. break;
  88. default:
  89. op = "unknown_operation";
  90. }
  91. std::string strValue = stack.pop()->getString() + " " + op + " " + stack.pop()->getString();
  92. stack.push(new VarValue(strValue));
  93. }
  94. void FF7::FF7WorldStoreInstruction::processInst(Function&, ValueStack &stack, Engine*, CodeGenerator *codeGen)
  95. {
  96. std::string strValue = stack.pop()->getString();
  97. // If the bank address is from a load bank instruction, then we only want
  98. // the bank address, not whats *at* the bank address
  99. ValuePtr bankValue = stack.pop();
  100. std::string bankAddr = bankValue->getString();
  101. codeGen->addOutputLine("Write(" + bankAddr + ", " + strValue + ");");
  102. }
  103. void FF7::FF7WorldStackInstruction::processInst(Function&, ValueStack&, Engine*, CodeGenerator*)
  104. {
  105. }
  106. void FF7::FF7WorldCondJumpInstruction::processInst(Function&, ValueStack&, Engine*, CodeGenerator*)
  107. {
  108. }
  109. uint32 FF7::FF7WorldCondJumpInstruction::getDestAddress() const
  110. {
  111. return 0x200 + _params[0]->getUnsigned();
  112. }
  113. std::ostream& FF7::FF7WorldCondJumpInstruction::print(std::ostream &output) const
  114. {
  115. Instruction::print(output);
  116. return output;
  117. }
  118. bool FF7::FF7WorldUncondJumpInstruction::isFuncCall() const
  119. {
  120. return _isCall;
  121. }
  122. bool FF7::FF7WorldUncondJumpInstruction::isUncondJump() const
  123. {
  124. return !_isCall;
  125. }
  126. uint32 FF7::FF7WorldUncondJumpInstruction::getDestAddress() const
  127. {
  128. // the world map while loops are incorrect without +1'in this, but
  129. // doing that will break some if elses.. hmm
  130. return 0x200 + _params[0]->getUnsigned();// +1; // TODO: +1 to skip param?
  131. }
  132. std::ostream& FF7::FF7WorldUncondJumpInstruction::print(std::ostream &output) const
  133. {
  134. Instruction::print(output);
  135. // output << " (Jump target address: 0x" << std::hex << getDestAddress() << std::dec << ")";
  136. return output;
  137. }
  138. void FF7::FF7WorldUncondJumpInstruction::processInst(Function& , ValueStack&, Engine*, CodeGenerator*)
  139. {
  140. }
  141. void FF7::FF7WorldKernelCallInstruction::processInst(Function& , ValueStack &stack, Engine*, CodeGenerator *codeGen)
  142. {
  143. std::string strFunc;
  144. switch (_opcode)
  145. {
  146. case 0x203:
  147. strFunc = "return;";
  148. break;
  149. case 0x317:
  150. strFunc = "TriggerBattle(" + stack.pop()->getString() + ");";
  151. break;
  152. case 0x324:
  153. // x, y, w, h
  154. strFunc = "SetWindowDimensions(" +
  155. stack.pop()->getString() + ", " +
  156. stack.pop()->getString() + ", " +
  157. stack.pop()->getString() + ", " +
  158. stack.pop()->getString() + ");";
  159. break;
  160. case 0x32D:
  161. strFunc = "WaitForWindowReady();";
  162. break;
  163. case 0x325:
  164. strFunc = "SetWindowMessage(" + stack.pop()->getString() + ");";
  165. break;
  166. case 0x333:
  167. strFunc = "Unknown333(" +
  168. stack.pop()->getString() + ", " +
  169. stack.pop()->getString() + ");";
  170. break;
  171. case 0x308:
  172. strFunc = "SetActiveEntityMeshCoordinates(" +
  173. stack.pop()->getString() + ", " +
  174. stack.pop()->getString() + ");";
  175. break;
  176. case 0x309:
  177. strFunc = "SetActiveEntityMeshCoordinatesInMesh(" +
  178. stack.pop()->getString() + ", " +
  179. stack.pop()->getString() + ");";
  180. break;
  181. case 0x32e:
  182. strFunc = "WaitForMessageAcknowledge();";
  183. break;
  184. case 0x32c:
  185. // Mode, Permanency
  186. strFunc = "SetWindowParameters(" +
  187. stack.pop()->getString() + ", " +
  188. stack.pop()->getString() + ");";
  189. break;
  190. case 0x318:
  191. strFunc = "EnterFieldScene(" +
  192. stack.pop()->getString() + ", " +
  193. stack.pop()->getString() + ");";
  194. break;
  195. case 0x348:
  196. strFunc = "FadeIn(" +
  197. stack.pop()->getString() + ", " +
  198. stack.pop()->getString() + ");";
  199. break;
  200. case 0x33b:
  201. strFunc = "FadeOut(" +
  202. stack.pop()->getString() + ", " +
  203. stack.pop()->getString() + ");";
  204. break;
  205. case 0x310:
  206. strFunc = "SetActivePoint(" +
  207. stack.pop()->getString() + ", " +
  208. stack.pop()->getString() + ");";
  209. break;
  210. case 0x311:
  211. strFunc = "SetLightMeshCoordinates(" +
  212. stack.pop()->getString() + ", " +
  213. stack.pop()->getString() + ");";
  214. break;
  215. case 0x312:
  216. strFunc = "SetLightMeshCoordinatesInMesh(" +
  217. stack.pop()->getString() + ", " +
  218. stack.pop()->getString() + ");";
  219. break;
  220. case 0x31D:
  221. strFunc = "PlaySoundEffect(" + stack.pop()->getString() + ");";
  222. break;
  223. case 0x328:
  224. strFunc = "SetActiveEntityDirection(" + stack.pop()->getString() + ");";
  225. break;
  226. case 0x336: // honours walk mesh
  227. case 0x303:
  228. strFunc = "SetActiveEntityMovespeed(" + stack.pop()->getString() + ");";
  229. break;
  230. case 0x304:
  231. strFunc = "SetActiveEntityDirectionAndFacing(" + stack.pop()->getString() + ");";
  232. break;
  233. case 0x32b:
  234. strFunc = "SetBattleLock(" + stack.pop()->getString() + ");";
  235. break;
  236. case 0x305:
  237. strFunc = "SetWaitFrames(" + stack.pop()->getString() + ");";
  238. break;
  239. case 0x33e:
  240. strFunc = "Unknown_AKAO(" + stack.pop()->getString() + ");";
  241. break;
  242. case 0x306:
  243. strFunc = "Wait();";
  244. break;
  245. case 0x350:
  246. strFunc = "SetMeteorTexture(" + stack.pop()->getString() + ");";
  247. break;
  248. case 0x34b:
  249. {
  250. std::string type = stack.pop()->getString();
  251. switch (std::stoi(type))
  252. {
  253. case 0:
  254. type = "yellow";
  255. break;
  256. case 1:
  257. type = "green";
  258. break;
  259. case 2:
  260. type = "blue";
  261. break;
  262. case 3:
  263. type = "black";
  264. break;
  265. case 4:
  266. type = "gold";
  267. break;
  268. }
  269. strFunc = "SetChocoboType(" + type + ");";
  270. }
  271. break;
  272. case 0x34c:
  273. {
  274. std::string type = stack.pop()->getString();
  275. switch (std::stoi(type))
  276. {
  277. case 0:
  278. type = "red";
  279. break;
  280. case 1:
  281. type = "blue";
  282. break;
  283. // Hack - not really supported, but works
  284. case -1:
  285. type = "gold";
  286. break;
  287. case -2:
  288. type = "black";
  289. break;
  290. }
  291. strFunc = "SetSubmarineColor(" + type + ");";
  292. }
  293. break;
  294. case 0x349:
  295. {
  296. std::string type = stack.pop()->getString();
  297. std::string comment = "// ";
  298. switch (std::stoi(type))
  299. {
  300. case 0:
  301. comment += "before temple of the ancients,";
  302. break;
  303. case 1:
  304. comment += "after temple of the ancients";
  305. break;
  306. case 2:
  307. comment += " after ultimate weapon appears,";
  308. break;
  309. case 3:
  310. comment += "after mideel";
  311. break;
  312. case 4:
  313. comment += "after ultimate weapon killed";
  314. break;
  315. default:
  316. comment += "??";
  317. break;
  318. }
  319. strFunc = "SetWorldProgress(" + type + "); " +comment;
  320. }
  321. break;
  322. case 0x300:
  323. {
  324. std::string type = stack.pop()->getString();
  325. std::string comment = "// ";
  326. try
  327. {
  328. switch (std::stoi(type))
  329. {
  330. case 0: comment += "Cloud"; break;
  331. case 1: comment += "Tifa?"; break;
  332. case 2: comment += "Cid?"; break;
  333. case 3: comment += "Ultimate Weapon"; break;
  334. case 4: comment += "Unknown"; break;
  335. case 5: comment += "Unknown"; break;
  336. case 6: comment += "Unknown"; break;
  337. case 7: comment += "Unknown"; break;
  338. case 8: comment += "Unknown"; break;
  339. case 9: comment += "Unknown"; break;
  340. case 10: comment += "Unknown"; break;
  341. case 11: comment += "Highwind"; break;
  342. case 12: comment += "Unknown"; break;
  343. case 13: comment += "Submarine"; break;
  344. case 14: comment += "Unknown"; break;
  345. case 15: comment += "Unknown"; break;
  346. case 16: comment += "Unknown"; break;
  347. case 17: comment += "Unknown"; break;
  348. case 18: comment += "Unknown"; break;
  349. case 19: comment += "Chocobo"; break;
  350. case 20: comment += "Unknown"; break;
  351. case 21: comment += "Unknown"; break;
  352. case 22: comment += "Unknown"; break;
  353. case 23: comment += "Unknown"; break;
  354. case 24: comment += "Unknown"; break;
  355. case 25: comment += "Unknown"; break;
  356. default:
  357. comment += "??";
  358. break;
  359. }
  360. }
  361. catch (std::invalid_argument&)
  362. {
  363. }
  364. strFunc = "LoadModel(" + type + "); " + comment;
  365. }
  366. break;
  367. case 0x307:
  368. strFunc = "SetControlLock(" + stack.pop()->getString() + ");";
  369. break;
  370. case 0x30c:
  371. strFunc = "EnterVehicle();";
  372. break;
  373. default:
  374. strFunc = "kernel_unknown_" + AddressValue(_opcode).getString() + "();";
  375. break;
  376. }
  377. codeGen->addOutputLine(strFunc);
  378. }
  379. void FF7::FF7WorldNoOutputInstruction::processInst(Function&, ValueStack&, Engine*, CodeGenerator*)
  380. {
  381. }