Exploring raycasters and possibly make a little "doom like" game based on it.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
raycaster/gui/dnd_loot.cpp

267 lines
6.8 KiB

#include "gui/guecstra.hpp"
#include "gui/dnd_loot.hpp"
namespace gui {
DNDLoot::DNDLoot(StatusUI& status_ui, LootUI& loot_ui, sf::RenderWindow &window, routing::Router& router) :
$status_ui(status_ui),
$loot_ui(loot_ui),
$window(window),
$router(router)
{
event(Event::STARTED);
}
bool DNDLoot::event(Event ev, std::any data) {
switch($state) {
FSM_STATE(DNDState, START, ev);
FSM_STATE(DNDState, LOOTING, ev, data);
FSM_STATE(DNDState, LOOT_GRAB, ev, data);
FSM_STATE(DNDState, INV_GRAB, ev, data);
FSM_STATE(DNDState, ITEM_PICKUP, ev, data);
FSM_STATE(DNDState, INV_PICKUP, ev, data);
FSM_STATE(DNDState, END, ev, data);
default:
dbc::log(fmt::format("event received with data but state={} is not handled", int($state)));
}
return !in_state(DNDState::END);
}
void DNDLoot::START(Event ev) {
dbc::check(ev == Event::STARTED, "START not given a STARTED event.");
END(Event::CLOSE);
}
void DNDLoot::LOOTING(Event ev, std::any data) {
using enum Event;
switch(ev) {
case LOOT_OPEN:
END(Event::CLOSE);
break;
case LOOT_SELECT:
$grab_source = start_grab($loot_ui.$gui, data);
if($grab_source) state(DNDState::LOOT_GRAB);
break;
case INV_SELECT:
$grab_source = start_grab($status_ui.$gui, data);
if($grab_source) state(DNDState::INV_GRAB);
break;
case MOUSE_DRAG_START:
case MOUSE_CLICK:
mouse_action(false);
break;
default:
state(DNDState::LOOTING);
}
}
void DNDLoot::LOOT_GRAB(Event ev, std::any data) {
using enum Event;
switch(ev) {
case LOOT_OPEN:
END(Event::CLOSE);
break;
case LOOT_SELECT:
$grab_source = start_grab($loot_ui.$gui, data);
if($grab_source) state(DNDState::LOOTING);
break;
case INV_SELECT:
if(commit_drop($loot_ui.$gui,
$status_ui.$gui, $grab_source, data))
{
state(DNDState::LOOTING);
}
break;
default:
handle_mouse(ev, $loot_ui.$gui);
}
}
void DNDLoot::INV_GRAB(Event ev, std::any data) {
using enum Event;
switch(ev) {
case LOOT_OPEN:
END(Event::CLOSE);
break;
case LOOT_SELECT:
if(commit_drop($status_ui.$gui,
$loot_ui.$gui, $grab_source, data))
{
state(DNDState::LOOTING);
}
break;
case INV_SELECT:
$grab_source = start_grab($status_ui.$gui, data);
state(DNDState::LOOTING);
break;
default:
handle_mouse(ev, $status_ui.$gui);
}
}
void DNDLoot::INV_PICKUP(Event ev, std::any data) {
using enum Event;
(void)data;
switch(ev) {
case MOUSE_CLICK:
case MOUSE_DROP: {
auto& grab = $status_ui.$gui.get<guecs::GrabSource>(*$grab_source);
grab.commit();
bool dropped = $status_ui.drop_item(grab.world_entity);
dbc::check(dropped, "DROP FAILED!");
END(Event::CLOSE);
} break;
default:
handle_mouse(ev, $status_ui.$gui);
}
}
void DNDLoot::ITEM_PICKUP(Event ev, std::any data) {
using enum Event;
switch(ev) {
case INV_SELECT:
commit_drop($loot_ui.$gui, $status_ui.$gui, $grab_source, data);
{
END(Event::CLOSE);
}
break;
case LOOT_ITEM:
dbc::log("PUT IT BACK!");
break;
default:
handle_mouse(ev, $loot_ui.$gui);
}
}
void DNDLoot::END(Event ev, std::any data) {
using enum Event;
switch(ev) {
case LOOT_ITEM: {
// NOTE: if > 1 items, go to LOOT_OPEN instead
auto gui_id = $loot_ui.$gui.entity("item_0");
$grab_source = start_grab($loot_ui.$gui, gui_id);
if($grab_source) {
auto& source = $loot_ui.$gui.get<guecs::GrabSource>(*$grab_source);
$grab_sprite = source.sprite;
// call this once to properly position the sprite
handle_mouse(Event::MOUSE_MOVE, $loot_ui.$gui);
state(DNDState::ITEM_PICKUP);
}
} break;
case INV_SELECT: {
$grab_source = start_grab($status_ui.$gui, data);
if($grab_source) {
auto& source = $status_ui.$gui.get<guecs::GrabSource>(*$grab_source);
$grab_sprite = source.sprite;
state(DNDState::INV_PICKUP);
} else {
dbc::log("inv slot empty");
}
} break;
case LOOT_OPEN:
open();
state(DNDState::LOOTING);
break;
case CLOSE:
// called the first time transitioning to END
close();
state(DNDState::END);
break;
case TICK: // ignored
break;
default:
dbc::sentinel(fmt::format("invalid event: {}", int(ev)));
}
}
sf::Vector2f DNDLoot::mouse_position() {
return $window.mapPixelToCoords($router.position);
}
void DNDLoot::mouse_action(bool hover) {
sf::Vector2f pos = mouse_position();
$status_ui.mouse(pos.x, pos.y, hover);
if($loot_ui.active) $loot_ui.mouse(pos.x, pos.y, hover);
}
void DNDLoot::handle_mouse(Event ev, guecs::UI& gui) {
using enum Event;
switch(ev) {
case MOUSE_CLICK:
mouse_action(false);
break;
case MOUSE_DRAG:
case MOUSE_MOVE: {
if($grab_source) {
auto& source = gui.get<guecs::GrabSource>(*$grab_source);
source.move($window.mapPixelToCoords($router.position));
}
mouse_action(true);
} break;
case MOUSE_DRAG_START:
mouse_action(false);
break;
case MOUSE_DROP:
mouse_action(false);
break;
default:
break; // ignored
}
}
void DNDLoot::open() {
$grab_source = std::nullopt;
$grab_sprite = nullptr;
$loot_ui.active = true;
}
void DNDLoot::close() {
$grab_source = std::nullopt;
$grab_sprite = nullptr;
$loot_ui.active = false;
}
void DNDLoot::render() {
if($grab_source && $grab_sprite) {
$window.draw(*$grab_sprite);
}
}
std::optional<guecs::Entity> DNDLoot::start_grab(guecs::UI& gui, std::any data) {
auto gui_id = std::any_cast<guecs::Entity>(data);
if(auto source = gui.get_if<guecs::GrabSource>(gui_id)) {
source->grab();
return gui_id;
} else {
return std::nullopt;
}
}
bool DNDLoot::commit_drop(guecs::UI& source, guecs::UI& target,
std::optional<guecs::Entity> source_id, std::any data)
{
if(!source_id) return false;
auto target_id = std::any_cast<guecs::Entity>(data);
auto& drop = target.get<guecs::DropTarget>(target_id);
auto& grab = source.get<guecs::GrabSource>(*source_id);
if(drop.commit(grab.world_entity)) {
grab.commit();
return true;
} else {
return false;
}
}
}