FieldModelInstruction.cpp 25 KB

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