FieldModelInstruction.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * V-Gears
  3. * Copyright (C) 2022 V-Gears Team
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <iostream>
  19. #include <sstream>
  20. #include <boost/format.hpp>
  21. #include "decompiler/field/instruction/FieldModelInstruction.h"
  22. #include "decompiler/field/FieldEngine.h"
  23. #include "decompiler/field/FieldCodeGenerator.h"
  24. #include "decompiler/field/FieldDisassembler.h"
  25. void FF7::FieldModelInstruction::ProcessInst(
  26. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  27. ){
  28. FF7::FieldEngine& eng = static_cast<FF7::FieldEngine&>(*engine);
  29. FunctionMetaData md(func.metadata);
  30. switch (_opcode){
  31. case OPCODES::JOIN: ProcessJOIN(code_gen); break;
  32. case OPCODES::SPLIT: ProcessSPLIT(code_gen); break;
  33. case OPCODES::BLINK: code_gen->WriteTodo(md.GetEntityName(), "BLINK"); break;
  34. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::EYETX:
  35. code_gen->WriteTodo(md.GetEntityName(), "EYETX");
  36. break;
  37. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::TRNSP:
  38. code_gen->WriteTodo(md.GetEntityName(), "TRNSP");
  39. break;
  40. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::AMBNT:
  41. code_gen->WriteTodo(md.GetEntityName(), "AMBNT");
  42. break;
  43. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown03:
  44. code_gen->WriteTodo(md.GetEntityName(), "Unknown03");
  45. break;
  46. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown04:
  47. code_gen->WriteTodo(md.GetEntityName(), "Unknown04");
  48. break;
  49. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown05:
  50. code_gen->WriteTodo(md.GetEntityName(), "Unknown05");
  51. break;
  52. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::LIGHT:
  53. code_gen->WriteTodo(md.GetEntityName(), "LIGHT");
  54. break;
  55. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown07:
  56. code_gen->WriteTodo(md.GetEntityName(), "Unknown07");
  57. break;
  58. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown08:
  59. code_gen->WriteTodo(md.GetEntityName(), "Unknown08");
  60. break;
  61. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown09:
  62. code_gen->WriteTodo(md.GetEntityName(), "Unknown09");
  63. break;
  64. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::SBOBJ:
  65. code_gen->WriteTodo(md.GetEntityName(), "SBOBJ");
  66. break;
  67. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown0B:
  68. code_gen->WriteTodo(md.GetEntityName(), "Unknown0B");
  69. break;
  70. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown0C:
  71. code_gen->WriteTodo(md.GetEntityName(), "Unknown0C");
  72. break;
  73. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::SHINE:
  74. code_gen->WriteTodo(md.GetEntityName(), "SHINE");
  75. break;
  76. case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::RESET:
  77. code_gen->WriteTodo(md.GetEntityName(), "RESET");
  78. break;
  79. case OPCODES::KAWIW: code_gen->WriteTodo(md.GetEntityName(), "KAWIW"); break;
  80. case OPCODES::PMOVA: code_gen->WriteTodo(md.GetEntityName(), "PMOVA"); break;
  81. case OPCODES::PDIRA: code_gen->WriteTodo(md.GetEntityName(), "PDIRA"); break;
  82. case OPCODES::PTURA: code_gen->WriteTodo(md.GetEntityName(), "PTURA"); break;
  83. case OPCODES::PGTDR: code_gen->WriteTodo(md.GetEntityName(), "PGTDR"); break;
  84. case OPCODES::PXYZI: code_gen->WriteTodo(md.GetEntityName(), "PXYZI"); break;
  85. case OPCODES::TLKON: ProcessTLKON(code_gen, md.GetEntityName()); break;
  86. case OPCODES::PC: ProcessPC(code_gen, md.GetEntityName()); break;
  87. case OPCODES::opCodeCHAR: ProcessCHAR(code_gen, md.GetEntityName()); break;
  88. case OPCODES::DFANM: ProcessDFANM(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
  89. case OPCODES::ANIME1:
  90. ProcessANIME1(code_gen, md.GetEntityName(), md.GetCharacterId());
  91. break;
  92. case OPCODES::VISI: ProcessVISI(code_gen, md.GetEntityName()); break;
  93. case OPCODES::XYZI: ProcessXYZI(code_gen, md.GetEntityName()); break;
  94. case OPCODES::XYI: code_gen->WriteTodo(md.GetEntityName(), "XYI"); break;
  95. case OPCODES::XYZ: code_gen->WriteTodo(md.GetEntityName(), "XYZ"); break;
  96. case OPCODES::MOVE: ProcessMOVE(code_gen, md.GetEntityName()); break;
  97. case OPCODES::CMOVE: code_gen->WriteTodo(md.GetEntityName(), "CMOVE"); break;
  98. case OPCODES::MOVA: code_gen->WriteTodo(md.GetEntityName(), "MOVA"); break;
  99. case OPCODES::TURA: code_gen->WriteTodo(md.GetEntityName(), "TURA"); break;
  100. case OPCODES::ANIMW: code_gen->WriteTodo(md.GetEntityName(), "ANIMW"); break;
  101. case OPCODES::FMOVE: code_gen->WriteTodo(md.GetEntityName(), "FMOVE"); break;
  102. case OPCODES::ANIME2: code_gen->WriteTodo(md.GetEntityName(), "ANIME2"); break;
  103. case OPCODES::ANIM_1: code_gen->WriteTodo(md.GetEntityName(), "ANIM_1"); break;
  104. case OPCODES::CANIM1: code_gen->WriteTodo(md.GetEntityName(), "CANIM1"); break;
  105. case OPCODES::CANM_1: code_gen->WriteTodo(md.GetEntityName(), "CANM_1"); break;
  106. case OPCODES::MSPED: ProcessMSPED(code_gen, md.GetEntityName()); break;
  107. case OPCODES::DIR: ProcessDIR(code_gen, md.GetEntityName()); break;
  108. case OPCODES::TURNGEN: ProcessTURNGEN(code_gen, md.GetEntityName()); break;
  109. case OPCODES::TURN: code_gen->WriteTodo(md.GetEntityName(), "TURN"); break;
  110. case OPCODES::DIRA: code_gen->WriteTodo(md.GetEntityName(), "DIRA"); break;
  111. case OPCODES::GETDIR: code_gen->WriteTodo(md.GetEntityName(), "GETDIR"); break;
  112. case OPCODES::GETAXY: code_gen->WriteTodo(md.GetEntityName(), "GETAXY"); break;
  113. case OPCODES::GETAI: ProcessGETAI(code_gen, eng); break;
  114. case OPCODES::ANIM_2:
  115. ProcessANIM_2(code_gen, md.GetEntityName(), md.GetCharacterId());
  116. break;
  117. case OPCODES::CANIM2:
  118. ProcessCANIM2(code_gen, md.GetEntityName(), md.GetCharacterId());
  119. break;
  120. case OPCODES::CANM_2:
  121. ProcessCANM_2(code_gen, md.GetEntityName(), md.GetCharacterId());
  122. break;
  123. case OPCODES::ASPED: code_gen->WriteTodo(md.GetEntityName(), "ASPED"); break;
  124. case OPCODES::CC: ProcessCC(code_gen, eng); break;
  125. case OPCODES::JUMP: ProcessJUMP(code_gen, md.GetEntityName()); break;
  126. case OPCODES::AXYZI: ProcessAXYZI(code_gen); break;
  127. case OPCODES::LADER: ProcessLADER(code_gen, md.GetEntityName()); break;
  128. case OPCODES::OFST: ProcessOFST(code_gen, md.GetEntityName()); break;
  129. case OPCODES::OFSTW:
  130. code_gen->AddOutputLine("self." + md.GetEntityName() + ":offset_sync()");
  131. break;
  132. case OPCODES::TALKR: code_gen->WriteTodo(md.GetEntityName(), "TALKR"); break;
  133. case OPCODES::SLIDR: code_gen->WriteTodo(md.GetEntityName(), "SLIDR"); break;
  134. case OPCODES::SOLID: ProcessSOLID(code_gen, md.GetEntityName()); break;
  135. case OPCODES::TLKR2: code_gen->WriteTodo(md.GetEntityName(), "TLKR2"); break;
  136. case OPCODES::SLDR2: code_gen->WriteTodo(md.GetEntityName(), "SLDR2"); break;
  137. case OPCODES::CCANM: code_gen->WriteTodo(md.GetEntityName(), "CCANM"); break;
  138. case OPCODES::FCFIX: code_gen->WriteTodo(md.GetEntityName(), "FCFIX"); break;
  139. case OPCODES::ANIMB: code_gen->WriteTodo(md.GetEntityName(), "ANIMB"); break;
  140. case OPCODES::TURNW: code_gen->WriteTodo(md.GetEntityName(), "TURNW"); break;
  141. default:
  142. code_gen->AddOutputLine(FF7::FieldCodeGenerator::FormatInstructionNotImplemented(
  143. md.GetEntityName(), _address, _opcode
  144. ));
  145. }
  146. }
  147. void FF7::FieldModelInstruction::ProcessJOIN(CodeGenerator* code_gen){
  148. code_gen->AddOutputLine("join_party(" + std::to_string(_params[0]->getUnsigned()) + ")");
  149. }
  150. void FF7::FieldModelInstruction::ProcessSPLIT(CodeGenerator* code_gen){
  151. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  152. const float scale = 128.0f * cg->GetScaleFactor();
  153. const auto& ax = FF7::FieldCodeGenerator::FormatValueOrVariable(
  154. cg->GetFormatter(), _params[0]->getUnsigned(), _params[6]->getSigned(),
  155. FF7::FieldCodeGenerator::ValueType::Float, scale
  156. );
  157. const auto& ay = FF7::FieldCodeGenerator::FormatValueOrVariable(
  158. cg->GetFormatter(), _params[1]->getUnsigned(), _params[7]->getSigned(),
  159. FF7::FieldCodeGenerator::ValueType::Float, scale
  160. );
  161. const auto& ar = FF7::FieldCodeGenerator::FormatValueOrVariable(
  162. cg->GetFormatter(), _params[2]->getUnsigned(), _params[8]->getSigned(),
  163. FF7::FieldCodeGenerator::ValueType::Float, scale
  164. );
  165. const auto& bx = FF7::FieldCodeGenerator::FormatValueOrVariable(
  166. cg->GetFormatter(), _params[3]->getUnsigned(), _params[9]->getSigned(),
  167. FF7::FieldCodeGenerator::ValueType::Float, scale
  168. );
  169. const auto& by = FF7::FieldCodeGenerator::FormatValueOrVariable(
  170. cg->GetFormatter(), _params[4]->getUnsigned(), _params[10]->getSigned(),
  171. FF7::FieldCodeGenerator::ValueType::Float, scale
  172. );
  173. const auto& br = FF7::FieldCodeGenerator::FormatValueOrVariable(
  174. cg->GetFormatter(), _params[5]->getUnsigned(), _params[11]->getSigned(),
  175. FF7::FieldCodeGenerator::ValueType::Float, scale
  176. );
  177. const auto& speed = _params[12]->getUnsigned();
  178. code_gen->AddOutputLine((
  179. boost::format("split_party(%1%, %2%, %3%, %4%, %5%, %6%, %7%)")
  180. % ax % ay % ar % bx % by % br % speed
  181. ).str());
  182. }
  183. void FF7::FieldModelInstruction::ProcessTLKON(CodeGenerator* code_gen, const std::string& entity){
  184. code_gen->AddOutputLine((
  185. boost::format("self.%1%:set_talkable(%2%)")
  186. % entity % FF7::FieldCodeGenerator::FormatInvertedBool(_params[0]->getUnsigned())
  187. ).str());
  188. }
  189. void FF7::FieldModelInstruction::ProcessPC(CodeGenerator* code_gen, const std::string& entity){
  190. code_gen->AddOutputLine(
  191. (boost::format("set_entity_to_character(\"%1%\", \"%1%\")") % entity).str()
  192. );
  193. }
  194. void FF7::FieldModelInstruction::ProcessCHAR(CodeGenerator* code_gen, const std::string& entity){
  195. code_gen->AddOutputLine(
  196. (boost::format("self.%1% = entity_manager:get_entity(\"%1%\")") % entity).str()
  197. );
  198. }
  199. void FF7::FieldModelInstruction::ProcessDFANM(
  200. CodeGenerator* code_gen, const std::string& entity, int char_id
  201. ){
  202. // ID will be fixed-up downstream.
  203. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  204. auto animation_id = _params[0]->getUnsigned();
  205. // TODO: check for zero.
  206. auto speed = 1.0f / _params[1]->getUnsigned();
  207. code_gen->AddOutputLine((
  208. boost::format("self.%1%:set_default_animation(\"%2%\") -- speed %3%")
  209. % entity % cg->GetFormatter().AnimationName(char_id, animation_id) % speed
  210. ).str());
  211. code_gen->AddOutputLine((
  212. boost::format("self.%1%:play_animation(\"%2%\")")
  213. % entity % cg->GetFormatter().AnimationName(char_id, animation_id)
  214. ).str());
  215. }
  216. void FF7::FieldModelInstruction::ProcessANIME1(
  217. CodeGenerator* code_gen, const std::string& entity, int char_id
  218. ){
  219. // ID will be fixed-up downstream.
  220. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  221. auto animation_id = _params[0]->getUnsigned();
  222. // TODO: check for zero.
  223. auto speed = 1.0f / _params[1]->getUnsigned();
  224. code_gen->AddOutputLine((
  225. boost::format("self.%1%:play_animation(\"%2%\") -- speed %3%")
  226. % entity % cg->GetFormatter().AnimationName(char_id, animation_id) % speed
  227. ).str());
  228. code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
  229. }
  230. void FF7::FieldModelInstruction::ProcessVISI(CodeGenerator* code_gen, const std::string& entity){
  231. code_gen->AddOutputLine((
  232. boost::format("self.%1%:set_visible(%2%)")
  233. % entity % FF7::FieldCodeGenerator::FormatBool(_params[0]->getUnsigned())
  234. ).str());
  235. }
  236. void FF7::FieldModelInstruction::ProcessXYZI(CodeGenerator* code_gen, const std::string& entity){
  237. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  238. const float scale = 128.0f * cg->GetScaleFactor();
  239. const auto& x = FF7::FieldCodeGenerator::FormatValueOrVariable(
  240. cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned(),
  241. FF7::FieldCodeGenerator::ValueType::Float, scale
  242. );
  243. const auto& y = FF7::FieldCodeGenerator::FormatValueOrVariable(
  244. cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned(),
  245. FF7::FieldCodeGenerator::ValueType::Float, scale
  246. );
  247. const auto& z = FF7::FieldCodeGenerator::FormatValueOrVariable(
  248. cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getSigned(),
  249. FF7::FieldCodeGenerator::ValueType::Float, scale
  250. );
  251. const auto& triangle_id = FF7::FieldCodeGenerator::FormatValueOrVariable(
  252. cg->GetFormatter(), _params[3]->getUnsigned(), _params[7]->getUnsigned()
  253. );
  254. code_gen->AddOutputLine((
  255. boost::format("self.%1%:set_position(%2%, %3%, %4%) -- triangle ID %5%")
  256. % entity % x % y % z % triangle_id
  257. ).str());
  258. }
  259. void FF7::FieldModelInstruction::ProcessMOVE(CodeGenerator* code_gen, const std::string& entity){
  260. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  261. const float scale = 128.0f * cg->GetScaleFactor();
  262. const auto& x = FF7::FieldCodeGenerator::FormatValueOrVariable(
  263. cg->GetFormatter(), _params[0]->getUnsigned(), _params[2]->getSigned(),
  264. FF7::FieldCodeGenerator::ValueType::Float, scale
  265. );
  266. const auto& y = FF7::FieldCodeGenerator::FormatValueOrVariable(
  267. cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getSigned(),
  268. FF7::FieldCodeGenerator::ValueType::Float, scale
  269. );
  270. code_gen->AddOutputLine(
  271. (boost::format("self.%1%:move_to_position(%2%, %3%)") % entity % x % y).str()
  272. );
  273. code_gen->AddOutputLine((boost::format("self.%1%:move_sync()") % entity).str());
  274. }
  275. void FF7::FieldModelInstruction::ProcessMSPED(CodeGenerator* code_gen, const std::string& entity){
  276. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  277. const float scale = 128.0f * cg->GetScaleFactor();
  278. const auto& speed = FF7::FieldCodeGenerator::FormatValueOrVariable(
  279. cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned(),
  280. FF7::FieldCodeGenerator::ValueType::Float, 256.0f * scale / 30.0f
  281. );
  282. code_gen->AddOutputLine(
  283. (boost::format("self.%1%:set_move_auto_speed(%2%)") % entity % speed).str()
  284. );
  285. }
  286. void FF7::FieldModelInstruction::ProcessDIR(CodeGenerator* code_gen, const std::string& entity){
  287. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  288. const auto& degrees = FF7::FieldCodeGenerator::FormatValueOrVariable(
  289. cg->GetFormatter(), _params[0]->getUnsigned(), _params[1]->getUnsigned(),
  290. FF7::FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
  291. );
  292. code_gen->AddOutputLine((boost::format("self.%1%:set_rotation(%2%)") % entity % degrees).str());
  293. }
  294. void FF7::FieldModelInstruction::ProcessTURNGEN(CodeGenerator* code_gen, const std::string& entity){
  295. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  296. const auto& degrees = FF7::FieldCodeGenerator::FormatValueOrVariable(
  297. cg->GetFormatter(), _params[1]->getUnsigned(), _params[2]->getUnsigned(),
  298. FF7::FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
  299. );
  300. std::string direction;
  301. switch (_params[3]->getUnsigned()){
  302. case 0: direction = "Entity.CLOCKWISE"; break;
  303. case 1: direction = "Entity.ANTICLOCKWISE"; break;
  304. case 2: direction = "Entity.CLOSEST"; break;
  305. // Default to closest:
  306. default: direction = "Entity.CLOSEST"; break;
  307. }
  308. auto steps = _params[4]->getUnsigned();
  309. std::string step_type;
  310. switch (_params[5]->getUnsigned()){
  311. case 1: step_type = "Entity.LINEAR"; break;
  312. case 2: step_type = "Entity.SMOOTH"; break;
  313. // Default to smooth
  314. default: step_type = "Entity.SMOOTH"; break;
  315. }
  316. const float scaled_steps = static_cast<float>(steps) / 30.0f;
  317. code_gen->AddOutputLine((
  318. boost::format("self.%1%:turn_to_direction(%2%, %3%, %4%, %5%)")
  319. % entity % degrees % direction % step_type % scaled_steps
  320. ).str());
  321. code_gen->AddOutputLine((boost::format("self.%1%:turn_sync()") % entity).str());
  322. }
  323. void FF7::FieldModelInstruction::ProcessGETAI(CodeGenerator* code_gen, const FieldEngine& engine){
  324. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  325. // TODO: check for assignment to literal.
  326. const auto& variable = FF7::FieldCodeGenerator::FormatValueOrVariable(
  327. cg->GetFormatter(), _params[1]->getUnsigned(), _params[3]->getUnsigned()
  328. );
  329. const auto& entity = engine.EntityByIndex(_params[2]->getUnsigned());
  330. code_gen->AddOutputLine(
  331. (boost::format("%1% = entity_manager:get_entity(\"%2%\"):get_move_triangle_id()")
  332. % variable % entity.GetName()
  333. ).str());
  334. }
  335. void FF7::FieldModelInstruction::ProcessANIM_2(
  336. CodeGenerator* code_gen, const std::string& entity, int char_id
  337. ){
  338. // ID will be fixed-up downstream.
  339. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  340. auto animation_id = _params[0]->getUnsigned();
  341. // TODO: check for zero.
  342. auto speed = 1.0f / _params[1]->getUnsigned();
  343. code_gen->AddOutputLine((
  344. boost::format("self.%1%:play_animation_stop(\"%2%\") -- speed %3%")
  345. % entity % cg->GetFormatter().AnimationName(char_id, animation_id) % speed
  346. ).str());
  347. code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
  348. }
  349. void FF7::FieldModelInstruction::ProcessCANIM2(
  350. CodeGenerator* code_gen, const std::string& entity, int char_id
  351. ){
  352. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  353. auto animation_id = _params[0]->getUnsigned();
  354. auto start_frame = _params[1]->getUnsigned() / 30.0f;
  355. auto end_frame = _params[2]->getUnsigned() / 30.0f;
  356. // TODO: check for zero.
  357. auto speed = 1.0f / _params[3]->getUnsigned();
  358. code_gen->AddOutputLine((
  359. boost::format("self.%1%:play_animation(\"%2%\", %3%, %4%) -- speed %5%")
  360. % entity % cg->GetFormatter().AnimationName(char_id, animation_id)
  361. % start_frame % end_frame % speed
  362. ).str());
  363. code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
  364. }
  365. void FF7::FieldModelInstruction::ProcessCANM_2(
  366. CodeGenerator* code_gen, const std::string& entity, int char_id
  367. ){
  368. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  369. // ID will be fixed-up downstream.
  370. auto animation_id = _params[0]->getUnsigned();
  371. auto start_frame = _params[1]->getUnsigned() / 30.0f;
  372. auto end_frame = _params[2]->getUnsigned() / 30.0f;
  373. // TODO: check for zero.
  374. auto speed = 1.0f / _params[3]->getUnsigned();
  375. code_gen->AddOutputLine((
  376. boost::format("self.%1%:play_animation_stop(\"%2%\", %3%, %4%) -- speed %5%")
  377. % entity % cg->GetFormatter().AnimationName(char_id, animation_id)
  378. % start_frame % end_frame % speed
  379. ).str());
  380. code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
  381. }
  382. void FF7::FieldModelInstruction::ProcessCC(CodeGenerator* code_gen, const FieldEngine& engine){
  383. const auto& entity = engine.EntityByIndex(_params[0]->getUnsigned());
  384. code_gen->AddOutputLine(
  385. (boost::format("entity_manager:set_player_entity(\"%1%\")") % entity.GetName()).str()
  386. );
  387. }
  388. void FF7::FieldModelInstruction::ProcessJUMP(CodeGenerator* code_gen, const std::string& entity){
  389. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  390. const float scale = 128.0f * cg->GetScaleFactor();
  391. float x = std::stof(FF7::FieldCodeGenerator::FormatValueOrVariable(
  392. cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned(),
  393. FF7::FieldCodeGenerator::ValueType::Float, scale
  394. ));
  395. float y = std::stof(FF7::FieldCodeGenerator::FormatValueOrVariable(
  396. cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned(),
  397. FF7::FieldCodeGenerator::ValueType::Float, scale
  398. ));
  399. int i = atoi(FF7::FieldCodeGenerator::FormatValueOrVariable(
  400. cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getSigned()
  401. ).c_str());
  402. int steps = atoi(FF7::FieldCodeGenerator::FormatValueOrVariable(
  403. cg->GetFormatter(), _params[3]->getUnsigned(), _params[7]->getSigned()
  404. ).c_str());
  405. //x *= 0.00781250273224;
  406. //y *= 0.00781250273224;
  407. // Always force reduce steps and bound it between 1 and 5.
  408. steps /= 6;
  409. if (steps < 1) steps = 1;
  410. if (steps > 5) steps = 5;
  411. // TODO: Z hardcoded as -1, handled in Entity::ScriptJumpToPosition.
  412. // TODO: Hardcoded 0.5 in seconds. Calculate using distance.
  413. code_gen->AddOutputLine((
  414. boost::format("self.%1%:jump_to_position(%2%, %3%, -1, 0.5, %4%) -- %5% steps.")
  415. % entity % x % y % i % steps
  416. ).str());
  417. code_gen->AddOutputLine((boost::format("self.%1%:jump_sync()") % entity).str());
  418. }
  419. void FF7::FieldModelInstruction::ProcessAXYZI(CodeGenerator* code_gen){
  420. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  421. const float scale = 128.0f * cg->GetScaleFactor();
  422. code_gen->AddOutputLine((
  423. boost::format("axyzi(%1%, %2%, %3%, %4%, %5%, %6%, %7%, %8%, %9%, %10%)")
  424. % _params[0]->getSigned() % _params[1]->getSigned() % _params[2]->getSigned()
  425. % _params[3]->getSigned() % _params[4]->getSigned() % _params[5]->getSigned()
  426. % _params[6]->getSigned() % _params[7]->getSigned() % _params[8]->getSigned()
  427. % scale
  428. ).str());
  429. }
  430. void FF7::FieldModelInstruction::ProcessLADER(CodeGenerator* code_gen, const std::string& entity){
  431. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  432. const float scale = 128.0f * cg->GetScaleFactor();
  433. const auto& x = FF7::FieldCodeGenerator::FormatValueOrVariable(
  434. cg->GetFormatter(), _params[0]->getUnsigned(), _params[4]->getSigned(),
  435. FF7::FieldCodeGenerator::ValueType::Float, scale
  436. );
  437. const auto& y = FF7::FieldCodeGenerator::FormatValueOrVariable(
  438. cg->GetFormatter(), _params[1]->getUnsigned(), _params[5]->getSigned(),
  439. FF7::FieldCodeGenerator::ValueType::Float, scale
  440. );
  441. const auto& z = FF7::FieldCodeGenerator::FormatValueOrVariable(
  442. cg->GetFormatter(), _params[2]->getUnsigned(), _params[6]->getSigned(),
  443. FF7::FieldCodeGenerator::ValueType::Float, scale
  444. );
  445. uint end_triangle = atoi(FF7::FieldCodeGenerator::FormatValueOrVariable(
  446. cg->GetFormatter(), _params[3]->getUnsigned(), _params[7]->getUnsigned()
  447. ).c_str());
  448. uint keys = _params[8]->getUnsigned();
  449. uint animation = _params[9]->getUnsigned();
  450. //float orientation = _params[10]->getUnsigned() / (256.0f / 360.0f);
  451. const auto& orientation = FF7::FieldCodeGenerator::FormatValueOrVariable(
  452. cg->GetFormatter(), 0, _params[10]->getSigned(),
  453. FF7::FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
  454. );
  455. uint speed = _params[11]->getUnsigned();
  456. // TODO: Animation hardcoded as "btce".
  457. // TODO: Orientation and speed not set.
  458. code_gen->AddOutputLine((
  459. boost::format(
  460. "self.%1%:linear_to_position(%2%, %3%, %4%, %5%, \"Climb\", %6%, %7%) "
  461. "-- Animation %8% -- Speed %9%"
  462. ) % entity % x % y % z % keys % orientation % end_triangle % animation % speed
  463. ).str());
  464. code_gen->AddOutputLine((boost::format("self.%1%:linear_sync()") % entity).str());
  465. }
  466. void FF7::FieldModelInstruction::ProcessSOLID(CodeGenerator* code_gen, const std::string& entity){
  467. code_gen->AddOutputLine((
  468. boost::format("self.%1%:set_solid(%2%)")
  469. % entity % FF7::FieldCodeGenerator::FormatInvertedBool(_params[0]->getUnsigned())
  470. ).str());
  471. }
  472. void FF7::FieldModelInstruction::ProcessOFST(CodeGenerator* code_gen, const std::string& entity){
  473. FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
  474. const float scale = 128.0f * cg->GetScaleFactor();
  475. float x = std::stof(FF7::FieldCodeGenerator::FormatValueOrVariable(
  476. cg->GetFormatter(), _params[0]->getUnsigned(), _params[5]->getSigned(),
  477. FF7::FieldCodeGenerator::ValueType::Float, scale
  478. ));
  479. float y = std::stof(FF7::FieldCodeGenerator::FormatValueOrVariable(
  480. cg->GetFormatter(), _params[1]->getUnsigned(),_params[6]->getSigned(),
  481. FF7::FieldCodeGenerator::ValueType::Float, scale
  482. ));
  483. float z = std::stof(FF7::FieldCodeGenerator::FormatValueOrVariable(
  484. cg->GetFormatter(), _params[2]->getUnsigned(), _params[7]->getSigned(),
  485. FF7::FieldCodeGenerator::ValueType::Float, scale
  486. ));
  487. float speed = std::stof(FF7::FieldCodeGenerator::FormatValueOrVariable(
  488. cg->GetFormatter(), _params[3]->getUnsigned(), _params[8]->getUnsigned()
  489. ));
  490. // Spatial coordinates need to be scaled down.
  491. // TODO: This number is empirically deducted. Why this number?
  492. //x *= 0.00390f;
  493. //y *= 0.00390f;
  494. //z *= 0.00390f;
  495. // Speed needs to be scaled down by the frame rate.
  496. speed /= 30.0f;
  497. code_gen->AddOutputLine((
  498. boost::format("self.%1%:offset_to_position(%2%, %3%, %4%, %5%, %6%)")
  499. % entity % x % y % z
  500. % (_params[4]->getUnsigned() ? "Entity.SMOOTH" : "Entity.LINEAR")% speed
  501. ).str());
  502. }