ff7_world_engine.cpp 11 KB

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