#include "boss/fight.hpp" #include "boss/system.hpp" #include "animation.hpp" #include "game_level.hpp" #include #include "rand.hpp" #include "events.hpp" namespace boss { using namespace DinkyECS; 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(); } void Fight::event(game::Event ev, std::any data) { // if the mouse event is handled the done, this may be wrong later if(handle_mouse(ev)) return; switch($state) { FSM_STATE(State, START, ev, data); FSM_STATE(State, PLAYER_REQUESTS, ev, data); FSM_STATE(State, EXEC_PLAN, ev, data); FSM_STATE(State, END, ev, data); } } void Fight::START(game::Event ev, std::any) { using enum game::Event; switch(ev) { // this is only if using the debug X key to skip it case TICK: case BOSS_START: $ui.status(L"PLAYER REQUESTS", L"COMMIT"); $battle.ap_refresh(); state(State::PLAYER_REQUESTS); break; default: break; } } void Fight::PLAYER_REQUESTS(game::Event ev, std::any data) { using enum game::Event; switch(ev) { // this is only if using the debug X key to skip it case BOSS_START: state(State::END); break; case COMBAT_START: System::plan_battle($battle, $world, $boss_id); $ui.status(L"EXEC PLAN", L"START"); state(State::EXEC_PLAN); 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::EXEC_PLAN(game::Event ev, std::any data) { using enum game::Event; switch(ev) { // this is only if using the debug X key to skip it case BOSS_START: state(State::END); break; case COMBAT_START: $ui.status(L"X TURN", L"STEP"); next_combat_dumb_name(); break; case COMBAT: do_combat(data); break; default: break; } } void Fight::next_combat_dumb_name() { if(auto action = $battle.next()) { System::combat(*action, $world, $boss_id, 0); } else if(player_dead()) { $ui.status(L"YOU DIED", L"DEAD"); state(State::END); } else { $ui.status(L"PLAYER REQUESTS", L"COMMIT"); $ui.reset_camera(); $battle.ap_refresh(); $battle.clear_requests(); state(State::PLAYER_REQUESTS); } } void Fight::do_combat(std::any data) { using combat::BattleHostState; dbc::check(data.type() == typeid(components::CombatResult), fmt::format("Boss Fight wrong any data={}", data.type().name())); auto result = std::any_cast(data); switch(result.host_state) { case BattleHostState::agree: case BattleHostState::disagree: { std::string player_move = Random::uniform(0, 1) == 0 ? "player1" : "player3"; $ui.move_actor("player", player_move); if(result.player_did > 0) $ui.animate_actor("player"); $ui.damage("player", "boss", result.player_did); } break; case BattleHostState::not_host: { std::string boss_move = Random::uniform(0, 1) == 0 ? "boss5" : "boss6"; $ui.move_actor("boss", boss_move); if(result.enemy_did > 0) $ui.animate_actor("boss"); $ui.damage("boss", "player", result.enemy_did); } break; case BattleHostState::out_of_ap: break; } } void Fight::END(game::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) { $ui.play_animations(); $ui.render(); } bool Fight::handle_mouse(game::Event ev) { using enum game::Event; $mouse_pos = $window->mapPixelToCoords($router.position); 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::set_window(sf::RenderWindow* window) { $window = window; $ui.set_window(window); } bool Fight::handle_keyboard_mouse() { dbc::check($window != nullptr, "you didn't set_window"); while(const auto ev = $window->pollEvent()) { auto gui_ev = $router.process_event(ev); if(gui_ev == game::Event::KEY_PRESS) { using KEY = sf::Keyboard::Scan; switch($router.scancode) { // REALLY? just go to state end or use another event case KEY::X: event(game::Event::BOSS_START, {}); break; default: fmt::println("key press!"); } } else if(gui_ev == game::Event::QUIT) { return true; } else { event(gui_ev, {}); } } return in_state(State::END); } bool Fight::handle_world_events() { if($world->has_event()) { while($world->has_event()) { auto [evt, entity, data] = $world->recv(); event(game::Event(evt), data); run_systems(); } } return in_state(State::END); } }