#include "battle.h" #include #include #include #include #include #include #include #include // #include #include "../world.h" #include "..//battle.h" #include #include #include #include #include #include #include #include namespace { ext::Gui* circleIn; ext::Gui* circleOut; ext::Gui* battleMessage; ext::Gui* commandOptions; ext::Gui* battleOptions; ext::Gui* targetOptions; ext::Gui* optionsBackground; ext::Gui* turnCounters; ext::Gui* partyMemberCommandCircle; ext::Gui* critCutInBackground; ext::Gui* critCutIn; std::vector partyMemberButtons(5); // std::vector partyMemberIcons(5); // std::vector partyMemberTexts(5); std::vector particles; ext::HousamoBattle* battleManager; ext::World* world; uf::Serializer masterTableGet( const std::string& table ) { if ( !world ) world = (ext::World*) uf::Entity::globalFindByName("World"); if ( !world ) return std::string(); uf::Serializer& mastertable = world->getComponent(); return mastertable["system"]["mastertable"][table]; } uf::Serializer masterDataGet( const std::string& table, const std::string& key ) { if ( !world ) world = (ext::World*) uf::Entity::globalFindByName("World"); if ( !world ) return std::string(); uf::Serializer& mastertable = world->getComponent(); return mastertable["system"]["mastertable"][table][key]; } inline int64_t parseInt( const std::string& str ) { return atoi(str.c_str()); } inline std::string colorString( const std::string& hex ) { return "%#" + hex + "%"; } void playSound( ext::GuiBattle& entity, const std::string& id, const std::string& key ) { if ( !world ) world = (ext::World*) uf::Entity::globalFindByName("World"); if ( !world ) return; uf::Serializer& masterdata = world->getComponent(); uf::Serializer cardData = masterDataGet("Card", id); uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); std::string name = charaData["filename"].asString(); if ( name == "none" ) return; std::string url = "https://cdn..xyz//unity/Android/voice/voice_" + name + "_"+key+".ogg"; if ( charaData["internal"].asBool() ) { url = "/smtsamo/voice/voice_" + name + "_" + key + ".ogg"; } uf::Asset& assetLoader = world->getComponent(); assetLoader.cache(url, "asset:Cache.Voice." + std::to_string(entity.getUid())); } void playSound( ext::GuiBattle& entity, std::size_t uid, const std::string& key ) { if ( !world ) world = (ext::World*) uf::Entity::globalFindByName("World"); if ( !world ) return; uf::Serializer& pMetadata = entity.getComponent(); uf::Serializer& masterdata = world->getComponent(); uf::Entity* = world->findByUid(uid); if ( ! ) return; uf::Serializer& metadata = ->getComponent(); std::string id = metadata[""]["id"].asString(); playSound( entity, id, key ); } void playSound( ext::GuiBattle& entity, const std::string& key ) { if ( !world ) world = (ext::World*) uf::Entity::globalFindByName("World"); if ( !world ) return; uf::Serializer& metadata = entity.getComponent(); uf::Serializer& masterdata = world->getComponent(); std::string url = "./data/audio/ui/" + key + ".ogg"; uf::Asset& assetLoader = world->getComponent(); assetLoader.cache(url, "asset:Cache.SFX." + std::to_string(entity.getUid())); } void playMusic( ext::GuiBattle& entity, const std::string& filename ) { if ( !world ) world = (ext::World*) uf::Entity::globalFindByName("World"); if ( !world ) return; uf::Asset& assetLoader = world->getComponent(); uf::Serializer& masterdata = world->getComponent(); assetLoader.load(filename, "asset:Load." + std::to_string(world->getUid())); } std::string getKeyFromIndex( uf::Serializer& object, uint64_t index ) { uint64_t i = 0; std::string key = ""; for ( auto it = object.begin(); it != object.end(); ++it ) { if ( i++ == index ) key = it.key().asString(); } return key; } uf::Audio sfx; uf::Audio voice; struct BattleStats { struct { int selection = 0; int selectionsMax = 3; std::vector invalids; } skill; struct { int selection = 0; int selectionsMax = 3; std::vector invalids; uf::Serializer current; } actions; struct { int selection = 0; int selectionsMax = 3; std::vector invalids; uf::Serializer current; } targets; uf::Serializer currentMember; uf::Serializer previousMember; std::string state = "open"; bool initialized = false; }; static BattleStats stats; } void ext::GuiBattle::initialize() { ext::Gui::initialize(); uf::Serializer& metadata = this->getComponent(); battleManager = (ext::HousamoBattle*) this->getRootParent().findByName( "Battle Manager" ); partyMemberButtons = std::vector(5); this->addHook( "asset:Cache.SFX." + std::to_string(this->getUid()), [&](const std::string& event)->std::string{ uf::Serializer json = event; std::string filename = json["filename"].asString(); if ( uf::string::extension(filename) != "ogg" ) return "false"; if ( filename == "" ) return "false"; uf::Serializer& masterdata = world->getComponent(); uf::Audio& sfx = this->getComponent().add(filename); /* uf::Audio& sfx = this->getComponent(); if ( sfx.playing() ) sfx.stop(); sfx = uf::Audio(); sfx.load(filename); */ sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); sfx.play(); return "true"; }); this->addHook( "asset:Cache.Voice." + std::to_string(this->getUid()), [&](const std::string& event)->std::string{ uf::Serializer json = event; std::string filename = json["filename"].asString(); if ( uf::string::extension(filename) != "ogg" ) return "false"; if ( filename == "" ) return "false"; uf::Serializer& masterdata = world->getComponent(); uf::Audio& voice = this->getComponent(); if ( voice.playing() ) voice.stop(); voice = uf::Audio(); voice.load(filename); voice.setVolume(masterdata["volumes"]["voice"].asFloat()); voice.play(); return "true"; }); // lock control { uf::Serializer payload; payload["state"] = true; uf::hooks.call("window:Mouse.CursorVisibility", payload); uf::hooks.call("window:Mouse.Lock"); } { battleMessage = new ext::Gui; this->addChild(*battleMessage); battleMessage->load("./battle-text.json", true); battleMessage->initialize(); } /* Magic Circle Outter */ { circleOut = new ext::Gui; this->addChild(*circleOut); circleOut->load("./circle-out.json", true); circleOut->initialize(); } /* Magic Circle Inner */ { circleIn = new ext::Gui; this->addChild(*circleIn); circleIn->load("./circle-in.json", true); circleIn->initialize(); } /* Command Circle */ { partyMemberCommandCircle = new ext::Gui; this->addChild(*partyMemberCommandCircle); partyMemberCommandCircle->load("./partyMemberCommandCircle.json", true); partyMemberCommandCircle->initialize(); } /* Command Circle */ { optionsBackground = new ext::Gui; this->addChild(*optionsBackground); optionsBackground->load("./optionsBackground.json", true); optionsBackground->initialize(); } /* Turn Counter Container */ { turnCounters = new ext::Gui; this->addChild(*turnCounters); turnCounters->load("./turnCounters.json", true); turnCounters->initialize(); } this->addHook("world:Battle.TurnStart.%UID%", [&](const std::string& event) -> std::string { uf::Serializer json = event; // turn start, play sfx if ( json["battle"]["turn"]["start of turn"].asBool() ) { playSound(*this, "turn"); } return "true"; }); this->addHook("world:Battle.Damage.%UID%", [&](const std::string& event) -> std::string { uf::Serializer json = event; std::string uid = json["target"]["uid"].asString(); std::string damage = json["target"]["damage"].asString(); pod::Transform<> pTransform; pTransform.position = { 0, 0, 0 }; for ( auto* pointerButton : partyMemberButtons ) { if ( !pointerButton ) continue; if ( pointerButton->getUid() == 0 ) continue; for ( auto* pointer : pointerButton->getChildren() ) { if ( !pointer ) continue; if ( pointer->getUid() == 0 ) continue; if ( pointer->getName() == "Menu: Party Member Icon" ) { uf::Serializer& pMetadata = pointer->getComponent(); if ( pMetadata[""]["uid"].asString() != uid ) continue; pTransform = pointer->getComponent>(); pTransform.position.y -= (0.1); } } } ext::Gui* particle = new ext::Gui; this->addChild(*particle); uf::Serializer& pMetadata = particle->getComponent(); particle->load("./damageText.json", true); std::string color = json["color"].isString() ? json["color"].asString() : "FF0000"; pMetadata["text settings"]["string"] = "%#"+color+"%" + damage; pod::Transform<>& transform = particle->getComponent>(); transform = pTransform; pMetadata["system"]["percent"] = 0; particle->initialize(); particles.push_back(particle); return "true"; }); this->addHook("world:Battle.Message.%UID%", [&](const std::string& event) -> std::string { uf::Serializer json = event; std::string message = json["message"].asString(); if ( battleMessage ) { battleMessage->destroy(); this->removeChild(*battleMessage); delete battleMessage; } battleMessage = new ext::Gui; this->addChild(*battleMessage); uf::Serializer& pMetadata = battleMessage->getComponent(); battleMessage->load("./battle-text.json", true); pMetadata["text settings"]["string"] = message; battleMessage->initialize(); // std::cout << message << std::endl; return "true"; }); this->addHook("world:Battle.RemoveOnCrit.%UID%", [&](const std::string& event) -> std::string { if ( critCutInBackground && critCutInBackground->getUid() != 0 ) { critCutInBackground->destroy(); this->removeChild(*critCutInBackground); delete critCutInBackground; critCutInBackground = NULL; } if ( critCutIn && critCutIn->getUid() != 0 ) { critCutIn->destroy(); this->removeChild(*critCutIn); delete critCutIn; critCutIn = NULL; } return "true"; }); this->addHook("world:Battle.OnCrit.%UID%", [&](const std::string& event) -> std::string { uf::Serializer json = event; if ( critCutInBackground && critCutInBackground->getUid() != 0 ) { critCutInBackground->destroy(); this->removeChild(*critCutInBackground); delete critCutInBackground; critCutInBackground = NULL; } if ( critCutIn && critCutIn->getUid() != 0 ) { critCutIn->destroy(); this->removeChild(*critCutIn); delete critCutIn; critCutIn = NULL; } { critCutInBackground = new ext::Gui; this->addChild(*critCutInBackground); critCutInBackground->load("./critCutInBackground.json", true); critCutInBackground->initialize(); } { critCutIn = new ext::Gui; this->addChild(*critCutIn); uf::Serializer& pMetadata = critCutIn->getComponent(); uf::Serializer cardData = masterDataGet("Card", json["id"].asString()); pMetadata["system"]["assets"][0] = "/smtsamo/ci/ci_"+ cardData["filename"].asString() +".png"; if ( !uf::string::exists( pMetadata["system"]["assets"][0].asString() ) ) pMetadata["system"]["assets"][0] = Json::nullValue; critCutIn->load("./critCutIn.json", true); critCutIn->initialize(); } playSound(*this, "crit"); this->queueHook("world:Battle.RemoveOnCrit.%UID%", "", 1.0); return "true"; }); this->addHook("world:Battle.Update.%UID%", [&](const std::string& event) -> std::string { uf::Serializer json = event; { float turns = json["battle"]["turn"]["counter"].asFloat(); if ( turnCounters && turnCounters->getUid() != 0 ) { this->removeChild(*turnCounters); turnCounters->destroy(); delete turnCounters; } { turnCounters = new ext::Gui; this->addChild(*turnCounters); turnCounters->load("./turnCounters.json", true); turnCounters->initialize(); } // show full counters float i = 0; while ( turns > 0 ) { ext::Gui* counter = new ext::Gui; turnCounters->addChild(*counter); counter->load("./turnCounter.json", true); counter->initialize(); pod::Transform<>& pTransform = counter->getComponent>(); pTransform.position.x -= 0.142716f * (i++); uf::Serializer& pMetadata = counter->getComponent(); if ( json["battle"]["turn"]["phase"] == "enemy" ) { pMetadata["color"][0] = 1.0f; pMetadata["color"][1] = 0.4f; pMetadata["color"][2] = 0.4f; pMetadata["color"][3] = 1.0f; } else { pMetadata["color"][0] = 0.4f; pMetadata["color"][1] = 0.0f; pMetadata["color"][2] = 0.8f; pMetadata["color"][3] = 1.0f; } // if ( turns < 1.0f && turns > 0 ) pMetadata["uv"][0] = 0.5f; if ( turns < 1.0f && turns > 0 ) { pMetadata["half counter"] = true; if ( json["battle"]["turn"]["phase"] == "enemy" ) { pMetadata["color"][0] = 1.0f; pMetadata["color"][1] = 0.7f; pMetadata["color"][2] = 0.7f; pMetadata["color"][3] = 1.0f; } else { pMetadata["color"][0] = 0.4f; pMetadata["color"][1] = 0.3f; pMetadata["color"][2] = 0.9f; pMetadata["color"][3] = 1.0f; } } turns = turns - 1.0f; } } int i = 0; for ( auto& member : json["battle"]["transients"] ) { if ( member["uid"].isNull() ) continue; if ( member["type"] == "enemy" ) continue; if ( member["hp"].asFloat() <= 0 ) continue; if ( i >= 4 ) break; uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); std::string name = cardData["filename"].asString(); if ( member["skin"].isString() ) name += "_" + member["skin"].asString(); std::string filename = "https://cdn..xyz//unity/Android/icon/icon_" + name + ".png"; if ( cardData["internal"].asBool() ) { filename = "/smtsamo/icon/icon_" + name + ".png"; } ext::Gui* partyMemberButton = NULL; pod::Transform<> bTransform; // completely recreate if different transient if ( partyMemberButtons[i] != NULL ) { partyMemberButton = partyMemberButtons[i]; uf::Serializer& pMetadata = partyMemberButton->getComponent(); if ( pMetadata[""]["id"] != member["id"] ) { this->removeChild(*partyMemberButton); partyMemberButton->destroy(); delete partyMemberButton; partyMemberButton = NULL; } else { pod::Transform<>& transform = partyMemberButton->getComponent>(); bTransform = transform; } } // update if ( partyMemberButton ) { { ext::Gui* partyMemberText = (ext::Gui*) partyMemberButton->findByName("Menu: Party Member Text"); if ( partyMemberText ) { partyMemberButton->removeChild(*partyMemberText); partyMemberText->destroy(); delete partyMemberText; partyMemberText = NULL; } partyMemberText = new ext::Gui; partyMemberButton->addChild(*partyMemberText); uf::Serializer& pMetadata = partyMemberText->getComponent(); partyMemberText->load("./partyMemberText.json", true); pMetadata["text settings"]["string"] = "" + colorString("00FF00") + "" + member["hp"].asString() + "\n" + colorString("0000FF") + "" + member["mp"].asString(); pMetadata[""] = member; pod::Transform<>& transform = partyMemberText->getComponent>(); transform.position = bTransform.position; transform.position.x += (-0.781352 - -0.694634) + 0.1; partyMemberText->initialize(); } ext::Gui* partyMemberHP = (ext::Gui*) partyMemberButton->findByName("Menu: Party Member HP Bar"); if ( partyMemberHP ) { uf::Serializer& pMetadata = partyMemberHP->getComponent(); float percentage = 1.0f; percentage = member["hp"].asFloat() / member["max hp"].asFloat(); // uv[0, 0] -> uv[09.43, 23.81] // uv[1, 1] -> uv[84.91, 68.25] pMetadata["uv"][2] = (percentage * 0.8491) + 0.0660; // pMetadata["uv"][3] = (percentage * 0.6808) + (1 - 0.0952); } ext::Gui* partyMemberMP = (ext::Gui*) partyMemberButton->findByName("Menu: Party Member MP Bar"); if ( partyMemberMP ) { uf::Serializer& pMetadata = partyMemberMP->getComponent(); float percentage = 1.0f; percentage = member["mp"].asFloat() / member["max mp"].asFloat(); // uv[0, 0] -> uv[09.43, 23.81] // uv[1, 1] -> uv[84.91, 68.25] pMetadata["uv"][2] = (percentage * 0.8491) + 0.0943; // pMetadata["uv"][3] = (percentage * 0.6825) + (1 - 0.2381); } // recreate } else { { partyMemberButton = new ext::Gui; this->addChild(*partyMemberButton); partyMemberButton->load("./partyMemberButton.json", true); pod::Transform<>& transform = partyMemberButton->getComponent>(); transform.position.y += (i * 0.45); bTransform = transform; partyMemberButton->initialize(); uf::Serializer& pMetadata = partyMemberButton->getComponent(); pMetadata[""] = member; partyMemberButtons[i] = partyMemberButton; } { ext::Gui* partyMemberIconShadow = NULL; partyMemberIconShadow = new ext::Gui; partyMemberButton->addChild(*partyMemberIconShadow); uf::Serializer& pMetadata = partyMemberIconShadow->getComponent(); pMetadata["system"]["assets"][0] = filename; partyMemberIconShadow->load("./partyMemberIconShadow.json", true); pMetadata[""] = member; pod::Transform<>& transform = partyMemberIconShadow->getComponent>(); transform.position = bTransform.position; transform.position.x += (-0.781352 - -0.694634) + 0.01; transform.position.y -= 0.01; partyMemberIconShadow->initialize(); } { ext::Gui* partyMemberIcon = NULL; partyMemberIcon = new ext::Gui; partyMemberButton->addChild(*partyMemberIcon); uf::Serializer& pMetadata = partyMemberIcon->getComponent(); pMetadata["system"]["assets"][0] = filename; partyMemberIcon->load("./partyMemberIcon.json", true); pMetadata[""] = member; pod::Transform<>& transform = partyMemberIcon->getComponent>(); transform.position = bTransform.position; transform.position.x += (-0.781352 - -0.694634); partyMemberIcon->initialize(); } { ext::Gui* partyMemberText = NULL; partyMemberText = new ext::Gui; partyMemberButton->addChild(*partyMemberText); uf::Serializer& pMetadata = partyMemberText->getComponent(); partyMemberText->load("./partyMemberText.json", true); pMetadata["text settings"]["string"] = "" + colorString("FF0000") + "" + member["hp"].asString() + "\n" + colorString("0000FF") + "" + member["mp"].asString(); pMetadata[""] = member; pod::Transform<>& transform = partyMemberText->getComponent>(); transform.position = bTransform.position; transform.position.x += (-0.781352 - -0.694634) + 0.1; partyMemberText->initialize(); } { ext::Gui* partyMemberBar = new ext::Gui; partyMemberButton->addChild(*partyMemberBar); partyMemberBar->load("./partyMemberBars.json", true); pod::Transform<>& transform = partyMemberBar->getComponent>(); transform.position = bTransform.position; transform.position.x = 0.742573; transform.position.y += 0.1; partyMemberBar->initialize(); } { ext::Gui* partyMemberHP = new ext::Gui; partyMemberButton->addChild(*partyMemberHP); partyMemberHP->load("./partyMemberHP.json", true); pod::Transform<>& transform = partyMemberHP->getComponent>(); transform.position = bTransform.position; transform.position.x = 0.742573; transform.position.y += 0.1; partyMemberHP->initialize(); uf::Serializer& pMetadata = partyMemberHP->getComponent(); float percentage = 1.0f; percentage = member["hp"].asFloat() / member["max hp"].asFloat(); // uv[0, 0] -> uv[09.43, 23.81] // uv[1, 1] -> uv[84.91, 68.25] pMetadata["uv"][2] = (percentage * 0.8491) + 0.0660; // pMetadata["uv"][3] = (percentage * 0.6808) + (1 - 0.0952); } { ext::Gui* partyMemberMP = new ext::Gui; partyMemberButton->addChild(*partyMemberMP); partyMemberMP->load("./partyMemberMP.json", true); pod::Transform<>& transform = partyMemberMP->getComponent>(); transform.position = bTransform.position; transform.position.x = 0.742573; transform.position.y += 0.1; partyMemberMP->initialize(); uf::Serializer& pMetadata = partyMemberMP->getComponent(); float percentage = 1.0f; percentage = member["mp"].asFloat() / member["max mp"].asFloat(); // uv[0, 0] -> uv[09.43, 23.81] // uv[1, 1] -> uv[84.91, 68.25] pMetadata["uv"][2] = (percentage * 0.8491) + 0.0943; // pMetadata["uv"][3] = (percentage * 0.6825) + (1 - 0.2381); } } ++i; }; for ( ; i < 4; ++i ) { if ( partyMemberButtons[i] != NULL ) { ext::Gui*& partyMemberButton = partyMemberButtons[i]; this->removeChild(*partyMemberButton); partyMemberButton->destroy(); delete partyMemberButton; partyMemberButton = NULL; } } return "true"; }); this->addHook("menu:Close.%UID%", [&]( const std::string& event ) -> std::string { // kill this->getParent().removeChild(*this); this->destroy(); delete this; return "true"; }); stats = BattleStats(); } void ext::GuiBattle::tick() { if ( !battleManager ) return; ext::World& world = this->getRootParent(); uf::Serializer& masterdata = world.getComponent(); uf::Serializer& bMetadata = this->getComponent(); static float alpha = 0.0f; static uf::Timer timer(false); static float timeout = 1.0f; if ( !timer.running() ) timer.start(); static std::string queuedAction; std::function postParseResult = [&]( uf::Serializer& result ) { if ( result["end"].asBool() ) bMetadata["system"]["closing"] = true; if ( !result["timeout"].isNull() ) timeout = result["timeout"].asFloat(); else timeout = 1; // modify timeout based on string length if ( result["message"].isString() && !result["target"].isNull() ) { uint64_t size = result["message"].asString().size(); float modified = size * 0.025f; if ( timeout < modified ) timeout = modified; } uf::Serializer payload; payload["message"] = result["message"]; this->callHook("world:Battle.Message.%UID%", payload); timer.reset(); }; std::function renderSkillOptions = [&]( uf::Serializer member ) { if ( battleOptions ) { this->removeChild(*battleOptions); battleOptions->destroy(); delete battleOptions; battleOptions = NULL; } if ( member["uid"].isNull() ) { stats.previousMember = stats.currentMember; return; } stats.currentMember = member; std::string string = ""; std::size_t counter = 0; std::size_t start = stats.skill.selection; stats.actions.invalids.clear(); stats.currentMember["skills"] = Json::arrayValue; for ( int i = 0; i < member["skills"].size(); ++i ) { std::string id = member["skills"][i].asString(); uf::Serializer skillData = masterDataGet("Skill", id); bool add = false; if ( skillData["type"].asInt() > 0 && skillData["type"].asInt() < 16 ) add = true; if ( add ) stats.currentMember["skills"].append(id); } std::string skillDescription = ""; for ( int i = start; i < stats.currentMember["skills"].size(); ++i ) { std::string id = stats.currentMember["skills"][i].asString(); std::string text = ""; if ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), id ) != stats.skill.invalids.end() ) continue; if ( ++counter > stats.skill.selectionsMax ) break; uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); uf::Serializer skillData = masterDataGet("Skill", id); if ( id != "0" ) { text = skillData["name"].asString(); } else { text = "攻撃"; } if ( i != stats.skill.selection ) { text = "" + colorString("FFFFFF") + "" + text; } else { text = "" + colorString("FF0000") + "" + text; skillDescription = skillData["effect"].asString(); if ( skillData["mp"].isNumeric() ) { int64_t cost = skillData["mp"].asInt64(); skillDescription = skillData["effect"].asString() + "\nCost: " + colorString("0000FF") + ""+std::to_string(cost)+" MP" + colorString("FFFFFF") + ""; } if ( skillData["hp%"].isNumeric() ) { int64_t cost = skillData["hp%"].asInt64(); cost = member["max hp"].asFloat() * ( cost / 100.0f ); skillDescription = skillData["effect"].asString() + "\nCost: " + colorString("00FF00") + ""+std::to_string(cost)+" HP" + colorString("FFFFFF") + ""; } } string += "\n" + text; } if ( stats.currentMember["skills"].size() > stats.skill.selectionsMax ) { for ( int i = 0; i < stats.currentMember["skills"].size(); ++i ) { std::string id = stats.currentMember["skills"][i].asString(); std::string text = ""; if ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), id ) != stats.skill.invalids.end() ) continue; if ( ++counter > stats.skill.selectionsMax ) break; if ( id != "0" ) { uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); uf::Serializer skillData = masterDataGet("Skill", id); text = skillData["name"].asString(); } else { uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); text = "攻撃"; } if ( i != stats.skill.selection ) text = "" + colorString("FFFFFF") + "" + text; else text = "" + colorString("FF0000") + "" + text; string += "\n" + text; } } if ( string != "" ) { string = string.substr(1); battleOptions = new ext::Gui; this->addChild(*battleOptions); uf::Serializer& pMetadata = battleOptions->getComponent(); battleOptions->load("./battle-option.json", true); pMetadata["text settings"]["string"] = string; pod::Transform<>& pTransform = battleOptions->getComponent>(); battleOptions->initialize(); } if ( skillDescription != "" ) { uf::Serializer payload; payload["message"] = skillDescription; this->callHook("world:Battle.Message.%UID%", payload); } }; std::function renderCommandOptions = [&]( uf::Serializer actions ) { if ( commandOptions ) { this->removeChild(*commandOptions); commandOptions->destroy(); delete commandOptions; commandOptions = NULL; } if ( actions.isNull() ) { stats.actions.selection = 0; queuedAction = ""; return; } stats.actions.current = actions; std::string string = ""; std::size_t counter = 0; std::size_t start = stats.actions.selection; auto keys = actions.getMemberNames(); for ( int i = start; i < keys.size(); ++i ) { std::string key = getKeyFromIndex( actions, i ); std::string text = actions[key].asString(); if ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), key ) != stats.actions.invalids.end() ) continue; if ( ++counter > stats.actions.selectionsMax ) break; if ( i != stats.actions.selection ) text = "" + colorString("FFFFFF") + "" + text; else text = "" + colorString("FF0000") + "" + text; string += "\n" + text; } if ( keys.size() > stats.actions.selectionsMax ) { for ( int i = 0; i < keys.size(); ++i ) { std::string key = getKeyFromIndex( actions, i ); std::string text = actions[key].asString(); if ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), key ) != stats.actions.invalids.end() ) continue; if ( ++counter > stats.actions.selectionsMax ) break; if ( i != stats.actions.selection ) text = "" + colorString("FFFFFF") + "" + text; else text = "" + colorString("FF0000") + "" + text; string += "\n" + text; } } if ( string != "" ) { string = string.substr(1); commandOptions = new ext::Gui; this->addChild(*commandOptions); uf::Serializer& pMetadata = commandOptions->getComponent(); commandOptions->load("./battle-option.json", true); pMetadata["text settings"]["string"] = string; pod::Transform<>& pTransform = commandOptions->getComponent>(); commandOptions->initialize(); } }; std::function renderTargetOptions = [&]( uf::Serializer actions ) { if ( targetOptions ) { this->removeChild(*targetOptions); targetOptions->destroy(); delete targetOptions; targetOptions = NULL; } if ( actions.isNull() ) { stats.skill.selection = 0; stats.targets.selection = 0; return; } stats.targets.current = actions; std::string string = ""; std::size_t counter = 0; std::size_t start = stats.targets.selection; stats.skill.invalids.clear(); stats.actions.invalids.clear(); std::string targetDescription = ""; for ( int i = start; i < actions.size(); ++i ) { uf::Serializer cardData = masterDataGet("Card", actions[i]["id"].asString()); uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); std::string text = charaData["name"].asString(); if ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), text ) != stats.targets.invalids.end() ) continue; if ( ++counter > stats.targets.selectionsMax ) break; if ( i != stats.targets.selection ) text = "" + colorString("FFFFFF") + "" + text; else text = "" + colorString("FF0000") + "" + text; string += "\n" + text; } if ( actions.size() > stats.targets.selectionsMax ) { for ( int i = 0; i < actions.size(); ++i ) { uf::Serializer cardData = masterDataGet("Card", actions[i]["id"].asString()); uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); std::string text = charaData["name"].asString(); if ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), text ) != stats.targets.invalids.end() ) continue; if ( ++counter > stats.targets.selectionsMax ) break; if ( i != stats.targets.selection ) text = "" + colorString("FFFFFF") + "" + text; else text = "" + colorString("FF0000") + "" + text; string += "\n" + text; } } if ( string != "" ) { string = string.substr(1); targetOptions = new ext::Gui; this->addChild(*targetOptions); uf::Serializer& pMetadata = targetOptions->getComponent(); targetOptions->load("./battle-option.json", true); pMetadata["text settings"]["string"] = string; pod::Transform<>& pTransform = targetOptions->getComponent>(); targetOptions->initialize(); } if ( queuedAction == "analyze" ) { uf::Serializer payload; payload["uid"] = stats.targets.current[stats.targets.selection]["uid"].asString(); // if ( payload["uid"].asString() == "") payload["action"] = "analyze"; uf::Serializer result = battleManager->callHook("world:Battle.Action.%UID%", payload)[0]; targetDescription = result["message"].asString(); } if ( targetDescription != "" ) { uf::Serializer payload; payload["message"] = targetDescription; this->callHook("world:Battle.Message.%UID%", payload); } }; if ( !stats.initialized ) { stats.initialized = true; uf::Serializer& metadata = this->getComponent(); this->addHook("world:Battle.Turn.%UID%", [&](const std::string& event) -> std::string { uf::Serializer json = event; uf::Serializer payload; payload["action"] = "turn-start"; if ( !stats.previousMember["uid"].isNull() ) payload["uid"] = stats.previousMember["uid"].asUInt64() + 1; auto hookCall = battleManager->callHook("world:Battle.Action.%UID%", payload); if ( hookCall.empty() ) { metadata["system"]["closing"] = true; return "false"; } uf::Serializer result = hookCall[0]; if ( result["end"].asBool() ) { if ( metadata.isObject() ) metadata["system"]["closing"] = true; return "false"; } postParseResult(result); if ( result["uid"].isNull() ) return "false"; uint64_t uid = result["uid"].asUInt64(); renderCommandOptions(std::string("")); renderSkillOptions(std::string("")); renderTargetOptions(std::string("")); payload = uf::Serializer{}; payload["uid"] = uid; if ( result[""]["type"] == "enemy" ) { payload["action"] = "enemy-attack"; } else if ( result["skipped"].asBool() ) { payload["action"] = "forced-pass"; } else { stats.currentMember = result[""]; renderCommandOptions(result["actions"]); return "true"; } result = battleManager->callHook("world:Battle.Action.%UID%", payload)[0]; postParseResult(result); stats.previousMember = uf::Serializer{}; timer.reset(); stats.state = "waiting"; this->queueHook("world:Battle.Turn.%UID%", "", timeout); return "true"; }); this->queueHook("world:Battle.Turn.%UID%"); } { uf::Serializer& metadata = this->getComponent(); if ( metadata["system"]["closing"].asBool() ) { if ( alpha >= 1.0f ) { uf::Asset assetLoader; std::string canonical = assetLoader.load("./data/audio/ui/menu close.ogg"); uf::Audio& sfx = assetLoader.get(canonical); sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); sfx.play(); } if ( alpha <= 0.0f ) { alpha = 0.0f; metadata["system"]["closing"] = false; metadata["system"]["closed"] = true; } else alpha -= uf::physics::time::delta; metadata["color"][3] = alpha; } else if ( metadata["system"]["closed"].asBool() ) { uf::Object& parent = this->getParent(); parent.getComponent()["system"]["closed"] = true; this->destroy(); parent.removeChild(*this); } else { if ( !metadata["initialized"].asBool() ) alpha = 0.0f; metadata["initialized"] = true; if ( alpha >= 1.0f ) alpha = 1.0f; else alpha += uf::physics::time::delta * 1.5f; metadata["color"][3] = alpha; } } if ( circleIn ) { pod::Transform<>& transform = circleIn->getComponent>(); static float time = 0.0f; float speed = 0.0125f; uf::Serializer& metadata = circleIn->getComponent(); if ( metadata["hovered"].asBool() ) speed = -0.25f; time += uf::physics::time::delta * speed; transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); static pod::Vector3f start = { transform.position.x, -2.0f, 0.0f }; static pod::Vector3f end = transform.position; static float delta = 0.0f; if ( !metadata["initialized"].asBool() ) delta = 0.0f; metadata["initialized"] = true; if ( delta >= 1 ) delta = 1; else { delta += uf::physics::time::delta * 1.5f; transform.position = uf::vector::lerp( start, end, delta ); } metadata["color"][3] = alpha * 0.1f; } if ( circleOut ) { pod::Transform<>& transform = circleOut->getComponent>(); uf::Serializer& metadata = circleOut->getComponent(); static float time = 0.0f; float speed = 0.0125f; if ( metadata["hovered"].asBool() ) speed = 0.25f; time += uf::physics::time::delta * speed; transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); static pod::Vector3f start = { transform.position.x, 2.0f, 0.0f }; static pod::Vector3f end = transform.position; static float delta = 0.0f; if ( !metadata["initialized"].asBool() ) delta = 0.0f; metadata["initialized"] = true; if ( delta >= 1 ) delta = 1; else { delta += uf::physics::time::delta * 1.5f; transform.position = uf::vector::lerp( start, end, delta ); } metadata["color"][3] = alpha * 0.1f; } if ( turnCounters ) { static float time = 0.0f; time += uf::physics::time::delta; for ( uf::Entity* pointer : turnCounters->getChildren() ) { uf::Serializer& pMetadata = pointer->getComponent(); float coeff = 2.0f; // if ( pMetadata["half counter"].asBool() ) coeff = 4.0f; // pMetadata["color"][3] = sin(time * coeff) * 0.25f + 0.75f; pMetadata["color"][3] = std::min( 1.0f, (float) sin(time * coeff) * 0.5f + 1.0f ); } } if ( optionsBackground ) { pod::Transform<>& transform = optionsBackground->getComponent>(); uf::Serializer& metadata = optionsBackground->getComponent(); static pod::Vector3f start = { transform.position.x, 2.0f, 0.0f }; static pod::Vector3f end = transform.position; static float delta = 0.0f; if ( !metadata["initialized"].asBool() ) delta = 0.0f; metadata["initialized"] = true; if ( delta >= 1 ) delta = 1; else { delta += uf::physics::time::delta * 1.5f; transform.position = uf::vector::lerp( start, end, delta ); } metadata["color"][3] = alpha; if ( !commandOptions && !battleOptions && !targetOptions ) { metadata["color"][3] = 0.1f; } } for ( auto* pointerButton : partyMemberButtons ) { if ( !pointerButton ) continue; if ( pointerButton->getUid() == 0 ) continue; for ( auto* pointer : pointerButton->getChildren() ) { if ( !pointer ) continue; if ( pointer->getUid() == 0 ) continue; if ( pointer->getName() == "Menu: Party Member Icon" ) { pod::Transform<>& transform = pointer->getComponent>(); uf::Serializer& metadata = pointer->getComponent(); metadata["color"][3] = alpha; if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= timeout ) { } static float color = 0.0f; // std::cout << pointer << ": " << metadata << ": " << stats.currentMember << std::endl; if ( metadata[""]["uid"] == stats.currentMember["uid"] ) { color += uf::physics::time::delta * 4.0f; float factor = (1 - (1.0f + cos(color)) / 8.0f); metadata["color"][0] = 1.0f * factor; metadata["color"][1] = 1.0f * factor; metadata["color"][2] = 0.6f * factor; if ( partyMemberCommandCircle && partyMemberCommandCircle->getUid() != 0 ) { uf::Serializer& metadata = partyMemberCommandCircle->getComponent(); pod::Transform<>& pTransform = partyMemberCommandCircle->getComponent>(); if ( pTransform.position.x == 0 && pTransform.position.y == 0 ) { pTransform.position.x = transform.position.x; pTransform.position.y = transform.position.y; } metadata["system"]["lerp"]["delta"] = 0; metadata["system"]["lerp"]["start"][0] = pTransform.position.x; metadata["system"]["lerp"]["start"][1] = pTransform.position.y; metadata["system"]["lerp"]["start"][2] = pTransform.position.z; metadata["system"]["lerp"]["end"][0] = transform.position.x; metadata["system"]["lerp"]["end"][1] = transform.position.y; metadata["system"]["lerp"]["end"][2] = transform.position.z; } } else { metadata["color"][0] = 1.0f; metadata["color"][2] = 1.0f; metadata["color"][2] = 1.0f; } } else if ( pointer->getName() == "Menu: Party Member Text" ) { pod::Transform<>& transform = pointer->getComponent>(); uf::Serializer& metadata = pointer->getComponent(); metadata["color"][3] = alpha; if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= timeout ) { } static float color = 0.0f; // std::cout << pointer << ": " << metadata << ": " << stats.currentMember << std::endl; if ( metadata[""]["uid"] == stats.currentMember["uid"] ) { color += uf::physics::time::delta * 4.0f; float factor = (1 - (1.0f + cos(color)) / 8.0f); metadata["color"][0] = 1.0f * factor; metadata["color"][1] = 1.0f * factor; metadata["color"][2] = 0.6f * factor; } else { metadata["color"][0] = 1.0f; metadata["color"][2] = 1.0f; metadata["color"][2] = 1.0f; } } } } /* particles */ for ( auto it = particles.begin(); it != particles.end(); ++it ) { ext::Gui* particle = *it; if ( !particle ) { particles.erase( it ); return; } if ( particle->getUid() == 0 ) { particles.erase( it ); return; } uf::Serializer& metadata = particle->getComponent(); pod::Transform<>& transform = particle->getComponent>(); // state 1 // std::cout << particle << ": " << metadata["system"]["percent"] << ": " << metadata["text settings"]["string"] << std::endl; // std::cout << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; try { if ( !metadata["system"].isObject() ) { this->removeChild(*particle); particle->destroy(); delete particle; *it = NULL; continue; } if ( metadata["system"]["percent"] < 0.25f ) { transform.position.y -= uf::physics::time::delta / 2.0f; } else if ( metadata["system"]["percent"] < 0.5f ) { transform.position.y += uf::physics::time::delta / 2.0f; } else if ( metadata["system"]["percent"] < 1.0f ) { } else { this->removeChild(*particle); particle->destroy(); delete particle; *it = NULL; continue; } metadata["system"]["percent"] = metadata["system"]["percent"].asFloat() + uf::physics::time::delta; } catch ( ... ) { if ( particle ) { this->removeChild(*particle); particle->destroy(); delete particle; *it = NULL; } } } for ( auto* pointer : partyMemberButtons ) { if ( !pointer ) continue; if ( pointer->getUid() == 0 ) continue; pod::Transform<>& transform = pointer->getComponent>(); uf::Serializer& metadata = pointer->getComponent(); metadata["color"][3] = alpha; } if ( partyMemberCommandCircle && partyMemberCommandCircle->getUid() != 0 ) { pod::Transform<>& transform = partyMemberCommandCircle->getComponent>(); uf::Serializer& metadata = partyMemberCommandCircle->getComponent(); static float time = 0.0f; float speed = 0.5f; if ( metadata["hovered"].asBool() ) speed = 0.75f; time += uf::physics::time::delta * speed; transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); metadata["color"][3] = alpha; { pod::Vector3f start = { metadata["system"]["lerp"]["start"][0].asFloat(), metadata["system"]["lerp"]["start"][1].asFloat(), metadata["system"]["lerp"]["start"][2].asFloat(), }; pod::Vector3f end = { metadata["system"]["lerp"]["end"][0].asFloat(), metadata["system"]["lerp"]["end"][1].asFloat(), metadata["system"]["lerp"]["end"][2].asFloat(), }; float delta = metadata["system"]["lerp"]["delta"].asFloat(); if ( delta >= 1 ) delta = 1; else { delta += uf::physics::time::delta * 8.0f; transform.position = uf::vector::lerp( start, end, delta ); } metadata["system"]["lerp"]["delta"] = delta; } } ext::Gui::tick(); if ( stats.state != "open" ) { if ( timer.elapsed().asDouble() >= timeout ) stats.state = "open"; return; } struct { bool up = uf::Window::isKeyPressed("W"); bool down = uf::Window::isKeyPressed("S"); bool back = uf::Window::isKeyPressed("Escape"); bool select = uf::Window::isKeyPressed("Enter"); } keys; if ( targetOptions ) { bool delta = false; bool invalid = false; pod::Transform<>& transform = targetOptions->getComponent>(); uf::Serializer& metadata = targetOptions->getComponent(); metadata["color"][3] = alpha; for ( uf::Entity* pointer : targetOptions->getChildren() ) { uf::Serializer& cMetadata = pointer->getComponent(); cMetadata["text settings"]["color"][3] = alpha; } static bool released = true; if ( keys.up ) { if ( released ) { delta = true; released = false; do { --stats.targets.selection; if ( stats.targets.selection < 0 ) { stats.targets.selection = stats.targets.current.size() - 1; } } while ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), stats.targets.current[stats.targets.selection]["id"].asString() ) != stats.targets.invalids.end() ); } } else if ( keys.down ) { if ( released ) { delta = true; released = false; do { ++stats.targets.selection; if ( stats.targets.selection >= stats.targets.current.size() ) { stats.targets.selection = 0; } } while ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), stats.targets.current[stats.targets.selection]["id"].asString() ) != stats.targets.invalids.end() ); } } else released = true; if ( stats.targets.selection < 0 ) { stats.targets.selection = stats.targets.current.size() - 1; } else if ( stats.targets.selection >= stats.targets.current.size() ) { stats.targets.selection = 0; } if ( queuedAction == "analyze" ) keys.select = false; if ( !released ) { if ( invalid ) { playSound(*this, "invalid select"); } else if ( delta ) { playSound(*this, "menu flip"); renderTargetOptions(stats.targets.current); } } else if ( keys.back && timer.elapsed().asDouble() >= timeout ) { playSound(*this, "menu close"); renderTargetOptions(std::string("")); if ( queuedAction == "analyze" ) { renderSkillOptions(std::string("")); renderCommandOptions(stats.actions.current); } else renderSkillOptions(stats.currentMember); timer.reset(); } else if ( keys.select && timer.elapsed().asDouble() >= timeout ) { playSound(*this, "menu close"); uf::Serializer payload; payload["action"] = "member-attack"; payload["uid"] = stats.currentMember["uid"]; payload["target"] = Json::arrayValue; payload["target"].append(stats.targets.current[stats.targets.selection]["uid"]); payload["skill"] = stats.currentMember["skills"][stats.skill.selection]; uf::Serializer result = battleManager->callHook("world:Battle.Action.%UID%", payload)[0]; postParseResult(result); renderTargetOptions(std::string("")); renderCommandOptions(std::string("")); renderSkillOptions(std::string("")); timer.reset(); stats.state = "waiting"; if ( result["invalid"].asBool() ) { // stats.actions.invalids.push_back(action); renderCommandOptions(stats.actions.current); // this->queueHook("world:Battle.Turn.%UID%", "", timeout); } else { this->queueHook("world:Battle.Turn.%UID%", "", timeout); } } } else if ( battleOptions ) { bool delta = false; bool invalid = false; pod::Transform<>& transform = battleOptions->getComponent>(); uf::Serializer& metadata = battleOptions->getComponent(); metadata["color"][3] = alpha; for ( uf::Entity* pointer : battleOptions->getChildren() ) { uf::Serializer& cMetadata = pointer->getComponent(); cMetadata["text settings"]["color"][3] = alpha; } static bool released = true; if ( keys.up ) { if ( released ) { delta = true; released = false; do { --stats.skill.selection; if ( stats.skill.selection < 0 ) { stats.skill.selection = stats.currentMember["skills"].size()- 1; } } while ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), stats.currentMember["skills"][stats.skill.selection].asString() ) != stats.skill.invalids.end() ); } } else if ( keys.down ) { if ( released ) { delta = true; released = false; do { ++stats.skill.selection; if ( stats.skill.selection >= stats.currentMember["skills"].size()) { stats.skill.selection = 0; } } while ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), stats.currentMember["skills"][stats.skill.selection].asString() ) != stats.skill.invalids.end() ); } } else released = true; if ( !released ) { if ( invalid ) { playSound(*this, "menu close"); } else if ( delta ) { playSound(*this, "menu flip"); renderSkillOptions(stats.currentMember); } } else if ( keys.back && timer.elapsed().asDouble() >= timeout ) { playSound(*this, "menu close"); renderSkillOptions(std::string("")); renderCommandOptions(stats.actions.current); timer.reset(); } else if ( keys.select && timer.elapsed().asDouble() >= timeout ) { playSound(*this, "menu close"); bool allRanged = false; renderSkillOptions(std::string("")); renderCommandOptions(std::string("")); uf::Serializer payload; payload["action"] = "member-targets"; payload["uid"] = stats.currentMember["uid"]; payload["skill"] = stats.currentMember["skills"][stats.skill.selection]; uf::Serializer result = battleManager->callHook("world:Battle.Action.%UID%", payload)[0]; std::string skillId = stats.currentMember["skills"][stats.skill.selection].asString(); uf::Serializer skillData = masterDataGet("Skill", skillId); if ( result["range"].isNumeric() ) skillData["range"] = result["range"]; if ( skillData["range"].asInt64() > 1 ) { uf::Serializer payload; payload["action"] = "member-attack"; payload["uid"] = stats.currentMember["uid"]; payload["skill"] = stats.currentMember["skills"][stats.skill.selection]; uf::Serializer result = battleManager->callHook("world:Battle.Action.%UID%", payload)[0]; postParseResult(result); timer.reset(); stats.state = "waiting"; if ( result["invalid"].asBool() ) { // stats.actions.invalids.push_back(action); renderCommandOptions(stats.actions.current); // this->queueHook("world:Battle.Turn.%UID%", "", timeout); } else { this->queueHook("world:Battle.Turn.%UID%", "", timeout); } } else { postParseResult(result); renderTargetOptions(result["targets"]); } } } else if ( commandOptions ) { /* bool delta = false; bool invalid = false; pod::Transform<>& transform = commandOptions->getComponent>(); uf::Serializer& metadata = commandOptions->getComponent(); metadata["color"][3] = alpha; for ( uf::Entity* pointer : commandOptions->getChildren() ) { uf::Serializer& cMetadata = pointer->getComponent(); cMetadata["text settings"]["color"][3] = alpha; } static bool released = true; if ( keys.up ) { if ( released ) { delta = true; released = false; do { --stats.actions.selection; if ( stats.actions.selection < 0 ) { stats.actions.selection = stats.actions.current.size() - 1; } } while ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), stats.actions.current[stats.actions.selection].asString() ) != stats.actions.invalids.end() ); } } else if ( keys.down ) { if ( released ) { delta = true; released = false; do { ++stats.actions.selection; if ( stats.actions.selection >= stats.actions.current.size() ) { stats.actions.selection = 0; } } while ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), stats.actions.current[stats.actions.selection].asString() ) != stats.actions.invalids.end() ); } } else released = true; if ( stats.actions.selection < 0 ) { stats.actions.selection = stats.actions.current.size() - 1; } else if ( stats.actions.selection >= stats.actions.current.size() ) { stats.actions.selection = 0; } if ( !released ) { if ( invalid ) { playSound(*this, "invalid select"); } else if ( delta ) { playSound(*this, "menu flip"); renderCommandOptions(stats.actions.current); } } else if ( keys.back && timer.elapsed().asDouble() >= timeout ) { playSound(*this, "invalid select"); timer.reset(); } else if ( keys.select && timer.elapsed().asDouble() >= timeout ) { playSound(*this, "menu close"); uf::Serializer payload; std::string action = stats.actions.current[stats.actions.selection].asString(); payload["action"] = action; if ( payload["action"] == "member-attack" ) { payload["uid"] = stats.currentMember["uid"]; payload["skill"] = stats.currentMember["skills"][stats.skill.selection]; } uf::Serializer result = battleManager->callHook("world:Battle.Action.%UID%", payload)[0]; postParseResult(result); timer.reset(); renderCommandOptions(std::string("")); stats.state = "waiting"; if ( result["invalid"].asBool() ) { stats.actions.invalids.push_back(action); renderCommandOptions(stats.actions.current); // this->queueHook("world:Battle.Turn.%UID%", "", timeout); } else if ( payload["action"] == "member-attack" ) { renderSkillOptions(std::string("")); stats.state = "waiting"; this->queueHook("world:Battle.Turn.%UID%", "", timeout); } else if ( payload["action"] == "member-skill" ) { renderSkillOptions(stats.currentMember); } else if ( payload["action"] == "pass" ) { stats.previousMember = stats.currentMember; this->queueHook("world:Battle.Turn.%UID%", "", timeout); } } } */ bool delta = false; bool invalid = false; pod::Transform<>& transform = commandOptions->getComponent>(); uf::Serializer& metadata = commandOptions->getComponent(); metadata["color"][3] = alpha; for ( uf::Entity* pointer : commandOptions->getChildren() ) { uf::Serializer& cMetadata = pointer->getComponent(); cMetadata["text settings"]["color"][3] = alpha; } static bool released = true; if ( keys.up ) { if ( released ) { delta = true; released = false; do { --stats.actions.selection; if ( stats.actions.selection < 0 ) { stats.actions.selection = stats.actions.current.size() - 1; } } while ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), getKeyFromIndex(stats.actions.current, stats.actions.selection) ) != stats.actions.invalids.end() ); } } else if ( keys.down ) { if ( released ) { delta = true; released = false; do { ++stats.actions.selection; if ( stats.actions.selection >= stats.actions.current.size() ) { stats.actions.selection = 0; } } while ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), getKeyFromIndex(stats.actions.current, stats.actions.selection) ) != stats.actions.invalids.end() ); } } else released = true; if ( stats.actions.selection < 0 ) { stats.actions.selection = stats.actions.current.size() - 1; } else if ( stats.actions.selection >= stats.actions.current.size() ) { stats.actions.selection = 0; } if ( stats.actions.current.size() == 0 ) released = true; if ( !released ) { if ( invalid ) { playSound(*this, "invalid select"); } else if ( delta ) { playSound(*this, "menu flip"); renderCommandOptions(stats.actions.current); } } else if ( keys.back && timer.elapsed().asDouble() >= timeout ) { playSound(*this, "invalid select"); timer.reset(); } else if ( keys.select && timer.elapsed().asDouble() >= timeout ) { playSound(*this, "menu close"); uf::Serializer payload; std::string action = getKeyFromIndex(stats.actions.current, stats.actions.selection); action = uf::string::extension(action); payload["action"] = action; payload["uid"] = stats.currentMember["uid"]; if ( payload["action"] == "member-attack" ) { // payload["skill"] = stats.currentMember["skills"][0]; payload["skill"] = 0; } if ( payload["action"] == "analyze" ) { payload["action"] = "member-targets"; } uf::Serializer result = battleManager->callHook("world:Battle.Action.%UID%", payload)[0]; // std::cout << payload << ": " << result << std::endl; postParseResult(result); timer.reset(); renderCommandOptions(std::string("")); queuedAction = action; stats.state = "waiting"; if ( result["invalid"].asBool() ) { stats.actions.invalids.push_back(action); renderCommandOptions(stats.actions.current); } else if ( payload["action"] == "member-attack" ) { renderSkillOptions(std::string("")); stats.state = "waiting"; this->queueHook("world:Battle.Turn.%UID%", "", timeout); } else if ( payload["action"] == "member-skill" ) { renderSkillOptions(stats.currentMember); } else if ( payload["action"] == "member-targets" ) { renderTargetOptions(result["targets"]); } else if ( payload["action"] == "pass" ) { stats.previousMember = stats.currentMember; this->queueHook("world:Battle.Turn.%UID%", "", timeout); } else { renderCommandOptions(stats.actions.current); } } } } void ext::GuiBattle::render() { ext::Gui::render(); } void ext::GuiBattle::destroy() { ext::Gui::destroy(); }