diff --git a/assets/sounds/test_story.ogg b/assets/sounds/test_story.ogg index 688b5af..f9fb660 100644 Binary files a/assets/sounds/test_story.ogg and b/assets/sounds/test_story.ogg differ diff --git a/assets/stories.json b/assets/stories.json index 8d14de0..c058343 100644 --- a/assets/stories.json +++ b/assets/stories.json @@ -10,18 +10,18 @@ ], "beats": [ ["00:00", "a","pan"], - ["00:06", "a","pan"], - ["00:13", "b","pan"], - ["00:19", "g","pan"], - ["00:25", "h","pan"], - ["00:29", "h","bounce"], - ["00:31", "c1","pan"], - ["00:34", "c2","pan"], - ["00:39", "d","bounce"], - ["00:44", "e","shake"], - ["00:48", "i","pan"], - ["00:53", "i","shake"], - ["00:55", "i","bounce"] + ["00:01", "a","pan"], + ["00:02", "b","pan"], + ["00:03", "g","pan"], + ["00:04", "h","pan"], + ["00:05", "h","bounce"], + ["00:06", "c1","pan"], + ["00:07", "c2","pan"], + ["00:08", "d","bounce"], + ["00:09", "e","shake"], + ["00:10", "i","pan"], + ["00:11", "i","shake"], + ["00:12", "i","bounce"] ] } } diff --git a/boss/fight.cpp b/boss/fight.cpp index 2840ed6..9dd67e8 100644 --- a/boss/fight.cpp +++ b/boss/fight.cpp @@ -4,8 +4,11 @@ #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), @@ -19,9 +22,10 @@ namespace boss { $ui.init(); } - bool Fight::event(game::Event ev, std::any data) { + 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 in_state(State::END); + if(handle_mouse(ev)) return; switch($state) { FSM_STATE(State, START, ev, data); @@ -30,10 +34,6 @@ namespace boss { FSM_STATE(State, EXEC_PLAN, ev, data); FSM_STATE(State, END, ev, data); } - - run_systems(); - - return in_state(State::END); } void Fight::START(game::Event ev, std::any) { @@ -41,10 +41,8 @@ namespace boss { switch(ev) { // this is only if using the debug X key to skip it - case BOSS_START: - state(State::END); - break; case TICK: + case BOSS_START: $ui.status(L"PLAYER REQUESTS"); $battle.ap_refresh(); state(State::PLAYER_REQUESTS); @@ -169,7 +167,6 @@ namespace boss { } void Fight::render(sf::RenderWindow& window) { - window.clear(); $ui.play_animations(); $ui.render(window); } @@ -179,10 +176,10 @@ namespace boss { switch(ev) { case MOUSE_CLICK: { - $ui.mouse(mouse_pos.x, mouse_pos.y, guecs::NO_MODS); + $ui.mouse($router.position.x, $router.position.y, guecs::NO_MODS); } break; case MOUSE_MOVE: { - $ui.mouse(mouse_pos.x, mouse_pos.y, {1 << guecs::ModBit::hover}); + $ui.mouse($router.position.x, $router.position.y, {1 << guecs::ModBit::hover}); } break; case MOUSE_DRAG: dbc::log("mouse drag"); @@ -210,33 +207,47 @@ namespace boss { run_systems(); } - void Fight::handle_world_events() { - fmt::println(">>>>>>>>>>>>>>>>> BOSS FIGHT EVENTS"); - dbc::check($world->has_event(), "World doesn't have GUI events."); + void Fight::set_window(sf::RenderWindow* window) { + $window = window; + } - while($world->has_event()) { - auto [evt, entity, data] = $world->recv(); - fmt::println("boss fight received event", int(evt)); + bool Fight::handle_keyboard_mouse() { + dbc::check($window != nullptr, "you didn't set_window"); - switch(evt) { - case game::Event::ATTACK: - fmt::println("sending attack"); - event(game::Event::ATTACK, data); - break; - case game::Event::COMBAT_START: - fmt::println("sending combat start {}", data.type().name()); - event(game::Event::COMBAT_START, data); - break; - case game::Event::COMBAT: - fmt::println("sending combat {}", data.type().name()); - event(game::Event::COMBAT, data); - break; - default: - fmt::println("GUI EVENT: {} entity={}", int(evt), entity); + 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, {}); } } - dbc::check(!$world->has_event(), "World still has events!"); - fmt::println("<<<<<<<<<<<<<<<< BOSS FIGHT EVENTS"); + 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); } } diff --git a/boss/fight.hpp b/boss/fight.hpp index decc67e..b291c5e 100644 --- a/boss/fight.hpp +++ b/boss/fight.hpp @@ -5,35 +5,39 @@ #include "boss/ui.hpp" #include "events.hpp" #include "battle.hpp" +#include "gui/event_router.hpp" #include #include namespace boss { - using namespace DinkyECS; using std::shared_ptr; enum class State { - START=0, - PLAYER_REQUESTS=1, - PLAN_BATTLE=2, - EXEC_PLAN=3, - END=4 + START=__LINE__, + PLAYER_REQUESTS=__LINE__, + PLAN_BATTLE=__LINE__, + EXEC_PLAN=__LINE__, + END=__LINE__ }; class Fight : public DeadSimpleFSM { public: - shared_ptr $world = nullptr; - DinkyECS::Entity $boss_id = NONE; + sf::RenderWindow* $window = nullptr; + shared_ptr $world = nullptr; + DinkyECS::Entity $boss_id = DinkyECS::NONE; combat::BattleEngine $battle; boss::UI $ui; - sf::Vector2f mouse_pos{0,0}; - Entity $host = NONE; + DinkyECS::Entity $host = DinkyECS::NONE; components::Combat* $host_combat = nullptr; + gui::routing::Router $router; - Fight(shared_ptr world, Entity boss_id, Entity player_id); + Fight(shared_ptr world, + DinkyECS::Entity boss_id, + DinkyECS::Entity player_id); + void set_window(sf::RenderWindow* window); bool handle_mouse(game::Event ev); - bool event(game::Event ev, std::any data); + void event(game::Event ev, std::any data); void START(game::Event ev, std::any data); void PLAYER_REQUESTS(game::Event ev, std::any data); @@ -42,12 +46,14 @@ namespace boss { void END(game::Event ev, std::any data); void render(sf::RenderWindow& window); - void handle_world_events(); + bool handle_world_events(); void run_systems(); bool player_dead(); void init_fight(); void do_combat(std::any data); void next_combat_dumb_name(); + sf::Vector2f mouse_position(); + bool handle_keyboard_mouse(); }; } diff --git a/gui/fsm.cpp b/gui/fsm.cpp index d7271dd..48d755e 100644 --- a/gui/fsm.cpp +++ b/gui/fsm.cpp @@ -39,6 +39,7 @@ namespace gui { FSM_STATE(State, IDLE, ev, data); FSM_STATE(State, IN_COMBAT, ev); FSM_STATE(State, COMBAT_ROTATE, ev); + FSM_STATE(State, CUT_SCENE_PLAYING, ev, data); FSM_STATE(State, BOSS_FIGHT, ev, data); FSM_STATE(State, LOOTING, ev, data); FSM_STATE(State, END, ev); @@ -175,7 +176,7 @@ namespace gui { case BOSS_START: sound::stop("ambient"); next_level(true); - state(State::BOSS_FIGHT); + state(State::CUT_SCENE_PLAYING); break; case LOOT_ITEM: $dnd_loot.event(Event::LOOT_ITEM); @@ -211,26 +212,20 @@ namespace gui { } } - void FSM::BOSS_FIGHT(Event ev, std::any data) { - dbc::check($boss_fight != nullptr, "$boss_fight not initialized"); - + void FSM::CUT_SCENE_PLAYING(Event ev, std::any data) { if($boss_scene->playing()) { if(ev == game::Event::MOUSE_CLICK) { + dbc::log("exiting cut scene"); $boss_scene->mouse(0,0, 0); + state(State::BOSS_FIGHT); } - return; + } else { + state(State::BOSS_FIGHT); } + } - $boss_fight->mouse_pos = mouse_position(); - - if(ev == game::Event::QUIT) { - // just epsilon straight to the exit - IDLE(ev, data); - } if($boss_fight->event(ev, data)) { - sound::play("ambient"); - next_level(false); - state(State::IDLE); - } + void FSM::BOSS_FIGHT(Event ev, std::any data) { + dbc::log("this should not run, it's handled in handle_boss_fight_events"); } void FSM::IN_COMBAT(Event ev) { @@ -406,18 +401,20 @@ namespace gui { } void FSM::render() { + $window.clear(); + if(in_state(State::BOSS_FIGHT)) { - $window.clear(); - if($boss_scene->playing()) { - $boss_scene->render($window); - } else { - $boss_fight->render($window); - } + $boss_fight->render($window); + // this clears any attack animations, like fire + System::clear_attack(); + } else if(in_state(State::CUT_SCENE_PLAYING)) { + $boss_scene->render($window); } else { + // this clears any attack animations, like fire + System::clear_attack(); draw_gui(); } - System::clear_attack(); $window.display(); } @@ -435,7 +432,20 @@ namespace gui { return !in_state(State::END); } - void FSM::handle_world_events() { + void FSM::handle_boss_fight_events() { + dbc::check($boss_fight != nullptr, "$boss_fight not initialized"); + + // true means State::END in $boss_fight + if($boss_fight->handle_world_events() || $boss_fight->handle_keyboard_mouse()) { + dbc::log("boss fight ended, transition to IDLE"); + // fight is over, go back to regular game + sound::play("ambient"); + next_level(false); + state(State::IDLE); + } + } + + void FSM::handle_world_events() { using eGUI = game::Event; auto world = GameDB::current_world(); @@ -529,7 +539,9 @@ namespace gui { } } break; default: - $map_ui.log(fmt::format(L"INVALID EVENT! {},{}", evt, entity)); + dbc::log(fmt::format("Unhandled event: evt={}; enemy={}; data={}", + evt, entity, data.type().name())); + event(game::Event(evt), data); } } } @@ -547,8 +559,11 @@ namespace gui { void FSM::next_level(bool bossfight) { if(bossfight) { $boss_scene = std::make_shared("rat_king"); - $boss_fight = boss::System::create_bossfight(); $boss_scene->init(); + + $boss_fight = boss::System::create_bossfight(); + $boss_fight->set_window(&$window); + dbc::check($boss_scene->playing(), "boss scene doesn't play"); } else { GameDB::create_level(); diff --git a/gui/fsm.hpp b/gui/fsm.hpp index 2e45049..0e6fab7 100644 --- a/gui/fsm.hpp +++ b/gui/fsm.hpp @@ -17,16 +17,17 @@ namespace gui { enum class State { - START=0, - MOVING=1, - IN_COMBAT=2, - COMBAT_ROTATE=3, - ATTACKING=4, - ROTATING=5, - BOSS_FIGHT=6, - LOOTING=7, - IDLE=8, - END=9 + START=__LINE__, + MOVING=__LINE__, + IN_COMBAT=__LINE__, + COMBAT_ROTATE=__LINE__, + ATTACKING=__LINE__, + ROTATING=__LINE__, + BOSS_FIGHT=__LINE__, + LOOTING=__LINE__, + IDLE=__LINE__, + CUT_SCENE_PLAYING=__LINE__, + END=__LINE__, }; class FSM : public DeadSimpleFSM { @@ -63,6 +64,7 @@ namespace gui { void COMBAT_ROTATE(game::Event ev); void BOSS_FIGHT(game::Event ev, std::any data); void LOOTING(game::Event ev, std::any data); + void CUT_SCENE_PLAYING(game::Event ev, std::any data); void END(game::Event ev); void try_move(int dir, bool strafe); @@ -74,6 +76,7 @@ namespace gui { bool active(); void run_systems(); void handle_world_events(); + void handle_boss_fight_events(); void next_level(bool bossfight); void debug_render(); void take_screenshot(); diff --git a/main.cpp b/main.cpp index 9329823..40664ba 100644 --- a/main.cpp +++ b/main.cpp @@ -35,22 +35,26 @@ int main(int argc, char* argv[]) { while(main.active()) { main.render(); - // BUG: need to sort out how to deal with this in the FSM - if(main.in_state(gui::State::IDLE) - || main.in_state(gui::State::BOSS_FIGHT) - || main.in_state(gui::State::LOOTING) - || main.in_state(gui::State::IN_COMBAT)) - { - if(main.autowalking) { - walker.autowalk(); - } else { - main.handle_keyboard_mouse(); + if(main.in_state(gui::State::BOSS_FIGHT)) { + main.handle_boss_fight_events(); + } else { + // BUG: need to sort out how to deal with this in the FSM + if(main.in_state(gui::State::IDLE) + || main.in_state(gui::State::LOOTING) + || main.in_state(gui::State::CUT_SCENE_PLAYING) + || main.in_state(gui::State::IN_COMBAT)) + { + if(main.autowalking) { + walker.autowalk(); + } else { + main.handle_keyboard_mouse(); + } + } else{ + main.event(game::Event::TICK); } - } else{ - main.event(game::Event::TICK); - } - main.handle_world_events(); + main.handle_world_events(); + } } return 0; diff --git a/tools/arena.cpp b/tools/arena.cpp index fc7439f..ae6d0c1 100644 --- a/tools/arena.cpp +++ b/tools/arena.cpp @@ -1,4 +1,3 @@ -#include "gui/fsm.hpp" #include "textures.hpp" #include "sound.hpp" #include "autowalker.hpp" @@ -36,8 +35,6 @@ int main(int, char*[]) { if(FRAME_LIMIT) window.setFramerateLimit(FRAME_LIMIT); window.setPosition({0,0}); - gui::routing::Router router; - sound::mute(true); sound::play("ambient_1", true); @@ -45,25 +42,16 @@ int main(int, char*[]) { craft_weapon(); auto main = boss::System::create_bossfight(); + main->set_window(&window); + auto world = GameDB::current_world(); dbc::check(main->$world == world, "GameDB::current_world doesn't match boss fight world."); while(!main->in_state(boss::State::END)) { - main->mouse_pos = window.mapPixelToCoords(router.position); - - while(const auto ev = window.pollEvent()) { - auto gui_ev = router.process_event(ev); - - if(gui_ev == game::Event::QUIT || main->event(gui_ev, {})) { - return 0; - } else { - main->event(game::Event::TICK, {}); - } - } - - if(main->$world->has_event()) { - main->handle_world_events(); - dbc::check(!main->$world->has_event(), "You didn't eat all the events."); + if(main->handle_keyboard_mouse() || + main->handle_world_events()) + { + return 0; } main->render(window);