diff --git a/Makefile b/Makefile index e6ad107..6b74d7b 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ tracy_build: meson compile -j 10 -C builddir test: build - ./builddir/runtests "[event_router]" + ./builddir/runtests run: build test ifeq '$(OS)' 'Windows_NT' @@ -49,7 +49,7 @@ clean: meson compile --clean -C builddir debug_test: build - gdb --nx -x .gdbinit --ex run --args builddir/runtests -e "[event_router]" + gdb --nx -x .gdbinit --ex run --args builddir/runtests -e win_installer: powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp' diff --git a/events.hpp b/events.hpp index 4e6b5fe..6eb1484 100644 --- a/events.hpp +++ b/events.hpp @@ -34,6 +34,12 @@ namespace gui { LOOT_OPEN=14, LOOT_SELECT=15, LOOT_PLACE=16, - QUIT = 17 + QUIT = 17, + MOUSE_CLICK=18, + MOUSE_MOVE=19, + MOUSE_DRAG=20, + MOUSE_DRAG_START=21, + MOUSE_DROP=22, + KEY_PRESS=23 }; } diff --git a/gui/event_router.cpp b/gui/event_router.cpp index a7f3782..62e4b99 100644 --- a/gui/event_router.cpp +++ b/gui/event_router.cpp @@ -1,4 +1,3 @@ -#define FSM_DEBUG 1 #include "event_router.hpp" #include "dbc.hpp" #include "events.hpp" @@ -44,6 +43,7 @@ namespace gui { FSM_STATE(State, IDLE, ev); FSM_STATE(State, MOUSE_ACTIVE, ev); FSM_STATE(State, MOUSE_MOVING, ev); + FSM_STATE(State, MOUSE_DRAGGING, ev); } } @@ -54,17 +54,15 @@ namespace gui { void Router::IDLE(Event ev) { switch(ev) { case MOUSE_DOWN: + move_count=0; set_event(gui::Event::TICK); state(State::MOUSE_ACTIVE); break; - case MOUSE_UP: - dbc::log("mouse up in IDLE"); - break; case MOUSE_MOVE: - dbc::log("mouse move, send moved event"); + set_event(gui::Event::MOUSE_MOVE); break; case KEY_PRESS: - dbc::log("key pressed"); + set_event(gui::Event::KEY_PRESS); break; default: dbc::sentinel("invalid event"); @@ -73,18 +71,17 @@ namespace gui { void Router::MOUSE_ACTIVE(Event ev) { switch(ev) { - case MOUSE_DOWN: - dbc::log("mouse down in MOUSE_ACTIVE"); - break; case MOUSE_UP: - dbc::log("mouse up, send click event"); + set_event(gui::Event::MOUSE_CLICK); state(State::IDLE); break; case MOUSE_MOVE: + move_count++; + set_event(gui::Event::MOUSE_DRAG); state(State::MOUSE_MOVING); break; case KEY_PRESS: - dbc::log("send the key but cancel"); + set_event(gui::Event::KEY_PRESS); state(State::IDLE); break; default: @@ -94,22 +91,45 @@ namespace gui { void Router::MOUSE_MOVING(Event ev) { switch(ev) { - case MOUSE_DOWN: - dbc::log("mouse down in MOUSE_MOVING state"); + case MOUSE_UP: { + dbc::check(move_count < $drag_tolerance, "mouse up but not in dragging state"); + set_event(gui::Event::MOUSE_CLICK); + state(State::IDLE); + } break; + case MOUSE_MOVE: + move_count++; + + if(move_count < $drag_tolerance) { + set_event(gui::Event::MOUSE_DRAG); + } else { + set_event(gui::Event::MOUSE_DRAG_START); + state(State::MOUSE_DRAGGING); + } + break; + case KEY_PRESS: + set_event(gui::Event::KEY_PRESS); break; + default: + dbc::sentinel("invalid event"); + } + } + + + void Router::MOUSE_DRAGGING(Event ev) { + switch(ev) { case MOUSE_UP: - dbc::log("mouse up, send drop event"); + set_event(gui::Event::MOUSE_DROP); state(State::IDLE); break; case MOUSE_MOVE: - dbc::log("mouse move, send drag event"); + move_count++; + set_event(gui::Event::MOUSE_DRAG); break; case KEY_PRESS: - dbc::log("send the key but cancel"); - state(State::IDLE); + set_event(gui::Event::KEY_PRESS); break; default: - dbc::sentinel("invalid event"); + dbc::sentinel("invalid events"); } } } diff --git a/gui/event_router.hpp b/gui/event_router.hpp index 40cebdf..8de0e15 100644 --- a/gui/event_router.hpp +++ b/gui/event_router.hpp @@ -10,6 +10,7 @@ namespace gui { IDLE, MOUSE_ACTIVE, MOUSE_MOVING, + MOUSE_DRAGGING }; enum class Event { @@ -25,6 +26,8 @@ namespace gui { sf::Vector2i position; sf::Keyboard::Scancode scancode; gui::Event $next_event = gui::Event::TICK; + int move_count = 0; + int $drag_tolerance = 4; void event(Event ev); @@ -32,6 +35,7 @@ namespace gui { void IDLE(Event ev); void MOUSE_ACTIVE(Event ev); void MOUSE_MOVING(Event ev); + void MOUSE_DRAGGING(Event ev); gui::Event process_event(std::optional ev); diff --git a/gui/fsm.cpp b/gui/fsm.cpp index 3be2dbd..0221a67 100644 --- a/gui/fsm.cpp +++ b/gui/fsm.cpp @@ -127,6 +127,7 @@ namespace gui { state(State::IDLE); break; case LOOT_SELECT: { + fmt::println("loot is selected"); int slot_id = std::any_cast(data); if(auto entity = $loot_ui.select_slot(slot_id)) { @@ -137,8 +138,26 @@ namespace gui { case LOOT_PLACE: { std::string slot_name = std::any_cast(data); int slot_id = $status_ui.place_slot(slot_name); - $loot_ui.remove_slot(slot_id); + // BUG: fix this bullshit + if(slot_id != -1) { + $loot_ui.remove_slot(slot_id); + } } break; + case MOUSE_CLICK: + mouse_action(false); + break; + case MOUSE_MOVE: + mouse_action(true); + break; + case MOUSE_DRAG_START: + mouse_action(false); + break; + case MOUSE_DRAG: + mouse_action(true); + break; + case MOUSE_DROP: + mouse_action(false); + break; case TICK: // do nothing break; @@ -214,6 +233,17 @@ namespace gui { case LOOT_PLACE: // ignored break; + + case MOUSE_CLICK: + mouse_action(false); + break; + case MOUSE_MOVE: + mouse_action(true); + break; + case MOUSE_DRAG: // ignored + case MOUSE_DRAG_START: // ignored + case MOUSE_DROP: // ignored + break; default: dbc::sentinel("unhandled event in IDLE"); } @@ -227,6 +257,15 @@ namespace gui { sound::play("ambient"); next_level(); state(State::IDLE); + break; + case MOUSE_CLICK: { + sf::Vector2f pos = mouse_position(); + $boss_fight_ui->mouse(pos.x, pos.y, false); + + if($boss_fight_ui->boss_dead()) { + event(Event::STAIRS_DOWN); + } + } break; default: break; // do nothing for now } @@ -236,6 +275,12 @@ namespace gui { using enum Event; switch(ev) { + case MOUSE_CLICK: + mouse_action(false); + break; + case MOUSE_MOVE: + mouse_action(true); + break; case ATTACK: $main_ui.dirty(); sound::play("Sword_Hit_1"); @@ -280,45 +325,27 @@ namespace gui { dbc::log(fmt::format("END: received event after done: {}", int(ev))); } + sf::Vector2f FSM::mouse_position() { + return $window.mapPixelToCoords($router.position); + } + + void FSM::mouse_action(bool hover) { + sf::Vector2f pos = mouse_position(); + if($debug_ui.active) $debug_ui.mouse(pos.x, pos.y, hover); + $combat_ui.mouse(pos.x, pos.y, hover); + $status_ui.mouse(pos.x, pos.y, hover); + $main_ui.mouse(pos.x, pos.y, hover); + if($loot_ui.active) $loot_ui.mouse(pos.x, pos.y, hover); + } + void FSM::handle_keyboard_mouse() { while(const auto ev = $window.pollEvent()) { auto gui_ev = $router.process_event(ev); - if(gui_ev != gui::Event::TICK) { - event(gui_ev); - continue; - } - - if(const auto* mouse = ev->getIf()) { - if(mouse->button == sf::Mouse::Button::Left) { - sf::Vector2f pos = $window.mapPixelToCoords(mouse->position); - - if(in_state(State::NEXT_LEVEL)) { - $boss_fight_ui->mouse(pos.x, pos.y, false); - - if($boss_fight_ui->boss_dead()) { - event(Event::STAIRS_DOWN); - } - } else { - if($debug_ui.active) $debug_ui.mouse(pos.x, pos.y, false); - $combat_ui.mouse(pos.x, pos.y, false); - $status_ui.mouse(pos.x, pos.y, false); - $main_ui.mouse(pos.x, pos.y, false); - if($loot_ui.active) $loot_ui.mouse(pos.x, pos.y, false); - } - } - } else if(const auto* mouse = ev->getIf()) { - sf::Vector2f pos = $window.mapPixelToCoords(mouse->position); - if($debug_ui.active) $debug_ui.mouse(pos.x, pos.y, true); - $combat_ui.mouse(pos.x, pos.y, true); - $status_ui.mouse(pos.x, pos.y, true); - $main_ui.mouse(pos.x, pos.y, true); - } - - if(const auto* key = ev->getIf()) { + if(gui_ev == Event::KEY_PRESS) { using KEY = sf::Keyboard::Scan; - switch(key->scancode) { + switch($router.scancode) { case KEY::W: event(Event::MOVE_FORWARD); break; @@ -368,6 +395,8 @@ namespace gui { default: break; // ignored } + } else { + event(gui_ev); } } } diff --git a/gui/fsm.hpp b/gui/fsm.hpp index d2417d4..0905e76 100644 --- a/gui/fsm.hpp +++ b/gui/fsm.hpp @@ -46,6 +46,7 @@ namespace gui { LootUI $loot_ui; sf::Font $font; gui::routing::Router $router; + shared_ptr $dumb_sprite = nullptr; FSM(); @@ -67,6 +68,8 @@ namespace gui { void END(Event ev); void try_move(int dir, bool strafe); + sf::Vector2f mouse_position(); + void mouse_action(bool hover); void handle_keyboard_mouse(); void draw_gui(); void render(); diff --git a/gui/status_ui.cpp b/gui/status_ui.cpp index e014bfb..5fee91b 100644 --- a/gui/status_ui.cpp +++ b/gui/status_ui.cpp @@ -89,11 +89,12 @@ namespace gui { fmt::println("LOOT slot={}, entity={} PLACE into slot={}", $selected_slot, $selected_entity, name); - auto& sprite = $level.world->get($selected_entity); - auto gui_id = $gui.entity(name); - $gui.set_init(gui_id, {sprite.name}); - - $slots.insert_or_assign(name, $selected_entity); + if($level.world->has($selected_entity)) { + auto& sprite = $level.world->get($selected_entity); + auto gui_id = $gui.entity(name); + $gui.set_init(gui_id, {sprite.name}); + $slots.insert_or_assign(name, $selected_entity); + } return $selected_slot; } diff --git a/gui/status_ui.hpp b/gui/status_ui.hpp index 4f54bd4..3be241f 100644 --- a/gui/status_ui.hpp +++ b/gui/status_ui.hpp @@ -13,7 +13,7 @@ namespace gui { std::unordered_map $slots; GameLevel $level; ritual::UI $ritual_ui; - int $selected_slot; + int $selected_slot = -1; DinkyECS::Entity $selected_entity; StatusUI(GameLevel level);