| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809 |
- /*
- * V-Gears
- * Copyright (C) 2022 V-Gears Team
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <iostream>
- #include <sstream>
- #include <stdexcept>
- #include <boost/format.hpp>
- #include "decompiler/field/instruction/FieldModelInstruction.h"
- #include "decompiler/field/FieldEngine.h"
- #include "decompiler/field/FieldCodeGenerator.h"
- #include "decompiler/field/FieldDisassembler.h"
- static bool TryParseFloat(const std::string& value, float& parsed_value){
- size_t parsed_length = 0;
- try{
- parsed_value = std::stof(value, &parsed_length);
- return parsed_length == value.size();
- }
- catch (const std::invalid_argument&){
- return false;
- }
- catch (const std::out_of_range&){
- return false;
- }
- }
- void FieldModelInstruction::ProcessInst(
- Function& func, ValueStack&, Engine* engine, CodeGenerator *code_gen
- ){
- FieldEngine& eng = static_cast<FieldEngine&>(*engine);
- FunctionMetaData md(func.metadata);
- //std::cout << "Model opcode: " << opcode_ << "\n";
- switch (opcode_){
- case OPCODES::JOIN: ProcessJOIN(code_gen); break;
- case OPCODES::SPLIT: ProcessSPLIT(code_gen); break;
- case OPCODES::BLINK: code_gen->WriteTodo(md.GetEntityName(), "BLINK"); break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::EYETX:
- code_gen->WriteTodo(md.GetEntityName(), "EYETX");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::TRNSP:
- code_gen->WriteTodo(md.GetEntityName(), "TRNSP");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::AMBNT:
- code_gen->WriteTodo(md.GetEntityName(), "AMBNT");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown03:
- code_gen->WriteTodo(md.GetEntityName(), "Unknown03");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown04:
- code_gen->WriteTodo(md.GetEntityName(), "Unknown04");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown05:
- code_gen->WriteTodo(md.GetEntityName(), "Unknown05");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::LIGHT:
- code_gen->WriteTodo(md.GetEntityName(), "LIGHT");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown07:
- code_gen->WriteTodo(md.GetEntityName(), "Unknown07");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown08:
- code_gen->WriteTodo(md.GetEntityName(), "Unknown08");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown09:
- code_gen->WriteTodo(md.GetEntityName(), "Unknown09");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::SBOBJ:
- code_gen->WriteTodo(md.GetEntityName(), "SBOBJ");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown0B:
- code_gen->WriteTodo(md.GetEntityName(), "Unknown0B");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::Unknown0C:
- code_gen->WriteTodo(md.GetEntityName(), "Unknown0C");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::SHINE:
- code_gen->WriteTodo(md.GetEntityName(), "SHINE");
- break;
- case (OPCODES::KAWAI << 8) | OPCODES_KAWAI::RESET:
- code_gen->WriteTodo(md.GetEntityName(), "RESET");
- break;
- case OPCODES::KAWIW: code_gen->WriteTodo(md.GetEntityName(), "KAWIW"); break;
- case OPCODES::PMOVA: code_gen->WriteTodo(md.GetEntityName(), "PMOVA"); break;
- case OPCODES::PDIRA: code_gen->WriteTodo(md.GetEntityName(), "PDIRA"); break;
- case OPCODES::PTURA: code_gen->WriteTodo(md.GetEntityName(), "PTURA"); break;
- case OPCODES::PGTDR: code_gen->WriteTodo(md.GetEntityName(), "PGTDR"); break;
- case OPCODES::PXYZI: code_gen->WriteTodo(md.GetEntityName(), "PXYZI"); break;
- case OPCODES::TLKON: ProcessTLKON(code_gen, md.GetEntityName()); break;
- case OPCODES::PC: ProcessPC(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
- case OPCODES::opCodeCHAR: ProcessCHAR(code_gen, md.GetEntityName()); break;
- case OPCODES::DFANM: ProcessDFANM(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
- case OPCODES::ANIME1:
- ProcessANIME1(code_gen, md.GetEntityName(), md.GetCharacterId());
- break;
- case OPCODES::VISI: ProcessVISI(code_gen, md.GetEntityName()); break;
- case OPCODES::XYZI: ProcessXYZI(code_gen, md.GetEntityName()); break;
- case OPCODES::XYI: code_gen->WriteTodo(md.GetEntityName(), "XYI"); break;
- case OPCODES::XYZ: code_gen->WriteTodo(md.GetEntityName(), "XYZ"); break;
- case OPCODES::MOVE: ProcessMOVE(code_gen, md.GetEntityName()); break;
- case OPCODES::CMOVE: code_gen->WriteTodo(md.GetEntityName(), "CMOVE"); break;
- case OPCODES::MOVA: ProcessMOVA(code_gen, md.GetEntityName(), eng); break;
- case OPCODES::TURA: ProcessTURA(code_gen, md.GetEntityName(), eng); break;
- case OPCODES::ANIMW: ProcessANIMW(code_gen, md.GetEntityName()); break;
- case OPCODES::FMOVE: ProcessFMOVE(code_gen, md.GetEntityName()); break;
- case OPCODES::ANIME2:
- ProcessANIME2(code_gen, md.GetEntityName(), md.GetCharacterId());
- break;
- case OPCODES::ANIM_1:
- ProcessANIM_1(code_gen, md.GetEntityName(), md.GetCharacterId());
- break;
- case OPCODES::CANIM1:
- ProcessCANIM1(code_gen, md.GetEntityName(), md.GetCharacterId());
- break;
- case OPCODES::CANM_1:
- ProcessCANM_1(code_gen, md.GetEntityName(), md.GetCharacterId());
- break;
- case OPCODES::MSPED: ProcessMSPED(code_gen, md.GetEntityName()); break;
- case OPCODES::DIR: ProcessDIR(code_gen, md.GetEntityName()); break;
- case OPCODES::TURNGEN: ProcessTURNGEN(code_gen, md.GetEntityName()); break;
- case OPCODES::TURN: code_gen->WriteTodo(md.GetEntityName(), "TURN"); break;
- case OPCODES::DIRA: ProcessDIRA(code_gen, md.GetEntityName(), eng); break;
- case OPCODES::GETDIR: code_gen->WriteTodo(md.GetEntityName(), "GETDIR"); break;
- case OPCODES::GETAXY: code_gen->WriteTodo(md.GetEntityName(), "GETAXY"); break;
- case OPCODES::GETAI: ProcessGETAI(code_gen, eng); break;
- case OPCODES::ANIM_2:
- ProcessANIM_2(code_gen, md.GetEntityName(), md.GetCharacterId());
- break;
- case OPCODES::CANIM2:
- ProcessCANIM2(code_gen, md.GetEntityName(), md.GetCharacterId());
- break;
- case OPCODES::CANM_2:
- ProcessCANM_2(code_gen, md.GetEntityName(), md.GetCharacterId());
- break;
- case OPCODES::ASPED: ProcessASPED(code_gen, md.GetEntityName()); break;
- case OPCODES::CC: ProcessCC(code_gen, eng); break;
- case OPCODES::JUMP: ProcessJUMP(code_gen, md.GetEntityName()); break;
- case OPCODES::AXYZI: ProcessAXYZI(code_gen); break;
- case OPCODES::LADER: ProcessLADER(code_gen, md.GetEntityName(), md.GetCharacterId()); break;
- case OPCODES::OFST: ProcessOFST(code_gen, md.GetEntityName()); break;
- case OPCODES::OFSTW:
- code_gen->AddOutputLine("self." + md.GetEntityName() + ":offset_sync()");
- break;
- case OPCODES::TALKR: ProcessTALKR(code_gen, md.GetEntityName()); break;
- case OPCODES::SLIDR: ProcessSLIDR(code_gen, md.GetEntityName()); break;
- case OPCODES::SOLID: ProcessSOLID(code_gen, md.GetEntityName()); break;
- case OPCODES::TLKR2: ProcessTALKR(code_gen, md.GetEntityName()); break;
- case OPCODES::SLDR2: code_gen->WriteTodo(md.GetEntityName(), "SLDR2"); break;
- case OPCODES::CCANM: code_gen->WriteTodo(md.GetEntityName(), "CCANM"); break;
- case OPCODES::FCFIX: code_gen->WriteTodo(md.GetEntityName(), "FCFIX"); break;
- case OPCODES::ANIMB: code_gen->WriteTodo(md.GetEntityName(), "ANIMB"); break;
- case OPCODES::TURNW: code_gen->WriteTodo(md.GetEntityName(), "TURNW"); break;
- default:
- code_gen->AddOutputLine(FieldCodeGenerator::FormatInstructionNotImplemented(
- md.GetEntityName(), address_, opcode_
- ));
- }
- }
- void FieldModelInstruction::ProcessJOIN(CodeGenerator* code_gen){
- code_gen->AddOutputLine("join_party(" + std::to_string(params_[0]->GetUnsigned()) + ")");
- }
- void FieldModelInstruction::ProcessSPLIT(CodeGenerator* code_gen){
- const std::vector<ValuePtr> parameters = GetParams();
- if (parameters.size() != 13){
- code_gen->WriteTodo("FieldModelInstruction", "SPLIT with malformed parameters");
- return;
- }
- for (const ValuePtr& parameter : parameters){
- if (parameter == nullptr || !parameter->IsInteger()){
- code_gen->WriteTodo("FieldModelInstruction", "SPLIT with invalid parameter");
- return;
- }
- }
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- const auto& ax = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned(), params_[6]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& ay = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(), params_[7]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& ar = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[2]->GetUnsigned(), params_[8]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& bx = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[3]->GetUnsigned(), params_[9]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& by = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[4]->GetUnsigned(), params_[10]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& br = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[5]->GetUnsigned(), params_[11]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& speed = params_[12]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("split_party(%1%, %2%, %3%, %4%, %5%, %6%, %7%)")
- % ax % ay % ar % bx % by % br % speed
- ).str());
- }
- void FieldModelInstruction::ProcessTLKON(CodeGenerator* code_gen, const std::string& entity){
- code_gen->AddOutputLine((
- boost::format("self.%1%:set_talkable(%2%)")
- % entity % FieldCodeGenerator::FormatInvertedBool(params_[0]->GetUnsigned())
- ).str());
- }
- void FieldModelInstruction::ProcessPC(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- code_gen->AddOutputLine(
- (boost::format("set_entity_to_character(\"%1%\", %2%)") % entity % char_id).str()
- );
- }
- void FieldModelInstruction::ProcessCHAR(CodeGenerator* code_gen, const std::string& entity){
- code_gen->AddOutputLine(
- (boost::format("self.%1% = entity_manager:get_entity(\"%1%\")") % entity).str()
- );
- // A model that has no animation playing is not drawn. The ones with no "Idle" animation need
- // a default one, which a DFANM later in the script replaces.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const std::string animation = cg->GetFormatter().GetDefaultAnimationName(params_[0]->GetSigned());
- // The walk and run animations are the second and the third of the model.
- const std::string walk = cg->GetFormatter().GetMoveAnimationName(params_[0]->GetSigned(), 1);
- const std::string run = cg->GetFormatter().GetMoveAnimationName(params_[0]->GetSigned(), 2);
- if (!walk.empty() && !run.empty() && (walk != "Walk" || run != "Run")){
- code_gen->AddOutputLine((
- boost::format("self.%1%:set_move_animations(\"%2%\", \"%3%\")") % entity % walk % run
- ).str());
- }
- if (!animation.empty()){
- code_gen->AddOutputLine((
- boost::format("self.%1%:set_default_animation(\"%2%\") -- No Idle animation")
- % entity % animation
- ).str());
- code_gen->AddOutputLine(
- (boost::format("self.%1%:play_animation(\"%2%\")") % entity % animation).str()
- );
- }
- }
- void FieldModelInstruction::ProcessDFANM(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- // ID will be fixed-up downstream.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- auto animation_id = params_[0]->GetUnsigned();
- // TODO: check for zero.
- auto speed = 1.0f / params_[1]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("self.%1%:set_default_animation(\"%2%\") -- speed %3%")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id) % speed
- ).str());
- code_gen->AddOutputLine((
- boost::format("self.%1%:play_animation(\"%2%\")")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id)
- ).str());
- }
- void FieldModelInstruction::ProcessANIME1(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- // ID will be fixed-up downstream.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- auto animation_id = params_[0]->GetUnsigned();
- // TODO: check for zero.
- auto speed = 1.0f / params_[1]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("self.%1%:play_animation(\"%2%\") -- speed %3%")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id) % speed
- ).str());
- code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessMOVA(
- CodeGenerator* code_gen, const std::string& entity, const FieldEngine& engine
- ){
- // Walks to the other entity, and waits until it is there.
- const auto& target = engine.EntityByIndex(params_[0]->GetUnsigned());
- code_gen->AddOutputLine((
- boost::format("self.%1%:move_to_entity(entity_manager:get_entity(\"%2%\"))")
- % entity % target.GetName()
- ).str());
- code_gen->AddOutputLine((boost::format("self.%1%:move_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessTALKR(CodeGenerator* code_gen, const std::string& entity){
- // The range is given in the same units as the positions.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- const std::string range_value = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned() + params_[1]->GetUnsigned(),
- params_[2]->GetUnsigned(), FieldCodeGenerator::ValueType::Float, scale
- );
- float range = 0;
- if (TryParseFloat(range_value, range)){
- code_gen->AddOutputLine(
- (boost::format("self.%1%:set_talk_radius(%2%)") % entity % range).str()
- );
- }
- else{
- // A variable: the scale is not applied yet.
- code_gen->AddOutputLine(
- "self." + entity + ":set_talk_radius((" + range_value + ") / " + std::to_string(scale) + ")"
- );
- }
- }
- void FieldModelInstruction::ProcessDIRA(
- CodeGenerator* code_gen, const std::string& entity, const FieldEngine& engine
- ){
- // Turns the model towards another entity at once.
- const auto& target = engine.EntityByIndex(params_[0]->GetUnsigned());
- code_gen->AddOutputLine((
- boost::format("self.%1%:face_entity(entity_manager:get_entity(\"%2%\"))")
- % entity % target.GetName()
- ).str());
- }
- void FieldModelInstruction::ProcessASPED(CodeGenerator* code_gen, const std::string& entity){
- // The value is the speed of the animations: 16 is the normal one, 32 double and 8 half.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const std::string speed_value = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned() + params_[1]->GetUnsigned(),
- params_[2]->GetUnsigned()
- );
- float speed = 0;
- if (TryParseFloat(speed_value, speed)){
- code_gen->AddOutputLine((
- boost::format("self.%1%:set_animation_speed(%2%)") % entity % (speed / 16.0f)
- ).str());
- }
- else{
- code_gen->AddOutputLine(
- "self." + entity + ":set_animation_speed((" + speed_value + ") / 16.0)"
- );
- }
- }
- void FieldModelInstruction::ProcessANIME2(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- // Like ANIME1, but the script doesn't wait for the animation to end.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- auto animation_id = params_[0]->GetUnsigned();
- auto speed = 1.0f / params_[1]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("self.%1%:play_animation(\"%2%\") -- speed %3%")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id) % speed
- ).str());
- }
- void FieldModelInstruction::ProcessANIM_1(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- // Like ANIM_2, but the script doesn't wait for the animation to end.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- auto animation_id = params_[0]->GetUnsigned();
- auto speed = 1.0f / params_[1]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("self.%1%:play_animation_stop(\"%2%\") -- speed %3%")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id) % speed
- ).str());
- }
- void FieldModelInstruction::ProcessCANIM1(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- // Like CANIM2, but the script doesn't wait for the animation to end.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- auto animation_id = params_[0]->GetUnsigned();
- auto start_frame = params_[1]->GetUnsigned() / 30.0f;
- auto end_frame = params_[2]->GetUnsigned() / 30.0f;
- auto speed = 1.0f / params_[3]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("self.%1%:play_animation(\"%2%\", %3%, %4%) -- speed %5%")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id)
- % start_frame % end_frame % speed
- ).str());
- }
- void FieldModelInstruction::ProcessCANM_1(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- // Like CANM_2, but the script doesn't wait for the animation to end.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- auto animation_id = params_[0]->GetUnsigned();
- auto start_frame = params_[1]->GetUnsigned() / 30.0f;
- auto end_frame = params_[2]->GetUnsigned() / 30.0f;
- auto speed = 1.0f / params_[3]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("self.%1%:play_animation_stop(\"%2%\", %3%, %4%) -- speed %5%")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id)
- % start_frame % end_frame % speed
- ).str());
- }
- void FieldModelInstruction::ProcessANIMW(CodeGenerator* code_gen, const std::string& entity){
- // Waits for the animation that was started with one of the non-waiting opcodes.
- code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessVISI(CodeGenerator* code_gen, const std::string& entity){
- code_gen->AddOutputLine((
- boost::format("self.%1%:set_visible(%2%)")
- % entity % FieldCodeGenerator::FormatBool(params_[0]->GetUnsigned())
- ).str());
- }
- void FieldModelInstruction::ProcessXYZI(CodeGenerator* code_gen, const std::string& entity){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- const auto& x = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned(), params_[4]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& y = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(), params_[5]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& z = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[2]->GetUnsigned(), params_[6]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& triangle_id = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[3]->GetUnsigned(), params_[7]->GetUnsigned()
- );
- code_gen->AddOutputLine((
- boost::format("self.%1%:set_position(%2%, %3%, %4%) -- triangle ID %5%")
- % entity % x % y % z % triangle_id
- ).str());
- }
- void FieldModelInstruction::ProcessMOVE(CodeGenerator* code_gen, const std::string& entity){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- const auto& x = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned(), params_[2]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& y = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(), params_[3]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- code_gen->AddOutputLine(
- (boost::format("self.%1%:move_to_position(%2%, %3%)") % entity % x % y).str()
- );
- code_gen->AddOutputLine((boost::format("self.%1%:move_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessFMOVE(CodeGenerator* code_gen, const std::string& entity){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- const auto& x = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned(), params_[2]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& y = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(), params_[3]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- // Like MOVE, but the animation is the one the script chose, not the walking one.
- code_gen->AddOutputLine((boost::format("self.%1%:move_auto_animation(false)") % entity).str());
- code_gen->AddOutputLine(
- (boost::format("self.%1%:move_to_position(%2%, %3%)") % entity % x % y).str()
- );
- code_gen->AddOutputLine((boost::format("self.%1%:move_sync()") % entity).str());
- code_gen->AddOutputLine((boost::format("self.%1%:move_auto_animation(true)") % entity).str());
- }
- void FieldModelInstruction::ProcessTURA(
- CodeGenerator* code_gen, const std::string& entity, const FieldEngine& engine
- ){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const auto& dest_entity = engine.EntityByIndex(params_[0]->GetSigned());
- std::string direction;
- switch (params_[1]->GetUnsigned()){
- case 0: direction = "Entity.CLOCKWISE"; break;
- case 1: direction = "Entity.ANTICLOCKWISE"; break;
- case 2: direction = "Entity.CLOSEST"; break;
- // Default to closest:
- default: direction = "Entity.CLOSEST"; break;
- }
- auto steps = params_[2]->GetUnsigned();
- const float scaled_steps = static_cast<float>(steps) / 30.0f;
- code_gen->AddOutputLine((
- boost::format("self.%1%:turn_to_entity(entity_manager:get_entity(\"%2%\"), %3%, %4%)")
- % entity % dest_entity.GetName() % direction % scaled_steps
- ).str());
- code_gen->AddOutputLine((boost::format("self.%1%:turn_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessMSPED(CodeGenerator* code_gen, const std::string& entity){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- const auto& speed = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(), params_[2]->GetUnsigned(),
- FieldCodeGenerator::ValueType::Float, 256.0f * scale / 30.0f
- );
- code_gen->AddOutputLine(
- (boost::format("self.%1%:set_move_auto_speed(%2%)") % entity % speed).str()
- );
- }
- void FieldModelInstruction::ProcessDIR(CodeGenerator* code_gen, const std::string& entity){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const auto& degrees = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned(), params_[1]->GetUnsigned(),
- FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
- );
- code_gen->AddOutputLine((boost::format("self.%1%:set_rotation(%2%)") % entity % degrees).str());
- }
- void FieldModelInstruction::ProcessTURNGEN(CodeGenerator* code_gen, const std::string& entity){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const auto& degrees = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(), params_[2]->GetUnsigned(),
- FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
- );
- std::string direction;
- switch (params_[3]->GetUnsigned()){
- case 0: direction = "Entity.CLOCKWISE"; break;
- case 1: direction = "Entity.ANTICLOCKWISE"; break;
- case 2: direction = "Entity.CLOSEST"; break;
- // Default to closest:
- default: direction = "Entity.CLOSEST"; break;
- }
- auto steps = params_[4]->GetUnsigned();
- std::string step_type;
- switch (params_[5]->GetUnsigned()){
- case 1: step_type = "Entity.LINEAR"; break;
- case 2: step_type = "Entity.SMOOTH"; break;
- // Default to smooth
- default: step_type = "Entity.SMOOTH"; break;
- }
- const float scaled_steps = static_cast<float>(steps) / 30.0f;
- code_gen->AddOutputLine((
- boost::format("self.%1%:turn_to_direction(%2%, %3%, %4%, %5%)")
- % entity % degrees % direction % step_type % scaled_steps
- ).str());
- code_gen->AddOutputLine((boost::format("self.%1%:turn_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessGETAI(CodeGenerator* code_gen, const FieldEngine& engine){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- // TODO: check for assignment to literal.
- const auto& variable = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(), params_[3]->GetUnsigned()
- );
- const auto& entity = engine.EntityByIndex(params_[2]->GetUnsigned());
- code_gen->AddOutputLine(
- (boost::format("%1% = entity_manager:get_entity(\"%2%\"):get_move_triangle_id()")
- % variable % entity.GetName()
- ).str());
- }
- void FieldModelInstruction::ProcessANIM_2(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- // ID will be fixed-up downstream.
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- auto animation_id = params_[0]->GetUnsigned();
- // TODO: check for zero.
- auto speed = 1.0f / params_[1]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("self.%1%:play_animation_stop(\"%2%\") -- speed %3%")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id) % speed
- ).str());
- code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessCANIM2(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- auto animation_id = params_[0]->GetUnsigned();
- auto start_frame = params_[1]->GetUnsigned() / 30.0f;
- auto end_frame = params_[2]->GetUnsigned() / 30.0f;
- // TODO: check for zero.
- auto speed = 1.0f / params_[3]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("self.%1%:play_animation(\"%2%\", %3%, %4%) -- speed %5%")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id)
- % start_frame % end_frame % speed
- ).str());
- code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessCANM_2(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- // ID will be fixed-up downstream.
- auto animation_id = params_[0]->GetUnsigned();
- auto start_frame = params_[1]->GetUnsigned() / 30.0f;
- auto end_frame = params_[2]->GetUnsigned() / 30.0f;
- // TODO: check for zero.
- auto speed = 1.0f / params_[3]->GetUnsigned();
- code_gen->AddOutputLine((
- boost::format("self.%1%:play_animation_stop(\"%2%\", %3%, %4%) -- speed %5%")
- % entity % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation_id)
- % start_frame % end_frame % speed
- ).str());
- code_gen->AddOutputLine((boost::format("self.%1%:animation_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessCC(CodeGenerator* code_gen, const FieldEngine& engine){
- const auto& entity = engine.EntityByIndex(params_[0]->GetUnsigned());
- code_gen->AddOutputLine(
- (boost::format("entity_manager:set_player_entity(\"%1%\")") % entity.GetName()).str()
- );
- }
- void FieldModelInstruction::ProcessJUMP(CodeGenerator* code_gen, const std::string& entity){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- const std::string x_value = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned(), params_[4]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const std::string y_value = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(), params_[5]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- float x = 0;
- float y = 0;
- const bool literal_coordinates
- = TryParseFloat(x_value, x) && TryParseFloat(y_value, y);
- int i = atoi(FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[2]->GetUnsigned(), params_[6]->GetSigned()
- ).c_str());
- int steps = atoi(FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[3]->GetUnsigned(), params_[7]->GetSigned()
- ).c_str());
- //x *= 0.00781250273224;
- //y *= 0.00781250273224;
- // Always force reduce steps and bound it between 1 and 5.
- steps /= 6;
- if (steps < 1) steps = 1;
- if (steps > 5) steps = 5;
- // TODO: Z hardcoded as -1, handled in Entity::ScriptJumpToPosition.
- // TODO: Hardcoded 0.5 in seconds. Calculate using distance.
- if (literal_coordinates){
- code_gen->AddOutputLine((
- boost::format("self.%1%:jump_to_position(%2%, %3%, -1, 0.5, %4%) -- %5% steps.")
- % entity % x % y % i % steps
- ).str());
- }
- else{
- code_gen->AddOutputLine(
- "self." + entity + ":jump_to_position(" + x_value + ", " + y_value
- + ", -1, 0.5, " + std::to_string(i) + ")"
- );
- }
- code_gen->AddOutputLine((boost::format("self.%1%:jump_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessAXYZI(CodeGenerator* code_gen){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- code_gen->AddOutputLine((
- boost::format("axyzi(%1%, %2%, %3%, %4%, %5%, %6%, %7%, %8%, %9%, %10%)")
- % params_[0]->GetSigned() % params_[1]->GetSigned() % params_[2]->GetSigned()
- % params_[3]->GetSigned() % params_[4]->GetSigned() % params_[5]->GetSigned()
- % params_[6]->GetSigned() % params_[7]->GetSigned() % params_[8]->GetSigned()
- % scale
- ).str());
- }
- void FieldModelInstruction::ProcessLADER(
- CodeGenerator* code_gen, const std::string& entity, int char_id
- ){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- const auto& x = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned(), params_[4]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& y = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(), params_[5]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const auto& z = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[2]->GetUnsigned(), params_[6]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- uint end_triangle = atoi(FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[3]->GetUnsigned(), params_[7]->GetUnsigned()
- ).c_str());
- uint keys = params_[8]->GetUnsigned();
- uint animation = params_[9]->GetUnsigned();
- //float orientation = params_[10]->GetUnsigned() / (256.0f / 360.0f);
- const auto& orientation = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), 0, params_[10]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, 256.0f / 360.0f
- );
- uint speed = params_[11]->GetUnsigned();
- // TODO: Orientation and speed not set.
- code_gen->AddOutputLine((
- boost::format(
- "self.%1%:linear_to_position(%2%, %3%, %4%, %5%, \"%10%\", %6%, %7%) "
- "-- Animation %8% -- Speed %9%"
- ) % entity % x % y % z % keys % orientation % end_triangle % animation % speed
- % cg->GetFormatter().GetFriendlyAnimationName(char_id, animation)
- ).str());
- code_gen->AddOutputLine((boost::format("self.%1%:linear_sync()") % entity).str());
- }
- void FieldModelInstruction::ProcessSLIDR(CodeGenerator* code_gen, const std::string& entity){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- // The documentation says the value should be in param_[1], but it's actually on param_[2]
- const std::string radius_value = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned(), params_[2]->GetUnsigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- float radius = 0;
- if (TryParseFloat(radius_value, radius)){
- code_gen->AddOutputLine((
- boost::format("self.%1%:set_solid_radius(%2%)")
- % entity % radius
- ).str());
- }
- else{
- code_gen->AddOutputLine(
- "self." + entity + ":set_solid_radius(" + radius_value + ")"
- );
- }
- }
- void FieldModelInstruction::ProcessSOLID(CodeGenerator* code_gen, const std::string& entity){
- code_gen->AddOutputLine((
- boost::format("self.%1%:set_solid(%2%)")
- % entity % FieldCodeGenerator::FormatInvertedBool(params_[0]->GetUnsigned())
- ).str());
- }
- void FieldModelInstruction::ProcessOFST(CodeGenerator* code_gen, const std::string& entity){
- FieldCodeGenerator* cg = static_cast<FieldCodeGenerator*>(code_gen);
- const float scale = 128.0f * cg->GetScaleFactor();
- const std::string x_value = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[0]->GetUnsigned(), params_[5]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const std::string y_value = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[1]->GetUnsigned(),params_[6]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const std::string z_value = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[2]->GetUnsigned(), params_[7]->GetSigned(),
- FieldCodeGenerator::ValueType::Float, scale
- );
- const std::string speed_value = FieldCodeGenerator::FormatValueOrVariable(
- cg->GetFormatter(), params_[3]->GetUnsigned(), params_[8]->GetUnsigned()
- );
- float x = 0;
- float y = 0;
- float z = 0;
- float speed = 0;
- const bool literal_values
- = TryParseFloat(x_value, x) && TryParseFloat(y_value, y)
- && TryParseFloat(z_value, z) && TryParseFloat(speed_value, speed);
- std::string move_type;
- switch (params_[4]->GetUnsigned()){
- case 0: move_type = "Entity.NONE"; break;
- case 1: move_type = "Entity.LINEAR"; break;
- case 2: move_type = "Entity.SMOOTH"; break;
- default:
- code_gen->WriteTodo(entity, "OFST with unsupported movement type");
- return;
- }
- if (literal_values){
- speed /= 30.0f;
- code_gen->AddOutputLine((
- boost::format("self.%1%:offset_to_position(%2%, %3%, %4%, %5%, %6%)")
- % entity % x % y % z % move_type % speed
- ).str());
- }
- else{
- code_gen->AddOutputLine(
- "self." + entity + ":offset_to_position(" + x_value + ", " + y_value
- + ", " + z_value + ", " + move_type + ", (" + speed_value + ") / 30.0)"
- );
- }
- }
|