#include "boss/fight.hpp" #include "boss/system.hpp" #include "animation.hpp" #include "game_level.hpp" namespace boss { Fight::Fight(shared_ptr world, Entity boss_id, Entity player_id) : $world(world), $boss_id(boss_id), $battle(System::create_battle($world, $boss_id)), $ui(world, boss_id, player_id), $host(player_id) { $host_combat = $world->get_if(player_id); dbc::check($host_combat, fmt::format("No combat for host with player_id={}", player_id)); $ui.init(); } bool Fight::event(gui::Event ev, std::any data) { // if the mouse event is handled the done, this may be wrong later if(handle_mouse(ev)) return in_state(State::END); switch($state) { FSM_STATE(State, START, ev, data); FSM_STATE(State, PLAYER_REQUESTS, ev, data); FSM_STATE(State, PLAN_BATTLE, ev, data); FSM_STATE(State, EXEC_PLAN, ev, data); FSM_STATE(State, END, ev, data); } run_systems(); return in_state(State::END); } void Fight::START(gui::Event ev, std::any) { using enum gui::Event; switch(ev) { // this is only if using the debug X key to skip it case BOSS_START: state(State::END); break; case TICK: $ui.status(L"PLAYER REQUESTS"); $battle.ap_refresh(); state(State::PLAYER_REQUESTS); break; default: break; } } void Fight::PLAYER_REQUESTS(gui::Event ev, std::any data) { using enum gui::Event; switch(ev) { // this is only if using the debug X key to skip it case BOSS_START: state(State::END); break; case START_COMBAT: System::plan_battle($battle, $world, $boss_id); $ui.status(L"PLANNING BATTLE"); state(State::PLAN_BATTLE); break; case ATTACK: if($battle.player_request("kill_enemy")) { fmt::println("player requests kill_enemy {} vs. {}", $host_combat->ap, $battle.player_pending_ap()); } else { fmt::println("NO MORE ACTION!"); } break; case TICK: break; // ignore tick default: break; } } void Fight::PLAN_BATTLE(gui::Event ev, std::any data) { using enum gui::Event; switch(ev) { // this is only if using the debug X key to skip it case BOSS_START: state(State::END); break; case START_COMBAT: $ui.status(L"EXEC PLAN"); state(State::EXEC_PLAN); break; case TICK: break; // ignore tick default: break; } } void Fight::EXEC_PLAN(gui::Event ev, std::any data) { using enum gui::Event; switch(ev) { // this is only if using the debug X key to skip it case BOSS_START: state(State::END); break; case TICK: case COMBAT: if(auto action = $battle.next()) { fmt::println("COMBAT!"); System::combat(*action, $world, $boss_id, 0); run_systems(); } else { fmt::println("NO MORE BATTLE ACTIONS!"); } if(player_dead()) { $ui.status(L"YOU DIED"); state(State::END); } else { $ui.status(L"PLAYER REQUESTS"); $battle.ap_refresh(); $battle.clear_requests(); state(State::PLAYER_REQUESTS); } break; // ignore tick default: break; } } void Fight::END(gui::Event ev, std::any) { fmt::println("BOSS_FIGHT:END event {}", (int)ev); } void Fight::run_systems() { $ui.update_stats(); $battle.set($host, "tough_personality", false); $battle.set($host, "have_healing", false); $battle.set($host, "health_good", $host_combat->hp > 100); } void Fight::render(sf::RenderWindow& window) { window.clear(); $ui.play_animations(); $ui.render(window); } bool Fight::handle_mouse(gui::Event ev) { using enum gui::Event; switch(ev) { case MOUSE_CLICK: { $ui.mouse(mouse_pos.x, mouse_pos.y, guecs::NO_MODS); } break; case MOUSE_MOVE: { $ui.mouse(mouse_pos.x, mouse_pos.y, {1 << guecs::ModBit::hover}); } break; case MOUSE_DRAG: dbc::log("mouse drag"); break; case MOUSE_DRAG_START: dbc::log("mouse START drag"); break; case MOUSE_DROP: dbc::log("mouse DROP"); break; default: return false; } // switch/default didn't happen so handled it. return true; } bool Fight::player_dead() { return $host_combat->hp <= 0; } void Fight::init_fight() { System::initialize_actor_ai(*$world, $boss_id); run_systems(); } void Fight::handle_world_events() { fmt::println(">>>>>>>>>>>>>>>>> BOSS FIGHT EVENTS"); dbc::check($world->has_event(), "World doesn't have GUI events."); while($world->has_event()) { auto [evt, entity, data] = $world->recv(); fmt::println("boss fight received event", int(evt)); switch(evt) { case Events::GUI::ATTACK: fmt::println("sending attack"); event(gui::Event::ATTACK, data); break; case Events::GUI::COMBAT_START: fmt::println("sending combat start"); event(gui::Event::START_COMBAT, data); break; case Events::GUI::COMBAT: fmt::println("sending combat"); event(gui::Event::COMBAT, data); break; default: fmt::println("GUI EVENT: {} entity={}", int(evt), entity); } } dbc::check(!$world->has_event(), "World still has events!"); fmt::println("<<<<<<<<<<<<<<<< BOSS FIGHT EVENTS"); } }