ff7_field_engine.cpp 83 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844
  1. #include "ff7_field_engine.h"
  2. #include "ff7_field_disassembler.h"
  3. #include "ff7_field_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. /*
  10. OpCodes which need implementing (already done in DAT dumper)
  11. "BLINK"
  12. "XYI"
  13. "CMOVE"
  14. "MOVA"
  15. "TURA"
  16. "ANIMW"
  17. "FMOVE"
  18. "ANIME2"
  19. "ANIM_1"
  20. "CANIM1" ?
  21. "CANM_1"
  22. "TURN"
  23. "DIRA"
  24. "GETDIR"
  25. "GETAXY"
  26. "JUMP"
  27. "AXYZI"
  28. "LADER"
  29. "OFST"
  30. "TALKR"
  31. "ANIMB"
  32. "TURNW"
  33. */
  34. std::unique_ptr<Disassembler> FF7::FF7FieldEngine::getDisassembler(
  35. InstVec &insts, const std::vector<unsigned char>& raw_script_data
  36. ){
  37. auto ret = std::make_unique<FF7Disassembler>(mFormatter, this, insts, raw_script_data);
  38. mScaleFactor = ret->ScaleFactor();
  39. return std::move(ret);
  40. }
  41. std::unique_ptr<Disassembler> FF7::FF7FieldEngine::getDisassembler(InstVec &insts){
  42. auto ret = std::make_unique<FF7Disassembler>(mFormatter, this, insts);
  43. mScaleFactor = ret->ScaleFactor();
  44. return std::move(ret);
  45. }
  46. std::unique_ptr<CodeGenerator> FF7::FF7FieldEngine::getCodeGenerator(
  47. const InstVec& insts, std::ostream &output
  48. ){
  49. // The broken version:
  50. //return std::make_unique<FF7CodeGenerator>(this, insts, output);
  51. // The not-as-nice-but-at-least-it-works version:
  52. return std::make_unique<FF7SimpleCodeGenerator>(this, insts, output, mFormatter);
  53. }
  54. void FF7::FF7FieldEngine::postCFG(InstVec& insts, Graph g){
  55. /*
  56. // In FF7 some scripts ends with an infinite loop to "keep it alive"
  57. // in QGears this isn't required so we can remove them
  58. RemoveTrailingInfiniteLoops(insts, g);
  59. // This could generate bad code, but it always seems to follow that pattern that if the last
  60. // instruction is an uncond jump back into the script then it simply nests all of those blocks
  61. // in an infinite loop
  62. MarkInfiniteLoopGroups(insts, g);
  63. // Scripts end with a "return" this isn't required so strip them out
  64. RemoveExtraneousReturnStatements(insts, g);
  65. */
  66. }
  67. std::map<std::string, int> FF7::FF7FieldEngine::GetEntities() const{
  68. std::map<std::string, int> r;
  69. for (auto& f : _functions){
  70. const Function& func = f.second;
  71. FF7::FunctionMetaData meta(func._metadata);
  72. auto it = r.find(meta.EntityName());
  73. if (it != std::end(r)){
  74. // Try to find a function in this entity has that has a char id
  75. // don't overwrite a valid char id with a "blank" one
  76. if (it->second == -1) it->second = meta.CharacterId();
  77. }
  78. // TODO: Don't add lines here:
  79. else r[meta.EntityName()] = meta.CharacterId();
  80. }
  81. return r;
  82. }
  83. std::vector<SUDM::FF7::Field::Line> FF7::FF7FieldEngine::GetLineList() const{
  84. std::vector<SUDM::FF7::Field::Line> lines;
  85. for (auto entity: mEntityIndexMap){
  86. if (entity.second.IsLine() == true){
  87. SUDM::FF7::Field::Line line;
  88. line.name = entity.second.Name();
  89. line.point_a = entity.second.GetLinePointA();
  90. line.point_b = entity.second.GetLinePointB();
  91. lines.push_back(line);
  92. }
  93. }
  94. return lines;
  95. }
  96. void FF7::FF7FieldEngine::AddEntityFunction(
  97. const std::string& entity_name, size_t entity_index,
  98. const std::string& func_name, size_t func_index
  99. ){
  100. auto it = mEntityIndexMap.find(entity_index);
  101. if (it != std::end(mEntityIndexMap)) (*it).second.AddFunction(func_name, func_index);
  102. else{
  103. Entity e(entity_name);
  104. e.AddFunction(func_name, func_index);
  105. mEntityIndexMap.insert(std::make_pair(entity_index, e));
  106. }
  107. }
  108. void FF7::FF7FieldEngine::MarkEntityAsLine(
  109. size_t entity_index, bool line, std::vector<float> point_a, std::vector<float> point_b
  110. ){
  111. auto it = mEntityIndexMap.find(entity_index);
  112. if (it != std::end(mEntityIndexMap)){
  113. (*it).second.MarkAsLine(line, point_a, point_b);
  114. }
  115. }
  116. bool FF7::FF7FieldEngine::EntityIsLine(size_t entity_index){
  117. auto it = mEntityIndexMap.find(entity_index);
  118. if (it != std::end(mEntityIndexMap)) return (*it).second.IsLine();
  119. return false;
  120. }
  121. void FF7::FF7FieldEngine::RemoveExtraneousReturnStatements(InstVec& insts, Graph g){
  122. for (auto& f : _functions){
  123. Function& func = f.second;
  124. for (auto it = insts.begin(); it != insts.end(); it ++){
  125. // Is it the last instruction in the function, and is it a return statement?
  126. if ((*it)->_address == func.mEndAddr){
  127. if ((*it)->_opcode == eOpcodes::RET){
  128. // Set new end address to be before the NOP.
  129. func.mEndAddr = (*(it - 1))->_address;
  130. func.mNumInstructions --;
  131. Instruction* nop = new FF7NoOperationInstruction();
  132. nop->_opcode = eOpcodes::NOP;
  133. nop->_address = (*it)->_address;
  134. (*it).reset(nop);
  135. break;
  136. }
  137. }
  138. }
  139. }
  140. }
  141. void FF7::FF7FieldEngine::RemoveTrailingInfiniteLoops(InstVec& insts, Graph g){
  142. for (auto& f : _functions){
  143. Function& func = f.second;
  144. for (auto it = insts.begin(); it != insts.end(); it ++){
  145. // Is it the last instruction in the function, a jump, and a jumping to itself?
  146. if ((*it)->_address == func.mEndAddr){
  147. if ((*it)->isJump() && (*it)->getDestAddress() == (*it)->_address){
  148. // Set new end address to be before the NOP
  149. func.mEndAddr = (*(it - 1))->_address;
  150. func.mNumInstructions--;
  151. Instruction* nop = new FF7NoOperationInstruction();
  152. nop->_opcode = eOpcodes::NOP;
  153. nop->_address = (*it)->_address;
  154. (*it).reset(nop);
  155. break;
  156. }
  157. }
  158. }
  159. }
  160. }
  161. void FF7::FF7FieldEngine::MarkInfiniteLoopGroups(InstVec& insts, Graph g){
  162. for (auto& f : _functions){
  163. Function& func = f.second;
  164. for (auto it = insts.begin(); it != insts.end(); it ++){
  165. if ((*it)->_address == func.mEndAddr){
  166. // Note: This is a "best effort heuristic", so quite a few loops will
  167. // still end up as goto's. This could potentially generate invalid code too.
  168. if ((*it)->isUncondJump()){
  169. // Then assume its an infinite do { } while(true)
  170. // loop that wraps part of the script.
  171. VertexRange vr = boost::vertices(g);
  172. for (VertexIterator v = vr.first; v != vr.second; ++ v){
  173. GroupPtr gr = GET(*v);
  174. if ((*gr->_start)->_address == func.mEndAddr){
  175. // Then assume its an infinite do { } while(true) loop
  176. // that wraps part of the script.
  177. gr->_type = kDoWhileCondGroupType;
  178. }
  179. }
  180. }
  181. break;
  182. }
  183. }
  184. }
  185. }
  186. void FF7::FF7CondJumpInstruction::processInst(
  187. Function& function, ValueStack &stack, Engine* engine, CodeGenerator* code_gen
  188. ){
  189. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  190. std::string funcName;
  191. if (_opcode == eOpcodes::IFKEYON) funcName = "entity_manager:is_key_on";
  192. else if (_opcode == eOpcodes::IFKEYOFF) funcName = "entity_manager:is_key_off";
  193. else if (_opcode == eOpcodes::IFKEY) funcName = "Key";
  194. else if (_opcode == eOpcodes::IFMEMBQ) funcName = "IFMEMBQ";
  195. else if (_opcode == eOpcodes::IFPRTYQ) funcName = "IFPRTYQ";
  196. // If condition is a function, add and stop.
  197. if (!funcName.empty()){
  198. uint32 param = _params[0]->getUnsigned();
  199. // Special cases. The first parameter of IFKEY, IFKEYON and IFKEYOFF
  200. // can be ORed to get the individual keys, but there are two invalid
  201. // ones: 512 and 1024. They must be XORed.
  202. if (
  203. _opcode == eOpcodes::IFKEY
  204. || _opcode == eOpcodes::IFKEYON
  205. || _opcode == eOpcodes::IFKEYOFF
  206. ){
  207. if (param >= 1024) param = param ^ 1024;
  208. if (param >= 512) param = param ^ 512;
  209. }
  210. ValuePtr v = new UnqotedStringValue(funcName + "(" + std::to_string(param) + ")");
  211. stack.push(v);
  212. return;
  213. }
  214. std::string op;
  215. uint32 type = _params[4]->getUnsigned();
  216. const auto& source = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  217. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  218. );
  219. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  220. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  221. );
  222. switch (type){
  223. case 0: op = "=="; break;
  224. case 1: op = "~="; break;
  225. case 2: op = ">"; break;
  226. case 3: op = "<"; break;
  227. case 4: op = ">="; break;
  228. case 5: op = "<="; break;
  229. case 6: op = "&"; break;
  230. case 7: op = "^"; break;
  231. case 8: op = "|"; break;
  232. case 9:
  233. {
  234. op = "bit(" + _params[0]->getString() + ", " + _params[2]->getString()
  235. + ", " + destination + ") == 1";
  236. ValuePtr v = new UnqotedStringValue(op);
  237. stack.push(v);
  238. }
  239. return;
  240. case 0xA:
  241. {
  242. op = "bit(" + _params[0]->getString() + ", " + _params[2]->getString()
  243. + ", " + destination + ") == 0";
  244. ValuePtr v = new UnqotedStringValue(op);
  245. stack.push(v);
  246. }
  247. return;
  248. default: throw UnknownConditionalOperatorException(_address, type);
  249. }
  250. ValuePtr v = new BinaryOpValue(new VarValue(source), new VarValue(destination), op);
  251. stack.push(v);
  252. }
  253. uint32 FF7::FF7CondJumpInstruction::getDestAddress() const{
  254. uint32 params_size = 0;
  255. uint32 jump_param_index = 5;
  256. switch (_opcode){
  257. case eOpcodes::IFUB: params_size = 5; break;
  258. case eOpcodes::IFUBL: params_size = 5; break;
  259. case eOpcodes::IFSW: params_size = 7; break;
  260. case eOpcodes::IFSWL: params_size = 7; break;
  261. case eOpcodes::IFUW: params_size = 7; break;
  262. case eOpcodes::IFUWL: params_size = 7; break;
  263. case eOpcodes::IFKEYON:
  264. case eOpcodes::IFKEYOFF:
  265. case eOpcodes::IFKEY:
  266. params_size = 3;
  267. jump_param_index = 1;
  268. break;
  269. case eOpcodes::IFPRTYQ:
  270. case eOpcodes::IFMEMBQ:
  271. params_size = 2;
  272. jump_param_index = 1;
  273. break;
  274. default: throw UnknownJumpTypeException(_address, _opcode);
  275. }
  276. return _address + _params[jump_param_index]->getUnsigned() + params_size;
  277. }
  278. std::ostream& FF7::FF7CondJumpInstruction::print(std::ostream &output) const{
  279. Instruction::print(output);
  280. output << " (False target address: 0x" << std::hex << getDestAddress() << std::dec << ")";
  281. return output;
  282. }
  283. bool FF7::FF7UncondJumpInstruction::isFuncCall() const{return _isCall;}
  284. bool FF7::FF7UncondJumpInstruction::isUncondJump() const{return !_isCall;}
  285. uint32 FF7::FF7UncondJumpInstruction::getDestAddress() const{
  286. if (
  287. static_cast<eOpcodes>(_opcode) == eOpcodes::JMPF
  288. || static_cast<eOpcodes>(_opcode) == eOpcodes::JMPFL){
  289. // Short or long forward jump.
  290. return _address + _params[0]->getUnsigned() + 1;
  291. }
  292. // Backwards jump, eOpcodes::JMPB/L.
  293. return _address - _params[0]->getUnsigned();
  294. }
  295. std::ostream& FF7::FF7UncondJumpInstruction::print(std::ostream &output) const{
  296. Instruction::print(output);
  297. output << " (Jump target address: 0x" << std::hex << getDestAddress() << std::dec << ")";
  298. return output;
  299. }
  300. void FF7::FF7UncondJumpInstruction::processInst(
  301. Function& func, ValueStack&, Engine* engine, CodeGenerator* code_gen
  302. ){
  303. switch (_opcode){
  304. case eOpcodes::JMPB:
  305. case eOpcodes::JMPBL:
  306. // HACK: Hard loop will hang the game, insert a wait to yield control
  307. code_gen->addOutputLine("-- Hack, yield control for possible inf loop");
  308. code_gen->addOutputLine("script:wait(0)");
  309. break;
  310. }
  311. }
  312. static void WriteTodo(CodeGenerator *code_gen, std::string entity_name, std::string opCode){
  313. code_gen->addOutputLine("-- Todo(\"" + opCode + "\")");
  314. }
  315. void FF7::FF7ControlFlowInstruction::processInst(
  316. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  317. ){
  318. FF7::FF7FieldEngine& eng = static_cast<FF7::FF7FieldEngine&>(*engine);
  319. FunctionMetaData md(func._metadata);
  320. switch (_opcode){
  321. case eOpcodes::RET:
  322. // A few notes in RET.
  323. // - Lua requires all functions to end with a return.
  324. // - Lua doesn's like returns if not followed by an end.
  325. // - Don't add a return statement to on_start functions.
  326. // Game 'init' and 'main' code is concatenated in V-Gears. If the
  327. // 'main' return is kept, the code of 'main' is never executed.
  328. // There are safeguards forfunctions without a return in the end,
  329. // so it's OK not to include it here.
  330. if (func._name != "on_start") code_gen->addOutputLine("do return 0 end");
  331. break;
  332. case eOpcodes::REQ: processREQ(code_gen, eng); break;
  333. case eOpcodes::REQSW: processREQSW(code_gen, eng); break;
  334. case eOpcodes::REQEW: processREQEW(code_gen, eng); break;
  335. case eOpcodes::PREQ: WriteTodo(code_gen, md.EntityName(), "PREQ"); break;
  336. case eOpcodes::PRQSW: WriteTodo(code_gen, md.EntityName(), "PRQSW"); break;
  337. case eOpcodes::PRQEW: WriteTodo(code_gen, md.EntityName(), "PRQEW"); break;
  338. case eOpcodes::RETTO: processRETTO(code_gen); break;
  339. case eOpcodes::WAIT: processWAIT(code_gen); break;
  340. default:
  341. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  342. md.EntityName(), _address, _opcode
  343. ));
  344. }
  345. }
  346. void FF7::FF7ControlFlowInstruction::processREQ(
  347. CodeGenerator* code_gen, const FF7FieldEngine& engine
  348. ){
  349. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  350. const auto& entity = engine.EntityByIndex(_params[0]->getSigned());
  351. const auto& script_name = cg->mFormatter.FunctionName(
  352. entity.Name(), entity.FunctionByIndex(_params[2]->getUnsigned())
  353. );
  354. auto priority = _params[1]->getUnsigned();
  355. code_gen->addOutputLine((
  356. boost::format("script:request(Script.ENTITY, \"%1%\", \"%2%\", %3%)")
  357. % entity.Name() % script_name % priority
  358. ).str());
  359. }
  360. void FF7::FF7ControlFlowInstruction::processREQSW(
  361. CodeGenerator* code_gen, const FF7FieldEngine& engine
  362. ){
  363. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  364. const auto& entity = engine.EntityByIndex(_params[0]->getSigned());
  365. const auto& script_name = cg->mFormatter.FunctionName(
  366. entity.Name(), entity.FunctionByIndex(_params[2]->getUnsigned())
  367. );
  368. auto priority = _params[1]->getUnsigned();
  369. code_gen->addOutputLine((
  370. boost::format("script:request_start_sync(Script.ENTITY, \"%1%\", \"%2%\", %3%)")
  371. % entity.Name() % script_name % priority
  372. ).str());
  373. }
  374. void FF7::FF7ControlFlowInstruction::processREQEW(
  375. CodeGenerator* code_gen, const FF7FieldEngine& engine
  376. ){
  377. try{
  378. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  379. const auto& entity = engine.EntityByIndex(_params[0]->getSigned());
  380. const auto& script_name = cg->mFormatter.FunctionName(
  381. entity.Name(), entity.FunctionByIndex(_params[2]->getUnsigned())
  382. );
  383. auto priority = _params[1]->getUnsigned();
  384. code_gen->addOutputLine((
  385. boost::format("script:request_end_sync(Script.ENTITY, \"%1%\", \"%2%\", %3%)")
  386. % entity.Name() % script_name % priority
  387. ).str());
  388. }
  389. catch (const InternalDecompilerError&){
  390. code_gen->addOutputLine((
  391. boost::format("-- ERROR call to non existing function index %1%")
  392. % _params[2]->getUnsigned()
  393. ).str());
  394. }
  395. }
  396. void FF7::FF7ControlFlowInstruction::processRETTO(CodeGenerator* code_gen){
  397. auto entity_index = _params[0]->getUnsigned();
  398. auto priority = _params[1]->getUnsigned();
  399. code_gen->addOutputLine((
  400. boost::format("-- return_to(script_id_in_current_entity=%2%, priority=%1%)")
  401. % entity_index % priority
  402. ).str());
  403. }
  404. void FF7::FF7ControlFlowInstruction::processWAIT(CodeGenerator* code_gen){
  405. code_gen->addOutputLine((
  406. boost::format("script:wait(%1%)") % (_params[0]->getUnsigned() / 30.0f)
  407. ).str());
  408. }
  409. void FF7::FF7ModuleInstruction::processInst(
  410. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  411. ){
  412. FunctionMetaData md(func._metadata);
  413. switch (_opcode){
  414. case eOpcodes::DSKCG: WriteTodo(code_gen, md.EntityName(), "DSKCG"); break;
  415. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::ARROW:
  416. code_gen->addOutputLine((
  417. boost::format("game:pointer_enable(%1%)")
  418. % (_params[0]->getUnsigned() ? "true" : "false")
  419. ).str());
  420. break;
  421. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::PNAME:
  422. WriteTodo(code_gen, md.EntityName(), "PNAME");
  423. break;
  424. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::GMSPD:
  425. WriteTodo(code_gen, md.EntityName(), "GMSPD");
  426. break;
  427. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::SMSPD:
  428. WriteTodo(code_gen, md.EntityName(), "SMSPD");
  429. break;
  430. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::FLMAT:
  431. code_gen->addOutputLine("game:fill_materia()");
  432. break;
  433. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::FLITM:
  434. WriteTodo(code_gen, md.EntityName(), "FLITM");
  435. break;
  436. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::BTLCK:
  437. code_gen->addOutputLine((
  438. boost::format("game:battle_enable(%1%)")
  439. % (_params[0]->getUnsigned() ? "true" : "false")
  440. ).str());
  441. break;
  442. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::MVLCK:
  443. code_gen->addOutputLine((
  444. boost::format("game:movie_enable(%1%)")
  445. % (_params[0]->getUnsigned() ? "true" : "false")
  446. ).str());
  447. break;
  448. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::SPCNM:
  449. WriteTodo(code_gen, md.EntityName(), "SPCNM");
  450. break;
  451. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::RSGLB:
  452. code_gen->addOutputLine("game:global_reset()");
  453. break;
  454. case (eOpcodes::SPECIAL << 8) | eSpecialOpcodes::CLITM:
  455. WriteTodo(code_gen, md.EntityName(), "CLITM");
  456. break;
  457. case eOpcodes::MINIGAME: WriteTodo(code_gen, md.EntityName(), "MINIGAME"); break;
  458. case eOpcodes::BTMD2: WriteTodo(code_gen, md.EntityName(), "BTMD2"); break;
  459. case eOpcodes::BTRLD: WriteTodo(code_gen, md.EntityName(), "BTRLD"); break;
  460. case eOpcodes::BTLTB: WriteTodo(code_gen, md.EntityName(), "BTLTB"); break;
  461. case eOpcodes::MAPJUMP: processMAPJUMP(code_gen, func); break;
  462. case eOpcodes::LSTMP: WriteTodo(code_gen, md.EntityName(), "LSTMP"); break;
  463. case eOpcodes::BATTLE: processBATTLE(code_gen); break;
  464. case eOpcodes::BTLON: processBTLON(code_gen); break;
  465. case eOpcodes::BTLMD: WriteTodo(code_gen, md.EntityName(), "BTLMD"); break;
  466. case eOpcodes::MPJPO:
  467. // Gateway function will do nothing if this is set to true
  468. code_gen->addOutputLine(
  469. std::string("FFVII.Data.DisableGateways=")
  470. + (_params[0]->getUnsigned() ? "true" : "false")
  471. );
  472. break;
  473. // Prepare to change map, don't need to output anything for this.
  474. case eOpcodes::PMJMP: code_gen->addOutputLine("-- Prepare map change"); break;
  475. // Prepare to change map, don't need to output anything for this,
  476. // seems to be the same thing as PMJMP
  477. case eOpcodes::PMJMP2: code_gen->addOutputLine("-- Prepare map change 2"); break;
  478. case eOpcodes::GAMEOVER: WriteTodo(code_gen, md.EntityName(), "GAMEOVER"); break;
  479. default:
  480. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  481. md.EntityName(), _address, _opcode
  482. ));
  483. }
  484. }
  485. void FF7::FF7ModuleInstruction::processBATTLE(CodeGenerator* code_gen){
  486. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  487. const auto& battle_id = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  488. cg->mFormatter, _params[0]->getUnsigned(), _params[1]->getUnsigned()
  489. );
  490. code_gen->addOutputLine((boost::format("entity_manager:battle_run(%1%)") % battle_id).str());
  491. }
  492. void FF7::FF7ModuleInstruction::processBTLON(CodeGenerator* code_gen){
  493. code_gen->addOutputLine((
  494. boost::format("entity_manager:random_encounters_on(%1%)")
  495. % FF7CodeGeneratorHelpers::FormatInvertedBool(_params[0]->getUnsigned())
  496. ).str());
  497. }
  498. void FF7::FF7ModuleInstruction::processMAPJUMP(CodeGenerator* code_gen, Function& func){
  499. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  500. const auto target_map_id = _params[0]->getUnsigned();
  501. FunctionMetaData md(func._metadata);
  502. const std::string source_spawn_point_name
  503. = cg->mFormatter.SpawnPointName(target_map_id, md.EntityName(), func._name, _address);
  504. cg->mFormatter.AddSpawnPoint(
  505. target_map_id, md.EntityName(), func._name, _address,
  506. _params[1]->getSigned(), // X
  507. _params[2]->getSigned(), // Y
  508. _params[3]->getSigned(), // Walk mesh triangle ID
  509. _params[4]->getSigned() // Angle
  510. );
  511. const std::string target_map_name = cg->mFormatter.MapName(target_map_id);
  512. code_gen->addOutputLine(
  513. "load_field_map_request(\"" + target_map_name + "\", \"" + source_spawn_point_name + "\")"
  514. );
  515. }
  516. void FF7::FF7MathInstruction::processInst(
  517. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  518. ){
  519. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  520. FunctionMetaData md(func._metadata);
  521. switch (_opcode){
  522. case eOpcodes::PLUS_: processSaturatedPLUS(code_gen); break;
  523. case eOpcodes::PLUS2_: processSaturatedPLUS2(code_gen); break;
  524. case eOpcodes::MINUS_: processSaturatedMINUS(code_gen); break;
  525. case eOpcodes::MINUS2_: processSaturatedMINUS2(code_gen); break;
  526. case eOpcodes::INC_: processSaturatedINC(code_gen); break;
  527. case eOpcodes::INC2_: processSaturatedINC2(code_gen); break;
  528. case eOpcodes::DEC_: processSaturatedDEC(code_gen); break;
  529. case eOpcodes::DEC2_: processSaturatedDEC2(code_gen); break;
  530. case eOpcodes::RDMSD: processRDMSD(code_gen); break;
  531. case eOpcodes::SETBYTE:
  532. case eOpcodes::SETWORD:
  533. processSETBYTE_SETWORD(code_gen);
  534. break;
  535. case eOpcodes::BITON: processBITON(code_gen); break;
  536. case eOpcodes::BITOFF: processBITOFF(code_gen); break;
  537. case eOpcodes::BITXOR: WriteTodo(code_gen, md.EntityName(), "BITXOR"); break;
  538. case eOpcodes::PLUS:
  539. case eOpcodes::PLUS2:
  540. processPLUSx_MINUSx(code_gen, "+");
  541. break;
  542. case eOpcodes::MINUS:
  543. case eOpcodes::MINUS2:
  544. processPLUSx_MINUSx(code_gen, "-");
  545. break;
  546. case eOpcodes::MUL: WriteTodo(code_gen, md.EntityName(), "MUL"); break;
  547. case eOpcodes::MUL2: WriteTodo(code_gen, md.EntityName(), "MUL2"); break;
  548. case eOpcodes::DIV: WriteTodo(code_gen, md.EntityName(), "DIV"); break;
  549. case eOpcodes::DIV2: WriteTodo(code_gen, md.EntityName(), "DIV2"); break;
  550. case eOpcodes::MOD:
  551. {
  552. const uint32 source_bank = _params[0]->getUnsigned();
  553. const uint32 source_address_or_value = _params[2]->getUnsigned();
  554. auto source = FF7::FF7CodeGeneratorHelpers::FormatValueOrVariable(
  555. cg->mFormatter, source_bank, source_address_or_value
  556. );
  557. const uint32 dest_bank = _params[1]->getUnsigned();
  558. const uint32 dest_address = _params[3]->getUnsigned();
  559. auto dest = FF7::FF7CodeGeneratorHelpers::FormatValueOrVariable(
  560. cg->mFormatter, dest_bank, dest_address
  561. );
  562. code_gen->addOutputLine(
  563. source + " = " + source + " % " + dest + code_gen->TargetLang().LineTerminator()
  564. );
  565. }
  566. break;
  567. case eOpcodes::MOD2: WriteTodo(code_gen, md.EntityName(), "MOD2"); break;
  568. case eOpcodes::AND: WriteTodo(code_gen, md.EntityName(), "AND"); break;
  569. case eOpcodes::AND2: WriteTodo(code_gen, md.EntityName(), "AND2"); break;
  570. case eOpcodes::OR: WriteTodo(code_gen, md.EntityName(), "OR"); break;
  571. case eOpcodes::OR2: WriteTodo(code_gen, md.EntityName(), "OR2"); break;
  572. case eOpcodes::XOR: WriteTodo(code_gen, md.EntityName(), "XOR"); break;
  573. case eOpcodes::XOR2: WriteTodo(code_gen, md.EntityName(), "XOR2"); break;
  574. case eOpcodes::INC:
  575. case eOpcodes::INC2:
  576. processINCx_DECx(code_gen, "+");
  577. break;
  578. case eOpcodes::DEC:
  579. case eOpcodes::DEC2:
  580. processINCx_DECx(code_gen, "-");
  581. break;
  582. case eOpcodes::RANDOM: processRANDOM(code_gen); break;
  583. case eOpcodes::LBYTE: WriteTodo(code_gen, md.EntityName(), "LBYTE"); break;
  584. case eOpcodes::HBYTE: WriteTodo(code_gen, md.EntityName(), "HBYTE"); break;
  585. case eOpcodes::TWOBYTE: WriteTodo(code_gen, md.EntityName(), "2BYTE"); break;
  586. case eOpcodes::SIN: WriteTodo(code_gen, md.EntityName(), "SIN"); break;
  587. case eOpcodes::COS: WriteTodo(code_gen, md.EntityName(), "COS"); break;
  588. default:
  589. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  590. md.EntityName(), _address, _opcode
  591. ));
  592. }
  593. }
  594. void FF7::FF7MathInstruction::processSaturatedPLUS(CodeGenerator* code_gen){
  595. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  596. // TODO: Check for assignment to value.
  597. const auto& lhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  598. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  599. );
  600. const auto& rhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  601. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  602. );
  603. // TODO: Respect destination bank sizes and negative wrap-around.
  604. code_gen->addOutputLine((boost::format("%1% = %1% + %2%") % lhs % rhs).str());
  605. code_gen->addOutputLine((boost::format("--if (%1% > 255); %1% = 255; end") % lhs).str());
  606. }
  607. void FF7::FF7MathInstruction::processSaturatedPLUS2(CodeGenerator* code_gen){
  608. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  609. // TODO: Check for assignment to value.
  610. const auto& lhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  611. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  612. );
  613. const auto& rhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  614. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  615. );
  616. // TODO: Respect destination bank sizes and negative wrap-around.
  617. code_gen->addOutputLine((boost::format("%1% = %1% + %2%") % lhs % rhs).str());
  618. code_gen->addOutputLine((boost::format("--if (%1% > 32767); %1% = 32767; end") % lhs).str());
  619. }
  620. void FF7::FF7MathInstruction::processSaturatedMINUS(CodeGenerator* code_gen){
  621. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  622. // TODO: Check for assignment to value.
  623. const auto& lhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  624. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  625. );
  626. const auto& rhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  627. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  628. );
  629. // TODO: Respect destination bank sizes and positive wrap-around.
  630. code_gen->addOutputLine((boost::format("%1% = %1% - %2%") % lhs % rhs).str());
  631. code_gen->addOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % lhs).str());
  632. }
  633. void FF7::FF7MathInstruction::processSaturatedMINUS2(CodeGenerator* code_gen){
  634. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  635. // TODO: Check for assignment to value.
  636. const auto& lhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  637. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  638. );
  639. const auto& rhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  640. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  641. );
  642. // TODO: Respect destination bank sizes and positive wrap-around.
  643. code_gen->addOutputLine((boost::format("%1% = %1% - %2%") % lhs % rhs).str());
  644. code_gen->addOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % lhs).str());
  645. }
  646. void FF7::FF7MathInstruction::processSaturatedINC(CodeGenerator* code_gen){
  647. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  648. // TODO: Check for assignment to value.
  649. const auto& dest = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  650. cg->mFormatter, _params[0]->getUnsigned(), _params[1]->getUnsigned()
  651. );
  652. // TODO: Respect destination bank sizes and negative wrap-around.
  653. code_gen->addOutputLine((boost::format("%1% = %1% + 1") % dest).str());
  654. code_gen->addOutputLine((boost::format("--if (%1% > 255); %1% = 255; end") % dest).str());
  655. }
  656. void FF7::FF7MathInstruction::processSaturatedINC2(CodeGenerator* code_gen){
  657. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  658. // TODO: Check for assignment to value.
  659. const auto& dest = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  660. cg->mFormatter, _params[0]->getUnsigned(), _params[1]->getUnsigned()
  661. );
  662. // TODO: Respect destination bank sizes and negative wrap-around.
  663. code_gen->addOutputLine((boost::format("%1% = %1% + 1") % dest).str());
  664. code_gen->addOutputLine((boost::format("--if (%1% > 32767); %1% = 32767; end") % dest).str());
  665. }
  666. void FF7::FF7MathInstruction::processSaturatedDEC(CodeGenerator* code_gen){
  667. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  668. // TODO: Check for assignment to value.
  669. const auto& dest = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  670. cg->mFormatter, _params[0]->getUnsigned(), _params[1]->getUnsigned()
  671. );
  672. // TODO: Respect destination bank sizes and positive wrap-around.
  673. code_gen->addOutputLine((boost::format("%1% = %1% - 1") % dest).str());
  674. code_gen->addOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % dest).str());
  675. }
  676. void FF7::FF7MathInstruction::processSaturatedDEC2(CodeGenerator* code_gen){
  677. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  678. // TODO: Check for assignment to value.
  679. const auto& dest = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  680. cg->mFormatter, _params[0]->getUnsigned(), _params[1]->getUnsigned()
  681. );
  682. // TODO: Respect destination bank sizes and positive wrap-around.
  683. code_gen->addOutputLine((boost::format("%1% = %1% - 1") % dest).str());
  684. code_gen->addOutputLine((boost::format("--if (%1% < 0); %1% = 0; end") % dest).str());
  685. }
  686. void FF7::FF7MathInstruction::processRDMSD(CodeGenerator* code_gen){
  687. // TODO: we don't have os.time...
  688. // TODO: RNG emulation?
  689. code_gen->addOutputLine("math.randomseed(os.time())");
  690. }
  691. void FF7::FF7MathInstruction::processSETBYTE_SETWORD(CodeGenerator* code_gen){
  692. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  693. // TODO: Check for assignment to value.
  694. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  695. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  696. );
  697. const auto& source = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  698. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  699. );
  700. // TODO: respect destination bank sizes (16-bit writes only affect low byte)
  701. code_gen->addOutputLine((boost::format("%1% = %2%") % destination % source).str());
  702. }
  703. void FF7::FF7MathInstruction::processBITON(CodeGenerator* code_gen){
  704. code_gen->addOutputLine((boost::format("bit_on(%1%, %2%, %3%)")
  705. % _params[0]->getUnsigned() % _params[2]->getUnsigned() % _params[3]->getUnsigned()
  706. ).str());
  707. }
  708. void FF7::FF7MathInstruction::processBITOFF(CodeGenerator* code_gen){
  709. code_gen->addOutputLine((boost::format("bit_on(%1%, %2%, %3%)")
  710. % _params[0]->getUnsigned() % _params[2]->getUnsigned() % _params[3]->getUnsigned()
  711. ).str());
  712. }
  713. void FF7::FF7MathInstruction::processPLUSx_MINUSx(CodeGenerator* code_gen, const std::string& op){
  714. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  715. // TODO: Check for assignment to value.
  716. const auto& lhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  717. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  718. );
  719. const auto& rhs = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  720. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  721. );
  722. // TODO: repect destination bank sizes and wraparound
  723. code_gen->addOutputLine((boost::format("%1% = %1% %2% %3%") % lhs % op % rhs).str());
  724. }
  725. void FF7::FF7MathInstruction::processINCx_DECx(CodeGenerator* code_gen, const std::string& op){
  726. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  727. // TODO: Check for assignment to value.
  728. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  729. cg->mFormatter, _params[0]->getUnsigned(), _params[1]->getUnsigned()
  730. );
  731. // TODO: repect destination bank sizes and wraparound
  732. code_gen->addOutputLine((boost::format("%1% = %1% %2% 1") % destination % op).str());
  733. }
  734. void FF7::FF7MathInstruction::processRANDOM(CodeGenerator* code_gen){
  735. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  736. // TODO: Check for assignment to value.
  737. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  738. cg->mFormatter, _params[0]->getUnsigned(), _params[1]->getUnsigned()
  739. );
  740. // TODO: Respect destination bank sizes (16-bit writes only affect low byte).
  741. // TODO: RNG emulation?
  742. code_gen->addOutputLine((boost::format("%1% = math.random(0, 255)") % destination).str());
  743. }
  744. void FF7::FF7WindowInstruction::processInst(
  745. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  746. ){
  747. FF7::FF7FieldEngine& eng = static_cast<FF7::FF7FieldEngine&>(*engine);
  748. FunctionMetaData md(func._metadata);
  749. switch (_opcode){
  750. case eOpcodes::TUTOR: WriteTodo(code_gen, md.EntityName(), "TUTOR"); break;
  751. case eOpcodes::WCLS: WriteTodo(code_gen, md.EntityName(), "WCLS"); break;
  752. case eOpcodes::WSIZW: WriteTodo(code_gen, md.EntityName(), "WSIZW"); break;
  753. case eOpcodes::WSPCL: WriteTodo(code_gen, md.EntityName(), "WSPCL"); break;
  754. case eOpcodes::WNUMB: WriteTodo(code_gen, md.EntityName(), "WNUMB"); break;
  755. case eOpcodes::STTIM: WriteTodo(code_gen, md.EntityName(), "STTIM"); break;
  756. case eOpcodes::MESSAGE: processMESSAGE(code_gen, eng.ScriptName()); break;
  757. case eOpcodes::MPARA: WriteTodo(code_gen, md.EntityName(), "MPARA"); break;
  758. case eOpcodes::MPRA2: WriteTodo(code_gen, md.EntityName(), "MPRA2"); break;
  759. case eOpcodes::MPNAM: processMPNAM(code_gen); break;
  760. case eOpcodes::ASK: WriteTodo(code_gen, md.EntityName(), "ASK"); break;
  761. case eOpcodes::MENU: WriteTodo(code_gen, md.EntityName(), "MENU"); break;
  762. case eOpcodes::MENU2: processMENU2(code_gen); break;
  763. case eOpcodes::WINDOW: processWINDOW(code_gen); break;
  764. case eOpcodes::WMOVE: WriteTodo(code_gen, md.EntityName(), "WMOVE"); break;
  765. case eOpcodes::WMODE: WriteTodo(code_gen, md.EntityName(), "WMODE"); break;
  766. case eOpcodes::WREST: WriteTodo(code_gen, md.EntityName(), "WREST"); break;
  767. case eOpcodes::WCLSE: processWCLSE(code_gen); break;
  768. case eOpcodes::WROW: WriteTodo(code_gen, md.EntityName(), "WROW"); break;
  769. case eOpcodes::GWCOL: WriteTodo(code_gen, md.EntityName(), "GWCOL"); break;
  770. case eOpcodes::SWCOL: WriteTodo(code_gen, md.EntityName(), "SWCOL"); break;
  771. default:
  772. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  773. md.EntityName(), _address, _opcode
  774. ));
  775. }
  776. }
  777. void FF7::FF7WindowInstruction::processWINDOW(CodeGenerator* code_gen){
  778. // Init a new window. It won't be displayed until MESSAGE is used.
  779. auto windowId = _params[0]->getUnsigned();
  780. auto x = _params[1]->getUnsigned();
  781. auto y = _params[2]->getUnsigned();
  782. auto width = _params[3]->getUnsigned();
  783. auto height = _params[4]->getUnsigned();
  784. code_gen->addOutputLine((
  785. boost::format("dialog:dialog_open(\"%1%\", %2%, %3%, %4%, %5%)")
  786. % windowId % x % y % width % height
  787. ).str());
  788. }
  789. void FF7::FF7WindowInstruction::processMESSAGE(
  790. CodeGenerator* code_gen, const std::string& script_name
  791. ){
  792. // Displays a dialog in the WINDOW that has previously been initialized to display this dialog.
  793. auto window_id = _params[0]->getUnsigned();
  794. auto dialog_id = _params[1]->getUnsigned();
  795. code_gen->addOutputLine((
  796. boost::format("dialog:dialog_set_text(\"%1%\", \"%2%_%3%\")")
  797. % window_id % script_name % dialog_id
  798. ).str());
  799. code_gen->addOutputLine(
  800. (boost::format("dialog:dialog_wait_for_close(\"%1%\")") % window_id).str()
  801. );
  802. }
  803. void FF7::FF7WindowInstruction::processWCLSE(CodeGenerator* code_gen){
  804. // Close a dialog.
  805. auto windowId = _params[0]->getUnsigned();
  806. code_gen->addOutputLine((boost::format("dialog:dialog_close(\"%1%\")") % windowId).str());
  807. }
  808. void FF7::FF7WindowInstruction::processMPNAM(CodeGenerator* code_gen){
  809. code_gen->addOutputLine(
  810. (boost::format("-- field:map_name(%1%)") % _params[0]->getUnsigned()).str()
  811. );
  812. }
  813. void FF7::FF7WindowInstruction::processMENU2(CodeGenerator* code_gen){
  814. code_gen->addOutputLine((
  815. boost::format("-- field:menu_lock(%1%)")
  816. % FF7CodeGeneratorHelpers::FormatBool(_params[0]->getUnsigned())
  817. ).str());
  818. }
  819. void FF7::FF7PartyInstruction::processInst(
  820. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  821. ){
  822. FunctionMetaData md(func._metadata);
  823. switch (_opcode){
  824. case eOpcodes::SPTYE: WriteTodo(code_gen, md.EntityName(), "SPTYE"); break;
  825. case eOpcodes::GTPYE: WriteTodo(code_gen, md.EntityName(), "GTPYE"); break;
  826. case eOpcodes::GOLDU: WriteTodo(code_gen, md.EntityName(), "GOLDU"); break;
  827. case eOpcodes::GOLDD: WriteTodo(code_gen, md.EntityName(), "GOLDD"); break;
  828. case eOpcodes::HMPMAX1: WriteTodo(code_gen, md.EntityName(), "HMPMAX1"); break;
  829. case eOpcodes::HMPMAX2: WriteTodo(code_gen, md.EntityName(), "HMPMAX2"); break;
  830. case eOpcodes::MHMMX: WriteTodo(code_gen, md.EntityName(), "MHMMX"); break;
  831. case eOpcodes::HMPMAX3: WriteTodo(code_gen, md.EntityName(), "HMPMAX3"); break;
  832. case eOpcodes::MPU: WriteTodo(code_gen, md.EntityName(), "MPU"); break;
  833. case eOpcodes::MPD: WriteTodo(code_gen, md.EntityName(), "MPD"); break;
  834. case eOpcodes::HPU: WriteTodo(code_gen, md.EntityName(), "HPU"); break;
  835. case eOpcodes::HPD: WriteTodo(code_gen, md.EntityName(), "HPD"); break;
  836. case eOpcodes::STITM: processSTITM(code_gen); break;
  837. case eOpcodes::DLITM: WriteTodo(code_gen, md.EntityName(), "DLITM"); break;
  838. case eOpcodes::CKITM: WriteTodo(code_gen, md.EntityName(), "CKITM"); break;
  839. case eOpcodes::SMTRA: WriteTodo(code_gen, md.EntityName(), "SMTRA"); break;
  840. case eOpcodes::DMTRA: WriteTodo(code_gen, md.EntityName(), "DMTRA"); break;
  841. case eOpcodes::CMTRA: WriteTodo(code_gen, md.EntityName(), "CMTRA"); break;
  842. case eOpcodes::GETPC: WriteTodo(code_gen, md.EntityName(), "GETPC"); break;
  843. case eOpcodes::PRTYP: WriteTodo(code_gen, md.EntityName(), "PRTYP"); break;
  844. case eOpcodes::PRTYM: WriteTodo(code_gen, md.EntityName(), "PRTYM"); break;
  845. case eOpcodes::PRTYE: processPRTYE(code_gen); break;
  846. case eOpcodes::MMBUD: WriteTodo(code_gen, md.EntityName(), "MMBUD"); break;
  847. case eOpcodes::MMBLK: WriteTodo(code_gen, md.EntityName(), "MMBLK"); break;
  848. case eOpcodes::MMBUK: WriteTodo(code_gen, md.EntityName(), "MMBUK"); break;
  849. case eOpcodes::CHGLD: WriteTodo(code_gen, md.EntityName(), "CHGLD"); break;
  850. default:
  851. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  852. md.EntityName(), _address, _opcode
  853. ));
  854. }
  855. }
  856. void FF7::FF7PartyInstruction::processSTITM(CodeGenerator* code_gen){
  857. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  858. const auto& item_id = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  859. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  860. );
  861. const auto& amount = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  862. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  863. );
  864. code_gen->addOutputLine((boost::format("FFVII.add_item(%1%, %2%)") % item_id % amount).str());
  865. }
  866. void FF7::FF7PartyInstruction::processPRTYE(CodeGenerator* code_gen){
  867. FF7SimpleCodeGenerator* gc = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  868. auto char_id_1 = gc->mFormatter.CharName(_params[0]->getUnsigned());
  869. char_id_1 = (char_id_1 == "") ? "nil" : ("\"" + char_id_1 + "\"");
  870. auto char_id_2 = gc->mFormatter.CharName(_params[1]->getUnsigned());
  871. char_id_2 = (char_id_2 == "") ? "nil" : ("\"" + char_id_2 + "\"");
  872. auto char_id_3 = gc->mFormatter.CharName(_params[2]->getUnsigned());
  873. char_id_3 = (char_id_3 == "") ? "nil" : ("\"" + char_id_3 + "\"");
  874. code_gen->addOutputLine((
  875. boost::format("FFVII.set_party(%1%, %2%, %3%)") % char_id_1 % char_id_2 % char_id_3
  876. ).str());
  877. }
  878. void FF7::FF7ModelInstruction::processInst(
  879. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  880. ){
  881. FF7::FF7FieldEngine& eng = static_cast<FF7::FF7FieldEngine&>(*engine);
  882. FunctionMetaData md(func._metadata);
  883. switch (_opcode){
  884. case eOpcodes::JOIN: processJOIN(code_gen); break;
  885. case eOpcodes::SPLIT: processSPLIT(code_gen); break;
  886. case eOpcodes::BLINK: WriteTodo(code_gen, md.EntityName(), "BLINK"); break;
  887. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::EYETX:
  888. WriteTodo(code_gen, md.EntityName(), "EYETX");
  889. break;
  890. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::TRNSP:
  891. WriteTodo(code_gen, md.EntityName(), "TRNSP");
  892. break;
  893. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::AMBNT:
  894. WriteTodo(code_gen, md.EntityName(), "AMBNT");
  895. break;
  896. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::Unknown03:
  897. WriteTodo(code_gen, md.EntityName(), "Unknown03");
  898. break;
  899. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::Unknown04:
  900. WriteTodo(code_gen, md.EntityName(), "Unknown04");
  901. break;
  902. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::Unknown05:
  903. WriteTodo(code_gen, md.EntityName(), "Unknown05");
  904. break;
  905. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::LIGHT:
  906. WriteTodo(code_gen, md.EntityName(), "LIGHT");
  907. break;
  908. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::Unknown07:
  909. WriteTodo(code_gen, md.EntityName(), "Unknown07");
  910. break;
  911. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::Unknown08:
  912. WriteTodo(code_gen, md.EntityName(), "Unknown08");
  913. break;
  914. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::Unknown09:
  915. WriteTodo(code_gen, md.EntityName(), "Unknown09");
  916. break;
  917. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::SBOBJ:
  918. WriteTodo(code_gen, md.EntityName(), "SBOBJ");
  919. break;
  920. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::Unknown0B:
  921. WriteTodo(code_gen, md.EntityName(), "Unknown0B");
  922. break;
  923. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::Unknown0C:
  924. WriteTodo(code_gen, md.EntityName(), "Unknown0C");
  925. break;
  926. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::SHINE:
  927. WriteTodo(code_gen, md.EntityName(), "SHINE");
  928. break;
  929. case (eOpcodes::KAWAI << 8) | eKawaiOpcodes::RESET:
  930. WriteTodo(code_gen, md.EntityName(), "RESET");
  931. break;
  932. case eOpcodes::KAWIW: WriteTodo(code_gen, md.EntityName(), "KAWIW"); break;
  933. case eOpcodes::PMOVA: WriteTodo(code_gen, md.EntityName(), "PMOVA"); break;
  934. case eOpcodes::PDIRA: WriteTodo(code_gen, md.EntityName(), "PDIRA"); break;
  935. case eOpcodes::PTURA: WriteTodo(code_gen, md.EntityName(), "PTURA"); break;
  936. case eOpcodes::PGTDR: WriteTodo(code_gen, md.EntityName(), "PGTDR"); break;
  937. case eOpcodes::PXYZI: WriteTodo(code_gen, md.EntityName(), "PXYZI"); break;
  938. case eOpcodes::TLKON: processTLKON(code_gen, md.EntityName()); break;
  939. case eOpcodes::PC: processPC(code_gen, md.EntityName()); break;
  940. case eOpcodes::opCodeCHAR: processCHAR(code_gen, md.EntityName()); break;
  941. case eOpcodes::DFANM: processDFANM(code_gen, md.EntityName(), md.CharacterId()); break;
  942. case eOpcodes::ANIME1: processANIME1(code_gen, md.EntityName(), md.CharacterId()); break;
  943. case eOpcodes::VISI: processVISI(code_gen, md.EntityName()); break;
  944. case eOpcodes::XYZI: processXYZI(code_gen, md.EntityName()); break;
  945. case eOpcodes::XYI: WriteTodo(code_gen, md.EntityName(), "XYI"); break;
  946. case eOpcodes::XYZ: WriteTodo(code_gen, md.EntityName(), "XYZ"); break;
  947. case eOpcodes::MOVE: processMOVE(code_gen, md.EntityName()); break;
  948. case eOpcodes::CMOVE: WriteTodo(code_gen, md.EntityName(), "CMOVE"); break;
  949. case eOpcodes::MOVA: WriteTodo(code_gen, md.EntityName(), "MOVA"); break;
  950. case eOpcodes::TURA: WriteTodo(code_gen, md.EntityName(), "TURA"); break;
  951. case eOpcodes::ANIMW: WriteTodo(code_gen, md.EntityName(), "ANIMW"); break;
  952. case eOpcodes::FMOVE: WriteTodo(code_gen, md.EntityName(), "FMOVE"); break;
  953. case eOpcodes::ANIME2: WriteTodo(code_gen, md.EntityName(), "ANIME2"); break;
  954. case eOpcodes::ANIM_1: WriteTodo(code_gen, md.EntityName(), "ANIM_1"); break;
  955. case eOpcodes::CANIM1: WriteTodo(code_gen, md.EntityName(), "CANIM1"); break;
  956. case eOpcodes::CANM_1: WriteTodo(code_gen, md.EntityName(), "CANM_1"); break;
  957. case eOpcodes::MSPED: processMSPED(code_gen, md.EntityName()); break;
  958. case eOpcodes::DIR: processDIR(code_gen, md.EntityName()); break;
  959. case eOpcodes::TURNGEN: processTURNGEN(code_gen, md.EntityName()); break;
  960. case eOpcodes::TURN: WriteTodo(code_gen, md.EntityName(), "TURN"); break;
  961. case eOpcodes::DIRA: WriteTodo(code_gen, md.EntityName(), "DIRA"); break;
  962. case eOpcodes::GETDIR: WriteTodo(code_gen, md.EntityName(), "GETDIR"); break;
  963. case eOpcodes::GETAXY: WriteTodo(code_gen, md.EntityName(), "GETAXY"); break;
  964. case eOpcodes::GETAI: processGETAI(code_gen, eng); break;
  965. case eOpcodes::ANIM_2: processANIM_2(code_gen, md.EntityName(), md.CharacterId()); break;
  966. case eOpcodes::CANIM2: processCANIM2(code_gen, md.EntityName(), md.CharacterId()); break;
  967. case eOpcodes::CANM_2: processCANM_2(code_gen, md.EntityName(), md.CharacterId()); break;
  968. case eOpcodes::ASPED: WriteTodo(code_gen, md.EntityName(), "ASPED"); break;
  969. case eOpcodes::CC: processCC(code_gen, eng); break;
  970. case eOpcodes::JUMP: WriteTodo(code_gen, md.EntityName(), "JUMP"); break;
  971. case eOpcodes::AXYZI: WriteTodo(code_gen, md.EntityName(), "AXYZI"); break;
  972. case eOpcodes::LADER: WriteTodo(code_gen, md.EntityName(), "LADER"); break;
  973. case eOpcodes::OFST: processOFST(code_gen, md.EntityName()); break;
  974. case eOpcodes::OFSTW:
  975. code_gen->addOutputLine("self." + md.EntityName() + ":offset_sync()");
  976. break;
  977. case eOpcodes::TALKR: WriteTodo(code_gen, md.EntityName(), "TALKR"); break;
  978. case eOpcodes::SLIDR: WriteTodo(code_gen, md.EntityName(), "SLIDR"); break;
  979. case eOpcodes::SOLID: processSOLID(code_gen, md.EntityName()); break;
  980. case eOpcodes::TLKR2: WriteTodo(code_gen, md.EntityName(), "TLKR2"); break;
  981. case eOpcodes::SLDR2: WriteTodo(code_gen, md.EntityName(), "SLDR2"); break;
  982. case eOpcodes::CCANM: WriteTodo(code_gen, md.EntityName(), "CCANM"); break;
  983. case eOpcodes::FCFIX: WriteTodo(code_gen, md.EntityName(), "FCFIX"); break;
  984. case eOpcodes::ANIMB: WriteTodo(code_gen, md.EntityName(), "ANIMB"); break;
  985. case eOpcodes::TURNW: WriteTodo(code_gen, md.EntityName(), "TURNW"); break;
  986. default:
  987. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  988. md.EntityName(), _address, _opcode
  989. ));
  990. }
  991. }
  992. void FF7::FF7ModelInstruction::processJOIN(CodeGenerator* code_gen){
  993. code_gen->addOutputLine("join_party(" + std::to_string(_params[0]->getUnsigned()) + ")");
  994. }
  995. void FF7::FF7ModelInstruction::processSPLIT(CodeGenerator* code_gen){
  996. code_gen->addOutputLine(
  997. "split_party("
  998. + std::to_string(_params[0]->getUnsigned()) + ", " // ax_addr
  999. + std::to_string(_params[1]->getUnsigned()) + ", " // ay_addr
  1000. + std::to_string(_params[2]->getUnsigned()) + ", " // ar_addr
  1001. + std::to_string(_params[3]->getUnsigned()) + ", " // bx_addr
  1002. + std::to_string(_params[4]->getUnsigned()) + ", " // by_addr
  1003. + std::to_string(_params[5]->getUnsigned()) + ", " // br_addr
  1004. + std::to_string(_params[6]->getSigned()) + ", " // ax
  1005. + std::to_string(_params[7]->getSigned()) + ", " // ay
  1006. + std::to_string(_params[8]->getSigned()) + ", " // ar
  1007. + std::to_string(_params[9]->getSigned()) + ", " // bx
  1008. + std::to_string(_params[10]->getSigned()) + ", " // by
  1009. + std::to_string(_params[11]->getSigned()) + ", " // br
  1010. + std::to_string(_params[12]->getUnsigned()) + ", " // speed
  1011. + ")");
  1012. }
  1013. void FF7::FF7ModelInstruction::processTLKON(CodeGenerator* code_gen, const std::string& entity){
  1014. code_gen->addOutputLine((
  1015. boost::format("self.%1%:set_talkable(%2%)")
  1016. % entity % FF7CodeGeneratorHelpers::FormatInvertedBool(_params[0]->getUnsigned())
  1017. ).str());
  1018. }
  1019. void FF7::FF7ModelInstruction::processPC(CodeGenerator* code_gen, const std::string& entity){
  1020. code_gen->addOutputLine(
  1021. (boost::format("set_entity_to_character(\"%1%\", \"%1%\")") % entity).str()
  1022. );
  1023. }
  1024. void FF7::FF7ModelInstruction::processCHAR(CodeGenerator* code_gen, const std::string& entity){
  1025. code_gen->addOutputLine(
  1026. (boost::format("self.%1% = entity_manager:get_entity(\"%1%\")") % entity).str()
  1027. );
  1028. }
  1029. void FF7::FF7ModelInstruction::processDFANM(
  1030. CodeGenerator* code_gen, const std::string& entity, int char_id
  1031. ){
  1032. // ID will be fixed-up downstream.
  1033. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1034. auto animation_id = _params[0]->getUnsigned();
  1035. // TODO: check for zero.
  1036. auto speed = 1.0f / _params[1]->getUnsigned();
  1037. code_gen->addOutputLine((
  1038. boost::format("self.%1%:set_default_animation(\"%2%\") -- speed %3%")
  1039. % entity % cg->mFormatter.AnimationName(char_id, animation_id) % speed
  1040. ).str());
  1041. code_gen->addOutputLine((
  1042. boost::format("self.%1%:play_animation(\"%2%\")")
  1043. % entity % cg->mFormatter.AnimationName(char_id, animation_id)
  1044. ).str());
  1045. }
  1046. void FF7::FF7ModelInstruction::processANIME1(
  1047. CodeGenerator* code_gen, const std::string& entity, int char_id
  1048. ){
  1049. // ID will be fixed-up downstream.
  1050. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1051. auto animation_id = _params[0]->getUnsigned();
  1052. // TODO: check for zero.
  1053. auto speed = 1.0f / _params[1]->getUnsigned();
  1054. code_gen->addOutputLine((
  1055. boost::format("self.%1%:play_animation(\"%2%\") -- speed %3%")
  1056. % entity % cg->mFormatter.AnimationName(char_id, animation_id) % speed
  1057. ).str());
  1058. code_gen->addOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
  1059. }
  1060. void FF7::FF7ModelInstruction::processVISI(CodeGenerator* code_gen, const std::string& entity){
  1061. code_gen->addOutputLine((
  1062. boost::format("self.%1%:set_visible(%2%)")
  1063. % entity % FF7CodeGeneratorHelpers::FormatBool(_params[0]->getUnsigned())
  1064. ).str());
  1065. }
  1066. void FF7::FF7ModelInstruction::processXYZI(CodeGenerator* code_gen, const std::string& entity){
  1067. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1068. const float scale = 128.0f * cg->ScaleFactor();
  1069. const auto& x = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1070. cg->mFormatter, _params[0]->getUnsigned(), _params[4]->getSigned(),
  1071. FF7CodeGeneratorHelpers::ValueType::Float, scale
  1072. );
  1073. const auto& y = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1074. cg->mFormatter, _params[1]->getUnsigned(), _params[5]->getSigned(),
  1075. FF7CodeGeneratorHelpers::ValueType::Float, scale
  1076. );
  1077. const auto& z = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1078. cg->mFormatter, _params[2]->getUnsigned(), _params[6]->getSigned(),
  1079. FF7CodeGeneratorHelpers::ValueType::Float, scale
  1080. );
  1081. const auto& triangle_id = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1082. cg->mFormatter, _params[3]->getUnsigned(), _params[7]->getUnsigned()
  1083. );
  1084. code_gen->addOutputLine((
  1085. boost::format("self.%1%:set_position(%2%, %3%, %4%) -- triangle ID %5%")
  1086. % entity % x % y % z % triangle_id
  1087. ).str());
  1088. }
  1089. void FF7::FF7ModelInstruction::processMOVE(CodeGenerator* code_gen, const std::string& entity){
  1090. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1091. const float scale = 128.0f * cg->ScaleFactor();
  1092. const auto& x = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1093. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getSigned(),
  1094. FF7CodeGeneratorHelpers::ValueType::Float, scale
  1095. );
  1096. const auto& y = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1097. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getSigned(),
  1098. FF7CodeGeneratorHelpers::ValueType::Float, scale
  1099. );
  1100. code_gen->addOutputLine(
  1101. (boost::format("self.%1%:move_to_position(%2%, %3%)") % entity % x % y).str()
  1102. );
  1103. code_gen->addOutputLine((boost::format("self.%1%:move_sync()") % entity).str());
  1104. }
  1105. void FF7::FF7ModelInstruction::processMSPED(CodeGenerator* code_gen, const std::string& entity){
  1106. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1107. const float scale = 128.0f * cg->ScaleFactor();
  1108. const auto& speed = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1109. cg->mFormatter, _params[1]->getUnsigned(), _params[2]->getUnsigned(),
  1110. FF7CodeGeneratorHelpers::ValueType::Float, 256.0f * scale / 30.0f
  1111. );
  1112. code_gen->addOutputLine(
  1113. (boost::format("self.%1%:set_move_auto_speed(%2%)") % entity % speed).str()
  1114. );
  1115. }
  1116. void FF7::FF7ModelInstruction::processDIR(CodeGenerator* code_gen, const std::string& entity){
  1117. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1118. const auto& degrees = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1119. cg->mFormatter, _params[0]->getUnsigned(), _params[1]->getUnsigned(),
  1120. FF7CodeGeneratorHelpers::ValueType::Float, 256.0f / 360.0f
  1121. );
  1122. code_gen->addOutputLine((boost::format("self.%1%:set_rotation(%2%)") % entity % degrees).str());
  1123. }
  1124. void FF7::FF7ModelInstruction::processTURNGEN(CodeGenerator* code_gen, const std::string& entity){
  1125. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1126. const auto& degrees = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1127. cg->mFormatter, _params[1]->getUnsigned(), _params[2]->getUnsigned(),
  1128. FF7CodeGeneratorHelpers::ValueType::Float, 256.0f / 360.0f
  1129. );
  1130. std::string direction;
  1131. switch (_params[3]->getUnsigned()){
  1132. case 0: direction = "Entity.CLOCKWISE"; break;
  1133. case 1: direction = "Entity.ANTICLOCKWISE"; break;
  1134. case 2: direction = "Entity.CLOSEST"; break;
  1135. // Default to closest:
  1136. default: direction = "Entity.CLOSEST"; break;
  1137. }
  1138. auto steps = _params[4]->getUnsigned();
  1139. std::string step_type;
  1140. switch (_params[5]->getUnsigned()){
  1141. case 1: step_type = "Entity.LINEAR"; break;
  1142. case 2: step_type = "Entity.SMOOTH"; break;
  1143. // Default to smooth
  1144. default: step_type = "Entity.SMOOTH"; break;
  1145. }
  1146. const float scaled_steps = static_cast<float>(steps) / 30.0f;
  1147. code_gen->addOutputLine((
  1148. boost::format("self.%1%:turn_to_direction(%2%, %3%, %4%, %5%)")
  1149. % entity % degrees % direction % step_type % scaled_steps
  1150. ).str());
  1151. code_gen->addOutputLine((boost::format("self.%1%:turn_sync()") % entity).str());
  1152. }
  1153. void FF7::FF7ModelInstruction::processGETAI(CodeGenerator* code_gen, const FF7FieldEngine& engine){
  1154. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1155. // TODO: check for assignment to literal.
  1156. const auto& variable = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1157. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  1158. );
  1159. const auto& entity = engine.EntityByIndex(_params[2]->getUnsigned());
  1160. code_gen->addOutputLine(
  1161. (boost::format("%1% = entity_manager:get_entity(\"%2%\"):get_move_triangle_id()")
  1162. % variable % entity.Name()
  1163. ).str());
  1164. }
  1165. void FF7::FF7ModelInstruction::processANIM_2(
  1166. CodeGenerator* code_gen, const std::string& entity, int char_id
  1167. ){
  1168. // ID will be fixed-up downstream.
  1169. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1170. auto animation_id = _params[0]->getUnsigned();
  1171. // TODO: check for zero.
  1172. auto speed = 1.0f / _params[1]->getUnsigned();
  1173. code_gen->addOutputLine((
  1174. boost::format("self.%1%:play_animation_stop(\"%2%\") -- speed %3%")
  1175. % entity % cg->mFormatter.AnimationName(char_id, animation_id) % speed
  1176. ).str());
  1177. code_gen->addOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
  1178. }
  1179. void FF7::FF7ModelInstruction::processCANIM2(
  1180. CodeGenerator* code_gen, const std::string& entity, int char_id
  1181. ){
  1182. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1183. auto animation_id = _params[0]->getUnsigned();
  1184. auto start_frame = _params[1]->getUnsigned() / 30.0f;
  1185. auto end_frame = _params[2]->getUnsigned() / 30.0f;
  1186. // TODO: check for zero.
  1187. auto speed = 1.0f / _params[3]->getUnsigned();
  1188. code_gen->addOutputLine((
  1189. boost::format("self.%1%:play_animation(\"%2%\", %3%, %4%) -- speed %5%")
  1190. % entity % cg->mFormatter.AnimationName(char_id, animation_id)
  1191. % start_frame % end_frame % speed
  1192. ).str());
  1193. code_gen->addOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
  1194. }
  1195. void FF7::FF7ModelInstruction::processCANM_2(
  1196. CodeGenerator* code_gen, const std::string& entity, int char_id
  1197. ){
  1198. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1199. // ID will be fixed-up downstream.
  1200. auto animation_id = _params[0]->getUnsigned();
  1201. auto start_frame = _params[1]->getUnsigned() / 30.0f;
  1202. auto end_frame = _params[2]->getUnsigned() / 30.0f;
  1203. // TODO: check for zero.
  1204. auto speed = 1.0f / _params[3]->getUnsigned();
  1205. code_gen->addOutputLine((
  1206. boost::format("self.%1%:play_animation_stop(\"%2%\", %3%, %4%) -- speed %5%")
  1207. % entity % cg->mFormatter.AnimationName(char_id, animation_id)
  1208. % start_frame % end_frame % speed
  1209. ).str());
  1210. code_gen->addOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
  1211. }
  1212. void FF7::FF7ModelInstruction::processCC(CodeGenerator* code_gen, const FF7FieldEngine& engine){
  1213. const auto& entity = engine.EntityByIndex(_params[0]->getUnsigned());
  1214. code_gen->addOutputLine(
  1215. (boost::format("entity_manager:set_player_entity(\"%1%\")") % entity.Name()).str()
  1216. );
  1217. }
  1218. void FF7::FF7ModelInstruction::processSOLID(CodeGenerator* code_gen, const std::string& entity){
  1219. code_gen->addOutputLine((
  1220. boost::format("self.%1%:set_solid(%2%)")
  1221. % entity % FF7CodeGeneratorHelpers::FormatInvertedBool(_params[0]->getUnsigned())
  1222. ).str());
  1223. }
  1224. void FF7::FF7ModelInstruction::processOFST(CodeGenerator* code_gen, const std::string& entity){
  1225. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1226. float x = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1227. cg->mFormatter, _params[0]->getUnsigned(), _params[5]->getSigned()
  1228. ).c_str());
  1229. float y = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1230. cg->mFormatter, _params[1]->getUnsigned(),_params[6]->getSigned()
  1231. ).c_str());
  1232. float z = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1233. cg->mFormatter, _params[2]->getUnsigned(), _params[7]->getSigned()
  1234. ).c_str());
  1235. float speed = atoi(FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1236. cg->mFormatter, _params[3]->getUnsigned(), _params[8]->getUnsigned()
  1237. ).c_str());
  1238. // Spatial coordinates need to be scaled down.
  1239. // TODO: This number is empirically deducted. Why this number?
  1240. x *= 0.00390f;
  1241. y *= 0.00390f;
  1242. z *= 0.00390f;
  1243. // Speed needs to be scaled down by the frame rate.
  1244. speed /= 30.0f;
  1245. code_gen->addOutputLine((
  1246. boost::format("self.%1%:offset_to_position(%2%, %3%, %4%, %5%, %6%)")
  1247. % entity % x % y % z
  1248. % (_params[4]->getUnsigned() ? "Entity.SMOOTH" : "Entity.LINEAR")% speed
  1249. ).str());
  1250. }
  1251. void FF7::FF7WalkmeshInstruction::processInst(
  1252. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  1253. ){
  1254. FunctionMetaData md(func._metadata);
  1255. switch (_opcode){
  1256. case eOpcodes::SLIP: WriteTodo(code_gen, md.EntityName(), "SLIP"); break;
  1257. case eOpcodes::UC: processUC(code_gen); break;
  1258. case eOpcodes::IDLCK:
  1259. // Triangle id, on or off
  1260. code_gen->addOutputLine(
  1261. (boost::format("walkmesh:lock_walkmesh(%1%, %2%)")
  1262. % _params[0]->getUnsigned()
  1263. % FF7CodeGeneratorHelpers::FormatBool(_params[1]->getUnsigned())).str());
  1264. break;
  1265. case eOpcodes::LINE: processLINE(code_gen, md.EntityName()); break;
  1266. case eOpcodes::LINON: WriteTodo(code_gen, md.EntityName(), "LINON"); break;
  1267. case eOpcodes::SLINE: WriteTodo(code_gen, md.EntityName(), "SLINE"); break;
  1268. default:
  1269. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  1270. md.EntityName(), _address, _opcode
  1271. ));
  1272. }
  1273. }
  1274. void FF7::FF7WalkmeshInstruction::processUC(CodeGenerator* code_gen){
  1275. code_gen->addOutputLine((
  1276. boost::format("entity_manager:player_lock(%1%)")
  1277. % FF7CodeGeneratorHelpers::FormatBool(_params[0]->getUnsigned())
  1278. ).str());
  1279. }
  1280. void FF7::FF7WalkmeshInstruction::processLINE(CodeGenerator* code_gen, const std::string& entity){
  1281. float xa = _params[0]->getSigned();
  1282. float ya = _params[1]->getSigned();
  1283. float za = _params[2]->getSigned();
  1284. float xb = _params[3]->getSigned();
  1285. float yb = _params[4]->getSigned();
  1286. float zb = _params[5]->getSigned();
  1287. // Scale down. TODO: Why this number?
  1288. xa *= 0.00781249709639;
  1289. ya *= 0.00781249709639;
  1290. za *= 0.00781249709639;
  1291. xb *= 0.00781249709639;
  1292. yb *= 0.00781249709639;
  1293. zb *= 0.00781249709639;
  1294. // Just print as a comment.
  1295. code_gen->addOutputLine(
  1296. "-- LINE (" + std::to_string(xa) + ", " + std::to_string(ya) + ", " + std::to_string(za)
  1297. + ")-(" + std::to_string(xb) + ", " +std::to_string(yb) + ", " + std::to_string(zb) + ")"
  1298. );
  1299. }
  1300. void FF7::FF7BackgroundInstruction::processInst(
  1301. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  1302. ){
  1303. FunctionMetaData md(func._metadata);
  1304. switch (_opcode){
  1305. case eOpcodes::BGPDH: WriteTodo(code_gen, md.EntityName(), "BGPDH");break;
  1306. case eOpcodes::BGSCR: WriteTodo(code_gen, md.EntityName(), "BGSCR"); break;
  1307. case eOpcodes::MPPAL: WriteTodo(code_gen, md.EntityName(), "MPPAL"); break;
  1308. case eOpcodes::BGON: processBGON(code_gen); break;
  1309. case eOpcodes::BGOFF: processBGOFF(code_gen); break;
  1310. case eOpcodes::BGROL: WriteTodo(code_gen, md.EntityName(), "BGROL"); break;
  1311. case eOpcodes::BGROL2: WriteTodo(code_gen, md.EntityName(), "BGROL2"); break;
  1312. case eOpcodes::BGCLR: processBGCLR(code_gen); break;
  1313. case eOpcodes::STPAL: processSTPAL(code_gen); break;
  1314. case eOpcodes::LDPAL: processLDPAL(code_gen); break;
  1315. case eOpcodes::CPPAL: processCPPAL(code_gen); break;
  1316. case eOpcodes::RTPAL: WriteTodo(code_gen, md.EntityName(), "RTPAL"); break;
  1317. case eOpcodes::ADPAL: processADPAL(code_gen); break;
  1318. case eOpcodes::MPPAL2: processMPPAL2(code_gen); break;
  1319. case eOpcodes::STPLS: processSTPLS(code_gen); break;
  1320. case eOpcodes::LDPLS: processLDPLS(code_gen); break;
  1321. case eOpcodes::CPPAL2: WriteTodo(code_gen, md.EntityName(), "CPPAL2"); break;
  1322. case eOpcodes::ADPAL2: WriteTodo(code_gen, md.EntityName(), "ADPAL2"); break;
  1323. case eOpcodes::RTPAL2: WriteTodo(code_gen, md.EntityName(), "RTPAL2"); break;
  1324. default:
  1325. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  1326. md.EntityName(), _address, _opcode
  1327. ));
  1328. }
  1329. }
  1330. void FF7::FF7BackgroundInstruction::processBGON(CodeGenerator* code_gen){
  1331. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1332. const auto& background_id = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1333. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  1334. );
  1335. const auto& layer_id = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1336. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  1337. );
  1338. code_gen->addOutputLine(
  1339. (boost::format("-- field:background_on(%1%, %2%)") % background_id % layer_id).str()
  1340. );
  1341. }
  1342. void FF7::FF7BackgroundInstruction::processBGOFF(CodeGenerator* code_gen){
  1343. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1344. const auto& background_id = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1345. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  1346. );
  1347. const auto& layer_id = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1348. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  1349. );
  1350. code_gen->addOutputLine(
  1351. (boost::format("-- field:background_off(%1%, %2%)") % background_id % layer_id).str()
  1352. );
  1353. }
  1354. void FF7::FF7BackgroundInstruction::processBGCLR(CodeGenerator* code_gen){
  1355. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1356. const auto& background_id = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1357. cg->mFormatter, _params[1]->getUnsigned(), _params[2]->getUnsigned()
  1358. );
  1359. code_gen->addOutputLine(
  1360. (boost::format("-- field:background_clear(%1%)") % background_id).str()
  1361. );
  1362. }
  1363. void FF7::FF7BackgroundInstruction::processSTPAL(CodeGenerator* code_gen){
  1364. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1365. const auto& source = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1366. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  1367. );
  1368. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1369. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  1370. );
  1371. auto num_entries = _params[4]->getUnsigned() + 1;
  1372. code_gen->addOutputLine((
  1373. boost::format("-- store palette %1% to position %2%, start CLUT index 0, %3% entries")
  1374. % source % destination % num_entries
  1375. ).str());
  1376. }
  1377. void FF7::FF7BackgroundInstruction::processLDPAL(CodeGenerator* code_gen){
  1378. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1379. const auto& source = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1380. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  1381. );
  1382. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1383. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  1384. );
  1385. auto num_entries = _params[4]->getUnsigned() + 1;
  1386. code_gen->addOutputLine((
  1387. boost::format("-- load palette %2% from position %1%, start CLUT index 0, %3% entries")
  1388. % source % destination % num_entries
  1389. ).str());
  1390. }
  1391. void FF7::FF7BackgroundInstruction::processCPPAL(CodeGenerator* code_gen){
  1392. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1393. const auto& source = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1394. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  1395. );
  1396. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1397. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  1398. );
  1399. auto num_entries = _params[4]->getUnsigned() + 1;
  1400. code_gen->addOutputLine((
  1401. boost::format("-- copy palette %1% to palette %2%, %3% entries")
  1402. % source % destination % num_entries
  1403. ).str());
  1404. }
  1405. void FF7::FF7BackgroundInstruction::processADPAL(CodeGenerator* code_gen){
  1406. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1407. const auto& source = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1408. cg->mFormatter, _params[0]->getUnsigned(), _params[6]->getUnsigned()
  1409. );
  1410. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1411. cg->mFormatter, _params[1]->getUnsigned(), _params[7]->getUnsigned()
  1412. );
  1413. const auto& r = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1414. cg->mFormatter, _params[4]->getUnsigned(), _params[10]->getUnsigned()
  1415. );
  1416. const auto& g = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1417. cg->mFormatter, _params[3]->getUnsigned(), _params[9]->getUnsigned()
  1418. );
  1419. const auto& b = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1420. cg->mFormatter, _params[2]->getUnsigned(), _params[8]->getUnsigned()
  1421. );
  1422. auto num_entries = _params[11]->getUnsigned() + 1;
  1423. code_gen->addOutputLine((
  1424. boost::format(
  1425. "-- add RGB(%3%, %4%, %5%) to %6% entries of palette stored at position %1%, "
  1426. "storing result in position %2%"
  1427. ) % source % destination % r % g % b % num_entries
  1428. ).str());
  1429. }
  1430. void FF7::FF7BackgroundInstruction::processMPPAL2(CodeGenerator* code_gen){
  1431. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1432. const auto& source = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1433. cg->mFormatter, _params[0]->getUnsigned(), _params[6]->getUnsigned()
  1434. );
  1435. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1436. cg->mFormatter, _params[1]->getUnsigned(), _params[7]->getUnsigned()
  1437. );
  1438. const auto& r = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1439. cg->mFormatter, _params[4]->getUnsigned(), _params[10]->getUnsigned()
  1440. );
  1441. const auto& g = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1442. cg->mFormatter, _params[3]->getUnsigned(), _params[9]->getUnsigned()
  1443. );
  1444. const auto& b = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1445. cg->mFormatter, _params[2]->getUnsigned(), _params[8]->getUnsigned()
  1446. );
  1447. auto num_entries = _params[11]->getUnsigned() + 1;
  1448. code_gen->addOutputLine((
  1449. boost::format(
  1450. "-- multiply RGB(%3%, %4%, %5%) by %6% entries of palette stored at position %1%, "
  1451. "storing result in position %2%"
  1452. ) % source % destination % r % g % b % num_entries).str());
  1453. }
  1454. void FF7::FF7BackgroundInstruction::processSTPLS(CodeGenerator* code_gen){
  1455. auto source = _params[0]->getUnsigned();
  1456. auto destination = _params[1]->getUnsigned();
  1457. auto start_clut = _params[2]->getUnsigned();
  1458. auto num_entries = _params[3]->getUnsigned() + 1;
  1459. code_gen->addOutputLine((
  1460. boost::format("-- store palette %1% to position %2%, start CLUT index %3%, %4% entries")
  1461. % source % destination % start_clut % num_entries
  1462. ).str());
  1463. }
  1464. void FF7::FF7BackgroundInstruction::processLDPLS(CodeGenerator* code_gen){
  1465. auto source = _params[0]->getUnsigned();
  1466. auto destination = _params[1]->getUnsigned();
  1467. auto startClut = _params[2]->getUnsigned();
  1468. auto num_entries = _params[3]->getUnsigned() + 1;
  1469. code_gen->addOutputLine((
  1470. boost::format("-- load palette %2% from position %1%, start CLUT index %3%, %4% entries")
  1471. % source % destination % startClut % num_entries
  1472. ).str());
  1473. }
  1474. void FF7::FF7CameraInstruction::processInst(
  1475. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  1476. ){
  1477. FunctionMetaData md(func._metadata);
  1478. switch (_opcode){
  1479. case eOpcodes::NFADE: processNFADE(code_gen); break;
  1480. case eOpcodes::SHAKE: WriteTodo(code_gen, md.EntityName(), "SHAKE"); break;
  1481. case eOpcodes::SCRLO: WriteTodo(code_gen, md.EntityName(), "SCRLO"); break;
  1482. case eOpcodes::SCRLC: WriteTodo(code_gen, md.EntityName(), "SCRLC"); break;
  1483. case eOpcodes::SCR2D: processSCR2D(code_gen); break;
  1484. case eOpcodes::SCRCC: WriteTodo(code_gen, md.EntityName(), "SCRCC"); break;
  1485. case eOpcodes::SCR2DC: processSCR2DC(code_gen); break;
  1486. case eOpcodes::SCRLW: WriteTodo(code_gen, md.EntityName(), "SCRLW"); break;
  1487. case eOpcodes::SCR2DL: WriteTodo(code_gen, md.EntityName(), "SCR2DL"); break;
  1488. case eOpcodes::VWOFT: WriteTodo(code_gen, md.EntityName(), "VWOFT"); break;
  1489. case eOpcodes::FADE: processFADE(code_gen); break;
  1490. case eOpcodes::FADEW: WriteTodo(code_gen, md.EntityName(), "FADEW"); break;
  1491. case eOpcodes::SCRLP: WriteTodo(code_gen, md.EntityName(), "SCRLP"); break;
  1492. case eOpcodes::MVCAM: WriteTodo(code_gen, md.EntityName(), "MVCAM"); break;
  1493. case eOpcodes::SCRLA: WriteTodo(code_gen, md.EntityName(), "SCRLA"); break;
  1494. default:
  1495. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  1496. md.EntityName(), _address, _opcode
  1497. ));
  1498. }
  1499. }
  1500. void FF7::FF7CameraInstruction::processNFADE(CodeGenerator* code_gen){
  1501. // TODO: Not fully reversed.
  1502. auto raw_type = _params[4]->getUnsigned();
  1503. if (raw_type == 0){
  1504. code_gen->addOutputLine("-- fade:clear()");
  1505. return;
  1506. }
  1507. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1508. const std::string type = raw_type == 12 ? "Fade.SUBTRACT" : "Fade.ADD";
  1509. const auto& r = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1510. cg->mFormatter, _params[0]->getUnsigned(), _params[5]->getUnsigned()
  1511. );
  1512. const auto& g = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1513. cg->mFormatter, _params[1]->getUnsigned(), _params[6]->getUnsigned()
  1514. );
  1515. const auto& b = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1516. cg->mFormatter, _params[2]->getUnsigned(), _params[7]->getUnsigned()
  1517. );
  1518. const auto& unknown = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1519. cg->mFormatter, _params[3]->getUnsigned(), _params[8]->getUnsigned()
  1520. );
  1521. code_gen->addOutputLine(
  1522. (boost::format("-- fade:fade(%2%, %3%, %4%, %1%, %5%)") % type % r % g % b % unknown).str()
  1523. );
  1524. }
  1525. void FF7::FF7CameraInstruction::processSCR2D(CodeGenerator* code_gen){
  1526. // kUpScaler.
  1527. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1528. const auto& x = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1529. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getSigned()
  1530. );
  1531. const auto& y = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1532. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getSigned()
  1533. );
  1534. code_gen->addOutputLine((
  1535. boost::format("background2d:scroll_to_position(%1% * 3, %2% * 3, Background2D.NONE, 0)")
  1536. % x % y
  1537. ).str());
  1538. }
  1539. void FF7::FF7CameraInstruction::processSCR2DC(CodeGenerator* code_gen){
  1540. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1541. const auto& x = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1542. cg->mFormatter, _params[0]->getUnsigned(), _params[4]->getSigned()
  1543. );
  1544. const auto& y = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1545. cg->mFormatter, _params[1]->getUnsigned(), _params[5]->getSigned()
  1546. );
  1547. const auto& speed = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1548. cg->mFormatter, _params[3]->getUnsigned(), _params[6]->getUnsigned(),
  1549. FF7CodeGeneratorHelpers::ValueType::Float, 30.0f
  1550. );
  1551. code_gen->addOutputLine((
  1552. boost::format("background2d:scroll_to_position(%1% * 3, %2% * 3, Background2D.SMOOTH, %3%)")
  1553. % x % y % speed
  1554. ).str());
  1555. }
  1556. void FF7::FF7CameraInstruction::processFADE(CodeGenerator* code_gen){
  1557. // TODO: not fully reversed
  1558. auto raw_type = _params[8]->getUnsigned();
  1559. std::string type;
  1560. switch (raw_type) {
  1561. case 1:
  1562. case 2:
  1563. case 7:
  1564. case 8:
  1565. type = "Fade.SUBTRACT";
  1566. break;
  1567. case 4: code_gen->addOutputLine("-- fade:black()"); return;
  1568. default: type = "Fade.ADD"; break;
  1569. }
  1570. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1571. const auto& r = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1572. cg->mFormatter, _params[0]->getUnsigned(), _params[4]->getUnsigned()
  1573. );
  1574. const auto& g = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1575. cg->mFormatter, _params[1]->getUnsigned(), _params[5]->getUnsigned()
  1576. );
  1577. const auto& b = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1578. cg->mFormatter, _params[2]->getUnsigned(), _params[6]->getUnsigned()
  1579. );
  1580. // TODO: needs to be divided by 30.0f?
  1581. auto speed = _params[7]->getUnsigned();
  1582. auto start = _params[9]->getUnsigned();
  1583. code_gen->addOutputLine((
  1584. boost::format("-- fade:fade(%2%, %3%, %4%, %1%, %5%, %6%)") % type % r % g % b % speed % start
  1585. ).str());
  1586. }
  1587. void FF7::FF7AudioVideoInstruction::processInst(
  1588. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  1589. ){
  1590. FunctionMetaData md(func._metadata);
  1591. switch (_opcode){
  1592. case eOpcodes::BGMOVIE: WriteTodo(code_gen, md.EntityName(), "BGMOVIE"); break;
  1593. case eOpcodes::AKAO2: processAKAO2(code_gen); break;
  1594. case eOpcodes::MUSIC: processMUSIC(code_gen); break;
  1595. case eOpcodes::SOUND: processSOUND(code_gen); break;
  1596. case eOpcodes::AKAO: processAKAO(code_gen); break;
  1597. case eOpcodes::MUSVT: WriteTodo(code_gen, md.EntityName(), "MUSVT"); break;
  1598. case eOpcodes::MUSVM: WriteTodo(code_gen, md.EntityName(), "MUSVM"); break;
  1599. case eOpcodes::MULCK: processMULCK(code_gen); break;
  1600. case eOpcodes::BMUSC: WriteTodo(code_gen, md.EntityName(), "BMUSC"); break;
  1601. case eOpcodes::CHMPH: WriteTodo(code_gen, md.EntityName(), "CHMPH"); break;
  1602. case eOpcodes::PMVIE: processPMVIE(code_gen); break;
  1603. case eOpcodes::MOVIE: processMOVIE(code_gen); break;
  1604. case eOpcodes::MVIEF: processMVIEF(code_gen); break;
  1605. case eOpcodes::FMUSC: WriteTodo(code_gen, md.EntityName(), "FMUSC"); break;
  1606. case eOpcodes::CMUSC: WriteTodo(code_gen, md.EntityName(), "CMUSC"); break;
  1607. case eOpcodes::CHMST: WriteTodo(code_gen, md.EntityName(), "CHMST"); break;
  1608. default:
  1609. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  1610. md.EntityName(), _address, _opcode
  1611. ));
  1612. }
  1613. }
  1614. void FF7::FF7AudioVideoInstruction::processAKAO2(CodeGenerator* code_gen){
  1615. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1616. const auto& param1 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1617. cg->mFormatter, _params[0]->getUnsigned(), _params[7]->getUnsigned()
  1618. );
  1619. const auto& param2 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1620. cg->mFormatter, _params[1]->getUnsigned(), _params[8]->getUnsigned()
  1621. );
  1622. const auto& param3 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1623. cg->mFormatter, _params[2]->getUnsigned(), _params[9]->getUnsigned()
  1624. );
  1625. const auto& param4 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1626. cg->mFormatter, _params[3]->getUnsigned(), _params[10]->getUnsigned()
  1627. );
  1628. const auto& param5 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1629. cg->mFormatter, _params[5]->getUnsigned(), _params[11]->getUnsigned()
  1630. );
  1631. auto op = _params[6]->getUnsigned();
  1632. code_gen->addOutputLine((
  1633. boost::format("-- music:execute_akao(0x%6$02x, %1%, %2%, %3%, %4%, %5%)")
  1634. % param1 % param2 % param3 % param4 % param5 % op
  1635. ).str());
  1636. }
  1637. void FF7::FF7AudioVideoInstruction::processMUSIC(CodeGenerator* code_gen){
  1638. code_gen->addOutputLine((
  1639. boost::format("-- music:execute_akao(0x10, pointer_to_field_AKAO_%1%)")
  1640. % _params[0]->getUnsigned()
  1641. ).str());
  1642. }
  1643. void FF7::FF7AudioVideoInstruction::processSOUND(CodeGenerator* code_gen){
  1644. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1645. const auto& soundId = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1646. cg->mFormatter, _params[0]->getUnsigned(), _params[2]->getUnsigned()
  1647. );
  1648. const auto& panning = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1649. cg->mFormatter, _params[1]->getUnsigned(), _params[3]->getUnsigned()
  1650. );
  1651. code_gen->addOutputLine(
  1652. (boost::format("-- music:execute_akao(0x20, %1%, %2%)") % soundId % panning).str()
  1653. );
  1654. }
  1655. void FF7::FF7AudioVideoInstruction::processAKAO(CodeGenerator* code_gen){
  1656. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1657. const auto& param1 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1658. cg->mFormatter, _params[0]->getUnsigned(), _params[7]->getUnsigned()
  1659. );
  1660. const auto& param2 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1661. cg->mFormatter, _params[1]->getUnsigned(), _params[8]->getUnsigned()
  1662. );
  1663. const auto& param3 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1664. cg->mFormatter, _params[2]->getUnsigned(), _params[9]->getUnsigned()
  1665. );
  1666. const auto& param4 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1667. cg->mFormatter, _params[3]->getUnsigned(), _params[10]->getUnsigned()
  1668. );
  1669. const auto& param5 = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1670. cg->mFormatter, _params[5]->getUnsigned(), _params[11]->getUnsigned()
  1671. );
  1672. auto op = _params[6]->getUnsigned();
  1673. code_gen->addOutputLine((
  1674. boost::format("-- music:execute_akao(0x%6$02x, %1%, %2%, %3%, %4%, %5%)")
  1675. % param1 % param2 % param3 % param4 % param5 % op
  1676. ).str());
  1677. }
  1678. void FF7::FF7AudioVideoInstruction::processMULCK(CodeGenerator* code_gen){
  1679. code_gen->addOutputLine((
  1680. boost::format("-- music:lock(%1%)")
  1681. % FF7CodeGeneratorHelpers::FormatBool(_params[0]->getUnsigned())
  1682. ).str());
  1683. }
  1684. void FF7::FF7AudioVideoInstruction::processPMVIE(CodeGenerator* code_gen){
  1685. code_gen->addOutputLine(
  1686. (boost::format("-- field:movie_set(%1%)") % _params[0]->getUnsigned()
  1687. ).str());
  1688. }
  1689. void FF7::FF7AudioVideoInstruction::processMOVIE(CodeGenerator* code_gen){
  1690. code_gen->addOutputLine("-- field:play_movie()");
  1691. }
  1692. void FF7::FF7AudioVideoInstruction::processMVIEF(CodeGenerator* code_gen){
  1693. // TODO: Check for assignment to value.
  1694. FF7SimpleCodeGenerator* cg = static_cast<FF7SimpleCodeGenerator*>(code_gen);
  1695. const auto& destination = FF7CodeGeneratorHelpers::FormatValueOrVariable(
  1696. cg->mFormatter, _params[1]->getUnsigned(), _params[2]->getUnsigned());
  1697. code_gen->addOutputLine(
  1698. (boost::format("-- %1% = field:get_movie_frame()") % destination).str()
  1699. );
  1700. }
  1701. void FF7::FF7UncategorizedInstruction::processInst(
  1702. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  1703. ){
  1704. FunctionMetaData md(func._metadata);
  1705. switch (_opcode){
  1706. case eOpcodes::MPDSP: WriteTodo(code_gen, md.EntityName(), "MPDSP"); break;
  1707. case eOpcodes::SETX: WriteTodo(code_gen, md.EntityName(), "SETX"); break;
  1708. case eOpcodes::GETX: WriteTodo(code_gen, md.EntityName(), "GETX"); break;
  1709. case eOpcodes::SEARCHX: WriteTodo(code_gen, md.EntityName(), "SEARCHX"); break;
  1710. default:
  1711. code_gen->addOutputLine(FF7CodeGeneratorHelpers::FormatInstructionNotImplemented(
  1712. md.EntityName(), _address, _opcode)
  1713. );
  1714. }
  1715. }
  1716. void FF7::FF7NoOperationInstruction::processInst(
  1717. Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
  1718. ){}