Simple Loot UI started.
This commit is contained in:
parent
8a3046e141
commit
8545b8cf1d
23 changed files with 139 additions and 29 deletions
156
gui/boss_fight_ui.cpp
Normal file
156
gui/boss_fight_ui.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
#include "gui/boss_fight_ui.hpp"
|
||||
#include "easings.hpp"
|
||||
#include "sound.hpp"
|
||||
#include <fmt/xchar.h>
|
||||
|
||||
namespace gui {
|
||||
using namespace guecs;
|
||||
|
||||
BossFightUI::BossFightUI(shared_ptr<DinkyECS::World> world, DinkyECS::Entity boss_id)
|
||||
: $world(world),
|
||||
$boss_id(boss_id),
|
||||
$config(world->get_the<components::GameConfig>())
|
||||
{
|
||||
$status.position(0, 0, BOSS_VIEW_X, SCREEN_HEIGHT);
|
||||
$status.layout(
|
||||
"[main_status]"
|
||||
"[(150)status_3|(150)status_4]"
|
||||
"[(150)status_5|(150)status_6]"
|
||||
"[(150)status_7|(150)status_8]");
|
||||
|
||||
$overlay.position(BOSS_VIEW_X, BOSS_VIEW_Y,
|
||||
BOSS_VIEW_WIDTH, BOSS_VIEW_HEIGHT);
|
||||
|
||||
$overlay.layout("[overlay_1|overlay_2|overlay_4]"
|
||||
"[overlay_5|overlay_6|overlay_8]"
|
||||
"[overlay_9|overlay_10|overlay_12]"
|
||||
"[overlay_13|overlay_14|overlay_16]");
|
||||
|
||||
$sounds = $world->get<components::Sound>($boss_id);
|
||||
$combat = $world->get<components::Combat>($boss_id);
|
||||
}
|
||||
|
||||
void BossFightUI::configure_sprite() {
|
||||
$sprite_config = $world->get<components::Sprite>($boss_id);
|
||||
$animation = $world->get<components::Animation>($boss_id);
|
||||
$animation.frame_width = $sprite_config.width;
|
||||
|
||||
$boss_image = textures::get($sprite_config.name);
|
||||
sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}};
|
||||
$boss_image.sprite->setTextureRect(frame_rect);
|
||||
$boss_image.sprite->setScale({$sprite_config.scale, $sprite_config.scale});
|
||||
|
||||
auto bounds = $boss_image.sprite->getLocalBounds();
|
||||
auto bg_bounds = $boss_background.sprite->getLocalBounds();
|
||||
float x_diff = bg_bounds.size.x / 2;
|
||||
|
||||
$boss_pos = {float(BOSS_VIEW_X) + x_diff, bounds.size.y / 2};
|
||||
$boss_image.sprite->setOrigin({bounds.size.x / 2, bounds.size.y / 2});
|
||||
$boss_image.sprite->setPosition($boss_pos);
|
||||
}
|
||||
|
||||
void BossFightUI::configure_background() {
|
||||
auto& boss = $world->get<components::BossFight>($boss_id);
|
||||
|
||||
$boss_background = textures::get(boss.background);
|
||||
$boss_background.sprite->setPosition({BOSS_VIEW_X, BOSS_VIEW_Y});
|
||||
$status.set<Background>($status.MAIN, {$status.$parser});
|
||||
|
||||
if(boss.stage) {
|
||||
$boss_has_stage = true;
|
||||
$boss_stage = textures::get(*boss.stage);
|
||||
$boss_stage.sprite->setPosition({BOSS_VIEW_X, BOSS_VIEW_Y});
|
||||
}
|
||||
}
|
||||
|
||||
void BossFightUI::configure_gui() {
|
||||
for(auto& [name, cell] : $status.cells()) {
|
||||
auto button = $status.entity(name);
|
||||
$status.set<Rectangle>(button, {});
|
||||
$status.set<Clickable>(button, {
|
||||
[this, name](auto, auto){
|
||||
dbc::log(fmt::format("STATUS: {}", name));
|
||||
}
|
||||
});
|
||||
if(name == "main_status") {
|
||||
$status.set<Textual>(button, {fmt::format(L"HP: {}", $combat.hp)});
|
||||
} else {
|
||||
$status.set<Label>(button, {L"Attack"});
|
||||
}
|
||||
}
|
||||
$status.init();
|
||||
|
||||
for(auto& [name, cell] : $overlay.cells()) {
|
||||
auto region = $overlay.entity(name);
|
||||
$overlay.set<Clickable>(region, {
|
||||
[this, name](auto, auto){
|
||||
dbc::log(fmt::format("OVERLAY: {}", name));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$overlay.init();
|
||||
}
|
||||
|
||||
void BossFightUI::init() {
|
||||
// background must come first
|
||||
configure_background();
|
||||
configure_sprite();
|
||||
configure_gui();
|
||||
}
|
||||
|
||||
void BossFightUI::bounce_boss(sf::RenderWindow& window) {
|
||||
sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}};
|
||||
sf::Vector2f scale{$sprite_config.scale, $sprite_config.scale};
|
||||
sf::Vector2f pos{$boss_pos.x, $boss_pos.y};
|
||||
|
||||
$animation.step(scale, pos, frame_rect);
|
||||
$boss_image.sprite->setScale(scale);
|
||||
|
||||
if($animation.stationary) $boss_image.sprite->setPosition(pos);
|
||||
|
||||
if(!sound::playing($sounds.attack) && $animation.current == 1) {
|
||||
sound::play($sounds.attack);
|
||||
}
|
||||
|
||||
$boss_image.sprite->setTextureRect(frame_rect);
|
||||
window.draw(*$boss_image.sprite);
|
||||
}
|
||||
|
||||
void BossFightUI::render(sf::RenderWindow& window) {
|
||||
window.draw(*$boss_background.sprite);
|
||||
|
||||
if($boss_hit) {
|
||||
bounce_boss(window);
|
||||
} else {
|
||||
window.draw(*$boss_image.sprite);
|
||||
}
|
||||
|
||||
if($boss_has_stage) {
|
||||
window.draw(*$boss_stage.sprite);
|
||||
}
|
||||
|
||||
if($combat.hp == 0) {
|
||||
$overlay.show_label("overlay_1", L"YOU WON!");
|
||||
$overlay.show_label("overlay_4", L"CLICK TO CONTINUE...");
|
||||
}
|
||||
|
||||
$status.render(window);
|
||||
$overlay.render(window);
|
||||
}
|
||||
|
||||
bool BossFightUI::mouse(float x, float y, bool hover) {
|
||||
if($status.mouse(x, y, hover)) {
|
||||
dbc::log("STATUS button pressed");
|
||||
}
|
||||
|
||||
if($overlay.mouse(x, y, hover)) {
|
||||
$animation.play();
|
||||
sound::play("Sword_Hit_1");
|
||||
$boss_hit = !$boss_hit;
|
||||
$combat.hp--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
48
gui/boss_fight_ui.hpp
Normal file
48
gui/boss_fight_ui.hpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Graphics/Font.hpp>
|
||||
#include <guecs/ui.hpp>
|
||||
#include "textures.hpp"
|
||||
#include "components.hpp"
|
||||
#include <SFML/System/Clock.hpp>
|
||||
|
||||
// aspect ratio of art is 3/2 so 1.5
|
||||
// possible sizes: 900/600; 1620/1080; 1800/1200
|
||||
// To calculate it do short side * 1.5 so 1080 * 1.5 == 1620
|
||||
//
|
||||
// Side panel = 300/1080
|
||||
|
||||
namespace gui {
|
||||
using std::string;
|
||||
|
||||
class BossFightUI {
|
||||
public:
|
||||
sf::Clock $clock;
|
||||
bool $boss_hit = false;
|
||||
sf::Vector2f $boss_pos;
|
||||
components::Combat $combat;
|
||||
components::Sprite $sprite_config;
|
||||
components::Sound $sounds;
|
||||
components::Animation $animation;
|
||||
guecs::UI $status;
|
||||
guecs::UI $overlay;
|
||||
textures::SpriteTexture $boss_image;
|
||||
textures::SpriteTexture $boss_background;
|
||||
bool $boss_has_stage = false;
|
||||
textures::SpriteTexture $boss_stage;
|
||||
std::shared_ptr<DinkyECS::World> $world = nullptr;
|
||||
DinkyECS::Entity $boss_id;
|
||||
components::GameConfig& $config;
|
||||
|
||||
BossFightUI(std::shared_ptr<DinkyECS::World> world, DinkyECS::Entity boss_id);
|
||||
|
||||
void init();
|
||||
void render(sf::RenderWindow& window);
|
||||
bool mouse(float x, float y, bool hover);
|
||||
void bounce_boss(sf::RenderWindow& window);
|
||||
bool boss_dead() { return $combat.hp < 0; }
|
||||
void configure_sprite();
|
||||
void configure_background();
|
||||
void configure_gui();
|
||||
};
|
||||
}
|
86
gui/combat_ui.cpp
Normal file
86
gui/combat_ui.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include "gui/combat_ui.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "color.hpp"
|
||||
#include "rituals.hpp"
|
||||
#include <fmt/xchar.h>
|
||||
#include "guecstra.hpp"
|
||||
|
||||
namespace gui {
|
||||
using namespace guecs;
|
||||
|
||||
CombatUI::CombatUI(GameLevel level) :
|
||||
$level(level)
|
||||
{
|
||||
$gui.position(COMBAT_UI_X, COMBAT_UI_Y, COMBAT_UI_WIDTH, COMBAT_UI_HEIGHT);
|
||||
$gui.layout(
|
||||
"[button_0 | button_1 | button_2 | button_3"
|
||||
"|button_4 | button_5 | button_6 | hp_gauge ]"
|
||||
);
|
||||
}
|
||||
|
||||
DinkyECS::Entity CombatUI::make_button(
|
||||
std::string name,
|
||||
Events::GUI event,
|
||||
int action,
|
||||
const std::string &icon_name,
|
||||
const std::string &sound,
|
||||
const std::string &effect_name)
|
||||
{
|
||||
auto button = $gui.entity(name);
|
||||
$gui.set<Sprite>(button, {icon_name});
|
||||
$gui.set<Sound>(button, {sound});
|
||||
$gui.set<Effect>(button, {.duration=0.5f, .name=effect_name});
|
||||
$gui.set<Clickable>(button,
|
||||
guecs::make_action(*$level.world, event, {action}));
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
void CombatUI::init() {
|
||||
$gui.set<Background>($gui.MAIN, {$gui.$parser, ColorValue::DARK_MID});
|
||||
auto& the_belt = $level.world->get_the<ritual::Belt>();
|
||||
|
||||
for(int slot = 0; slot < the_belt.max_slots; slot++) {
|
||||
if(the_belt.has(slot)) {
|
||||
std::string name = fmt::format("button_{}", slot);
|
||||
auto& ritual = the_belt.get(slot);
|
||||
|
||||
using enum ritual::Element;
|
||||
|
||||
switch(ritual.element) {
|
||||
case FIRE:
|
||||
make_button(name, Events::GUI::ATTACK,
|
||||
slot, "broken_yoyo-64", "fireball_01", "flame");
|
||||
break;
|
||||
case LIGHTNING:
|
||||
make_button(name, Events::GUI::ATTACK,
|
||||
slot, "pocket_watch-64", "electric_shock_01", "lightning");
|
||||
break;
|
||||
default:
|
||||
make_button(name, Events::GUI::ATTACK,
|
||||
slot, "severed_finger-64", "punch_cartoony", "ui_shader");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto hp_gauge = $gui.entity("hp_gauge");
|
||||
$gui.set<Sprite>(hp_gauge, {"stone_doll_cursed-64"});
|
||||
$gui.set<Clickable>(hp_gauge,
|
||||
guecs::make_action(*$level.world, Events::GUI::HP_STATUS, {}));
|
||||
|
||||
$gui.init();
|
||||
}
|
||||
|
||||
void CombatUI::render(sf::RenderWindow& window) {
|
||||
$gui.render(window);
|
||||
}
|
||||
|
||||
void CombatUI::update_level(GameLevel &level) {
|
||||
$level = level;
|
||||
init();
|
||||
}
|
||||
|
||||
bool CombatUI::mouse(float x, float y, bool hover) {
|
||||
return $gui.mouse(x, y, hover);
|
||||
}
|
||||
}
|
24
gui/combat_ui.hpp
Normal file
24
gui/combat_ui.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "levelmanager.hpp"
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Graphics/Font.hpp>
|
||||
#include <guecs/ui.hpp>
|
||||
#include "events.hpp"
|
||||
|
||||
namespace gui {
|
||||
class CombatUI {
|
||||
public:
|
||||
guecs::UI $gui;
|
||||
GameLevel $level;
|
||||
|
||||
CombatUI(GameLevel level);
|
||||
|
||||
void init();
|
||||
void render(sf::RenderWindow& window);
|
||||
void update_level(GameLevel &level);
|
||||
bool mouse(float x, float y, bool hover);
|
||||
DinkyECS::Entity make_button(std::string name, Events::GUI event,
|
||||
int action, const std::string &icon_name,
|
||||
const std::string &sound, const std::string &effect_name);
|
||||
};
|
||||
}
|
118
gui/debug_ui.cpp
Normal file
118
gui/debug_ui.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
#include "gui/debug_ui.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "color.hpp"
|
||||
#include "events.hpp"
|
||||
#include <optional>
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/xchar.h>
|
||||
#include "components.hpp"
|
||||
|
||||
namespace gui {
|
||||
using namespace guecs;
|
||||
|
||||
DebugUI::DebugUI(LevelManager& level_mgr) :
|
||||
$level_mgr(level_mgr)
|
||||
{
|
||||
}
|
||||
|
||||
void DebugUI::init(lel::Cell cell) {
|
||||
$gui.position(cell.x, cell.y, cell.w, cell.h);
|
||||
$gui.layout(
|
||||
"[*%(100,400)debug_text]"
|
||||
"[_]"
|
||||
"[_]"
|
||||
"[_]"
|
||||
"[spawn1|spawn2|spawn3]"
|
||||
"[spawn4|spawn5|spawn6]");
|
||||
|
||||
add_spawn_button("AXE_RANGER", "axe_ranger", "spawn1");
|
||||
add_spawn_button("KNIGHT","armored_knight", "spawn2");
|
||||
add_spawn_button("SPIDER_GIANT_HAIRY", "hairy_spider", "spawn3");
|
||||
add_spawn_button("RAT_GIANT", "rat_with_sword", "spawn4");
|
||||
add_spawn_button("GOLD_SAVIOR", "gold_savior", "spawn5");
|
||||
|
||||
$gui.init();
|
||||
}
|
||||
|
||||
void DebugUI::add_spawn_button(std::string enemy_key, std::string sprite_name, std::string region) {
|
||||
auto button = $gui.entity(region);
|
||||
$gui.set<guecs::Clickable>(button, { [this, enemy_key](auto, auto){ spawn(enemy_key); } });
|
||||
$gui.set<guecs::Sprite>(button, { sprite_name});
|
||||
}
|
||||
|
||||
void DebugUI::spawn(std::string enemy_key) {
|
||||
auto ent = $level_mgr.spawn_enemy(enemy_key);
|
||||
|
||||
auto& level = $level_mgr.current();
|
||||
level.world->send<Events::GUI>(Events::GUI::ENEMY_SPAWN, ent, {});
|
||||
}
|
||||
|
||||
void DebugUI::render(sf::RenderWindow& window) {
|
||||
auto& level = $level_mgr.current();
|
||||
|
||||
auto debug_settings = level.world->get_the<components::Debug>();
|
||||
if(debug_settings.FPS) {
|
||||
auto player = level.world->get_the<components::Player>();
|
||||
auto player_combat = level.world->get<components::Combat>(player.entity);
|
||||
auto map = level.map;
|
||||
|
||||
std::wstring stats = fmt::format(L"STATS\n"
|
||||
L"HP: {}\n"
|
||||
L"mean:{:>8.5}\n"
|
||||
L"sdev: {:>8.5}\n"
|
||||
L"min: {:>8.5}\n"
|
||||
L"max: {:>8.5}\n"
|
||||
L"count:{:<10}\n"
|
||||
L"level: {} size: {}x{}\n\n"
|
||||
L"VSync? {}\n"
|
||||
L"FR Limit: {}\n"
|
||||
L"Debug? {}\n\n",
|
||||
player_combat.hp, $stats.mean(), $stats.stddev(), $stats.min,
|
||||
$stats.max, $stats.n, level.index, map->width(), map->height(),
|
||||
VSYNC, FRAME_LIMIT, DEBUG_BUILD);
|
||||
|
||||
$gui.show_text("debug_text", stats);
|
||||
$gui.render(window);
|
||||
// $gui.debug_layout(window);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugUI::debug() {
|
||||
auto& level = $level_mgr.current();
|
||||
|
||||
auto& dbg = level.world->get_the<components::Debug>();
|
||||
dbg.FPS = !dbg.FPS;
|
||||
dbg.PATHS = !dbg.PATHS;
|
||||
|
||||
if(dbg.FPS) {
|
||||
// it's on now, enable things
|
||||
auto player = level.world->get_the<components::Player>();
|
||||
auto& player_combat = level.world->get<components::Combat>(player.entity);
|
||||
player_combat.hp = player_combat.max_hp;
|
||||
$gui.show_text("debug_text", L"STATS");
|
||||
} else {
|
||||
// it's off now, close it
|
||||
$gui.close<Textual>("debug_text");
|
||||
}
|
||||
}
|
||||
|
||||
bool DebugUI::mouse(float x, float y, bool hover) {
|
||||
return $gui.mouse(x, y, hover);
|
||||
}
|
||||
|
||||
void DebugUI::update_level(GameLevel &level) {
|
||||
$level = level;
|
||||
}
|
||||
|
||||
Stats::TimeBullshit DebugUI::time_start() {
|
||||
return $stats.time_start();
|
||||
}
|
||||
|
||||
void DebugUI::sample_time(Stats::TimeBullshit start) {
|
||||
$stats.sample_time(start);
|
||||
}
|
||||
|
||||
void DebugUI::reset_stats() {
|
||||
$stats.reset();
|
||||
}
|
||||
}
|
30
gui/debug_ui.hpp
Normal file
30
gui/debug_ui.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
#include "levelmanager.hpp"
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Graphics/Font.hpp>
|
||||
#include <guecs/ui.hpp>
|
||||
#include "stats.hpp"
|
||||
|
||||
namespace gui {
|
||||
class DebugUI {
|
||||
public:
|
||||
Stats $stats;
|
||||
guecs::UI $gui;
|
||||
GameLevel $level;
|
||||
LevelManager& $level_mgr;
|
||||
|
||||
DebugUI(LevelManager& level_mgr);
|
||||
|
||||
void init(lel::Cell cell);
|
||||
void render(sf::RenderWindow& window);
|
||||
bool mouse(float x, float y, bool hover);
|
||||
void debug();
|
||||
void update_level(GameLevel &level);
|
||||
void spawn(std::string enemy_key);
|
||||
void add_spawn_button(std::string enemy_key, std::string sprite_name, std::string region);
|
||||
|
||||
Stats::TimeBullshit time_start();
|
||||
void sample_time(Stats::TimeBullshit start);
|
||||
void reset_stats();
|
||||
};
|
||||
}
|
481
gui/gui_fsm.cpp
Normal file
481
gui/gui_fsm.cpp
Normal file
|
@ -0,0 +1,481 @@
|
|||
#include "gui_fsm.hpp"
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <numeric>
|
||||
#include <functional>
|
||||
#include "components.hpp"
|
||||
#include <numbers>
|
||||
#include "systems.hpp"
|
||||
#include "events.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "shaders.hpp"
|
||||
#include <fmt/xchar.h>
|
||||
|
||||
namespace gui {
|
||||
using namespace components;
|
||||
|
||||
FSM::FSM() :
|
||||
$window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Raycaster Thing"),
|
||||
$debug_ui($levels),
|
||||
$main_ui($window),
|
||||
$level($levels.current()),
|
||||
$combat_ui($level),
|
||||
$status_ui($level),
|
||||
$map_ui($level),
|
||||
$mini_map($level),
|
||||
$loot_ui($level),
|
||||
$font{FONT_FILE_NAME}
|
||||
{
|
||||
}
|
||||
|
||||
void FSM::event(Event ev) {
|
||||
switch($state) {
|
||||
FSM_STATE(State, START, ev);
|
||||
FSM_STATE(State, MOVING, ev);
|
||||
FSM_STATE(State, ATTACKING, ev);
|
||||
FSM_STATE(State, ROTATING, ev);
|
||||
FSM_STATE(State, IDLE, ev);
|
||||
FSM_STATE(State, IN_COMBAT, ev);
|
||||
FSM_STATE(State, COMBAT_ROTATE, ev);
|
||||
FSM_STATE(State, NEXT_LEVEL, ev);
|
||||
FSM_STATE(State, LOOTING, ev);
|
||||
FSM_STATE(State, END, ev);
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::START(Event ) {
|
||||
|
||||
$main_ui.update_level($level);
|
||||
$level.world->set_the<Debug>({});
|
||||
$main_ui.init();
|
||||
$loot_ui.init();
|
||||
|
||||
// BUG: maybe this is a function on main_ui?
|
||||
auto cell = $main_ui.$overlay_ui.$gui.cell_for("left");
|
||||
$debug_ui.init(cell);
|
||||
$debug_ui.update_level($level);
|
||||
|
||||
$combat_ui.init();
|
||||
$status_ui.init();
|
||||
|
||||
$status_ui.log(L"Welcome to the game!");
|
||||
|
||||
$boss_fight_ui = $levels.create_bossfight($level.world);
|
||||
$boss_fight_ui->init();
|
||||
|
||||
$map_ui.init();
|
||||
$mini_map.init($main_ui.$overlay_ui.$gui);
|
||||
|
||||
run_systems();
|
||||
state(State::IDLE);
|
||||
}
|
||||
|
||||
void FSM::MOVING(Event ) {
|
||||
// this should be an optional that returns a point
|
||||
if(auto move_to = $main_ui.play_move()) {
|
||||
System::plan_motion(*$level.world, *move_to);
|
||||
run_systems();
|
||||
$main_ui.dirty();
|
||||
state(State::IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::ATTACKING(Event ev) {
|
||||
using enum Event;
|
||||
switch(ev) {
|
||||
case TICK: {
|
||||
System::combat($level, $temp_attack_id);
|
||||
run_systems();
|
||||
state(State::IN_COMBAT);
|
||||
} break;
|
||||
case STOP_COMBAT:
|
||||
dbc::log("Exiting ATTACKING STATE");
|
||||
state(State::IDLE);
|
||||
break;
|
||||
case ATTACK:
|
||||
// ignore these since they're just from SFML not having discrete events
|
||||
break;
|
||||
default:
|
||||
dbc::log(fmt::format("In ATTACKING state, unhandled event {}", (int)ev));
|
||||
state(State::IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::ROTATING(Event ) {
|
||||
if($main_ui.play_rotate()) {
|
||||
state(State::IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::COMBAT_ROTATE(Event ) {
|
||||
if($main_ui.play_rotate()) {
|
||||
state(State::IN_COMBAT);
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::LOOTING(Event ev) {
|
||||
using enum Event;
|
||||
|
||||
switch(ev) {
|
||||
case LOOT_OPEN:
|
||||
$loot_ui.active = false;
|
||||
state(State::IDLE);
|
||||
break;
|
||||
case TICK:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
state(State::LOOTING);
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::IDLE(Event ev) {
|
||||
using enum Event;
|
||||
|
||||
sound::stop("walk");
|
||||
|
||||
switch(ev) {
|
||||
case QUIT:
|
||||
$window.close();
|
||||
state(State::END);
|
||||
return; // done
|
||||
case MOVE_FORWARD:
|
||||
try_move(1, false);
|
||||
break;
|
||||
case MOVE_BACK:
|
||||
try_move(-1, false);
|
||||
break;
|
||||
case MOVE_LEFT:
|
||||
try_move(-1, true);
|
||||
break;
|
||||
case MOVE_RIGHT:
|
||||
try_move(1, true);
|
||||
break;
|
||||
case ROTATE_LEFT:
|
||||
$main_ui.plan_rotate(-1);
|
||||
state(State::ROTATING);
|
||||
break;
|
||||
case ROTATE_RIGHT:
|
||||
$main_ui.plan_rotate(1);
|
||||
state(State::ROTATING);
|
||||
break;
|
||||
case MAP_OPEN:
|
||||
$map_open = !$map_open;
|
||||
break;
|
||||
case ATTACK:
|
||||
state(State::ATTACKING);
|
||||
break;
|
||||
case START_COMBAT:
|
||||
$map_open = false;
|
||||
state(State::IN_COMBAT);
|
||||
break;
|
||||
case CLOSE:
|
||||
dbc::log("Nothing to close.");
|
||||
break;
|
||||
case STAIRS_DOWN:
|
||||
sound::stop("ambient");
|
||||
state(State::NEXT_LEVEL);
|
||||
break;
|
||||
case STOP_COMBAT:
|
||||
case TICK:
|
||||
// do nothing
|
||||
break;
|
||||
case LOOT_OPEN:
|
||||
$loot_ui.active = true;
|
||||
state(State::LOOTING);
|
||||
break;
|
||||
default:
|
||||
dbc::sentinel("unhandled event in IDLE");
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::NEXT_LEVEL(Event ev) {
|
||||
using enum Event;
|
||||
|
||||
switch(ev) {
|
||||
case STAIRS_DOWN:
|
||||
sound::play("ambient");
|
||||
next_level();
|
||||
state(State::IDLE);
|
||||
default:
|
||||
break; // do nothing for now
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::IN_COMBAT(Event ev) {
|
||||
using enum Event;
|
||||
|
||||
switch(ev) {
|
||||
case ATTACK:
|
||||
$main_ui.dirty();
|
||||
sound::play("Sword_Hit_1");
|
||||
state(State::ATTACKING);
|
||||
break;
|
||||
case ROTATE_LEFT:
|
||||
$main_ui.plan_rotate(-1);
|
||||
state(State::COMBAT_ROTATE);
|
||||
break;
|
||||
case ROTATE_RIGHT:
|
||||
$main_ui.plan_rotate(1);
|
||||
state(State::COMBAT_ROTATE);
|
||||
break;
|
||||
case STOP_COMBAT:
|
||||
$main_ui.$overlay_ui.close_sprite("top_right");
|
||||
state(State::IDLE);
|
||||
break;
|
||||
case QUIT:
|
||||
$window.close();
|
||||
state(State::END);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::try_move(int dir, bool strafe) {
|
||||
using enum State;
|
||||
// prevent moving into occupied space
|
||||
Point move_to = $main_ui.plan_move(dir, strafe);
|
||||
|
||||
if($level.map->can_move(move_to) && !$level.collision->occupied(move_to)) {
|
||||
sound::play("walk");
|
||||
state(MOVING);
|
||||
} else {
|
||||
state(IDLE);
|
||||
$main_ui.abort_plan();
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::END(Event ev) {
|
||||
dbc::log(fmt::format("END: received event after done: {}", int(ev)));
|
||||
}
|
||||
|
||||
void FSM::keyboard_mouse() {
|
||||
while(const auto ev = $window.pollEvent()) {
|
||||
|
||||
if(ev->is<sf::Event::Closed>()) {
|
||||
event(Event::QUIT);
|
||||
}
|
||||
|
||||
if(const auto* mouse = ev->getIf<sf::Event::MouseButtonPressed>()) {
|
||||
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 {
|
||||
$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::Event::MouseMoved>()) {
|
||||
sf::Vector2f pos = $window.mapPixelToCoords(mouse->position);
|
||||
$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<sf::Event::KeyPressed>()) {
|
||||
using KEY = sf::Keyboard::Scan;
|
||||
|
||||
switch(key->scancode) {
|
||||
case KEY::W:
|
||||
event(Event::MOVE_FORWARD);
|
||||
break;
|
||||
case KEY::S:
|
||||
event(Event::MOVE_BACK);
|
||||
break;
|
||||
case KEY::Q:
|
||||
event(Event::ROTATE_LEFT);
|
||||
break;
|
||||
case KEY::E:
|
||||
event(Event::ROTATE_RIGHT);
|
||||
break;
|
||||
case KEY::D:
|
||||
event(Event::MOVE_RIGHT);
|
||||
break;
|
||||
case KEY::A:
|
||||
event(Event::MOVE_LEFT);
|
||||
break;
|
||||
case KEY::R:
|
||||
dbc::log("HEY! DIPSHIT! You need to move debug ui so you can rest stats.");
|
||||
break;
|
||||
case KEY::M:
|
||||
event(Event::MAP_OPEN);
|
||||
break;
|
||||
case KEY::Escape:
|
||||
event(Event::CLOSE);
|
||||
break;
|
||||
case KEY::Space:
|
||||
event(Event::ATTACK);
|
||||
break;
|
||||
case KEY::P:
|
||||
sound::mute(false);
|
||||
$debug_ui.debug();
|
||||
shaders::reload();
|
||||
break;
|
||||
case KEY::O:
|
||||
autowalking = true;
|
||||
break;
|
||||
case KEY::L:
|
||||
event(Event::STAIRS_DOWN);
|
||||
break;
|
||||
case KEY::X:
|
||||
event(Event::LOOT_OPEN);
|
||||
break;
|
||||
default:
|
||||
break; // ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::draw_gui() {
|
||||
if(in_state(State::NEXT_LEVEL)) {
|
||||
$boss_fight_ui->render($window);
|
||||
} else {
|
||||
// BUG: maybe pass the stats to main_ui for this?
|
||||
auto start = $debug_ui.time_start();
|
||||
$main_ui.render();
|
||||
$debug_ui.sample_time(start);
|
||||
$debug_ui.render($window);
|
||||
$status_ui.render($window);
|
||||
$combat_ui.render($window);
|
||||
|
||||
if($loot_ui.active) $loot_ui.render($window);
|
||||
|
||||
if($map_open) {
|
||||
$map_ui.render($window, $main_ui.$compass_dir);
|
||||
} else {
|
||||
$mini_map.render($window, $main_ui.$compass_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::render() {
|
||||
if(in_state(State::NEXT_LEVEL)) {
|
||||
$window.clear();
|
||||
$boss_fight_ui->render($window);
|
||||
} else {
|
||||
draw_gui();
|
||||
}
|
||||
|
||||
$window.display();
|
||||
}
|
||||
|
||||
void FSM::run_systems() {
|
||||
System::generate_paths($level);
|
||||
System::enemy_ai_initialize($level);
|
||||
System::enemy_pathing($level);
|
||||
System::collision($level);
|
||||
System::motion($level);
|
||||
System::lighting($level);
|
||||
System::death($level, $levels.$components);
|
||||
}
|
||||
|
||||
bool FSM::active() {
|
||||
return !in_state(State::END);
|
||||
}
|
||||
|
||||
void FSM::handle_world_events() {
|
||||
using eGUI = Events::GUI;
|
||||
auto& world = *$level.world;
|
||||
|
||||
while(world.has_event<eGUI>()) {
|
||||
auto [evt, entity, data] = world.recv<eGUI>();
|
||||
auto player = world.get_the<Player>();
|
||||
|
||||
switch(evt) {
|
||||
case eGUI::COMBAT: {
|
||||
auto &damage = std::any_cast<Events::Combat&>(data);
|
||||
|
||||
if(damage.enemy_did > 0) {
|
||||
$status_ui.log(fmt::format(L"Enemy HIT YOU for {} damage!", damage.enemy_did));
|
||||
} else {
|
||||
$status_ui.log(L"Enemy MISSED YOU.");
|
||||
}
|
||||
|
||||
if(damage.player_did > 0) {
|
||||
$status_ui.log(fmt::format(L"You HIT enemy for {} damage!", damage.player_did));
|
||||
} else {
|
||||
$status_ui.log(L"You MISSED the enemy.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case eGUI::COMBAT_START:
|
||||
event(Event::START_COMBAT);
|
||||
break;
|
||||
case eGUI::ENEMY_SPAWN:
|
||||
$debug_ui.update_level($level);
|
||||
$main_ui.update_level($level);
|
||||
run_systems();
|
||||
break;
|
||||
case eGUI::NO_NEIGHBORS:
|
||||
event(Event::STOP_COMBAT);
|
||||
break;
|
||||
case eGUI::LOOT: {
|
||||
// auto &item = std::any_cast<InventoryItem&>(data);
|
||||
// $status_ui.log(fmt::format("You picked up a {}.",
|
||||
// std::string(item.data["name"])));
|
||||
$status_ui.log(L"You picked up an item.");
|
||||
} break;
|
||||
case eGUI::HP_STATUS:
|
||||
System::player_status($level);
|
||||
break;
|
||||
case eGUI::NEW_RITUAL:
|
||||
$combat_ui.init();
|
||||
break;
|
||||
case eGUI::EVADE:
|
||||
case eGUI::BLOCK:
|
||||
dbc::log("YOU NEED TO IMPLEMENT THIS!!!!!");
|
||||
break;
|
||||
case eGUI::ATTACK:
|
||||
$temp_attack_id = std::any_cast<int>(data);
|
||||
event(Event::ATTACK);
|
||||
break;
|
||||
case eGUI::STAIRS_DOWN:
|
||||
event(Event::STAIRS_DOWN);
|
||||
break;
|
||||
case eGUI::DEATH: {
|
||||
$status_ui.update();
|
||||
if(entity != player.entity) {
|
||||
$main_ui.dead_entity(entity);
|
||||
}
|
||||
} break;
|
||||
case eGUI::NOOP: {
|
||||
if(data.type() == typeid(std::string)) {
|
||||
auto name = std::any_cast<std::string>(data);
|
||||
$status_ui.log(fmt::format(L"NOOP EVENT! {},{}", evt, entity));
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
$status_ui.log(fmt::format(L"INVALID EVENT! {},{}", evt, entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FSM::next_level() {
|
||||
$levels.create_level($level.world);
|
||||
$level = $levels.next();
|
||||
|
||||
$debug_ui.update_level($level);
|
||||
$status_ui.update_level($level);
|
||||
$map_ui.update_level($level);
|
||||
$mini_map.update_level($level);
|
||||
$combat_ui.update_level($level);
|
||||
$main_ui.update_level($level);
|
||||
$loot_ui.update_level($level);
|
||||
|
||||
$boss_fight_ui = $levels.create_bossfight($level.world);
|
||||
$boss_fight_ui->init();
|
||||
|
||||
run_systems();
|
||||
}
|
||||
}
|
94
gui/gui_fsm.hpp
Normal file
94
gui/gui_fsm.hpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
#pragma once
|
||||
#include "constants.hpp"
|
||||
#include "stats.hpp"
|
||||
#include "levelmanager.hpp"
|
||||
#include "fsm.hpp"
|
||||
#include "gui/debug_ui.hpp"
|
||||
#include "gui/main_ui.hpp"
|
||||
#include "gui/combat_ui.hpp"
|
||||
#include "gui/status_ui.hpp"
|
||||
#include "gui/loot_ui.hpp"
|
||||
#include "gui/boss_fight_ui.hpp"
|
||||
#include "map_view.hpp"
|
||||
#include "mini_map.hpp"
|
||||
|
||||
namespace gui {
|
||||
enum class State {
|
||||
START,
|
||||
MOVING,
|
||||
IN_COMBAT,
|
||||
COMBAT_ROTATE,
|
||||
ATTACKING,
|
||||
ROTATING,
|
||||
NEXT_LEVEL,
|
||||
LOOTING,
|
||||
IDLE,
|
||||
END
|
||||
};
|
||||
|
||||
enum class Event {
|
||||
STARTED=0,
|
||||
TICK=1,
|
||||
MOVE_FORWARD = 2,
|
||||
MOVE_BACK = 3,
|
||||
MOVE_LEFT = 4,
|
||||
MOVE_RIGHT = 5,
|
||||
MAP_OPEN = 6,
|
||||
CLOSE = 7,
|
||||
ROTATE_LEFT = 8,
|
||||
ROTATE_RIGHT = 9,
|
||||
ATTACK = 10,
|
||||
START_COMBAT = 11,
|
||||
STOP_COMBAT = 12,
|
||||
STAIRS_DOWN = 13,
|
||||
LOOT_OPEN=14,
|
||||
QUIT = 15
|
||||
};
|
||||
|
||||
class FSM : public DeadSimpleFSM<State, Event> {
|
||||
public:
|
||||
sf::RenderWindow $window;
|
||||
bool $draw_stats = false;
|
||||
bool autowalking = false;
|
||||
bool $map_open = false;
|
||||
int $temp_attack_id = 0;
|
||||
LevelManager $levels;
|
||||
DebugUI $debug_ui;
|
||||
MainUI $main_ui;
|
||||
GameLevel $level;
|
||||
shared_ptr<BossFightUI> $boss_fight_ui = nullptr;
|
||||
CombatUI $combat_ui;
|
||||
StatusUI $status_ui;
|
||||
MapViewUI $map_ui;
|
||||
MiniMapUI $mini_map;
|
||||
LootUI $loot_ui;
|
||||
sf::Font $font;
|
||||
|
||||
FSM();
|
||||
|
||||
void event(Event ev);
|
||||
void autowalk();
|
||||
void start_autowalk(double rot_speed);
|
||||
|
||||
void START(Event );
|
||||
void MOVING(Event );
|
||||
void ATTACKING(Event );
|
||||
void MAPPING(Event);
|
||||
void ROTATING(Event );
|
||||
void IDLE(Event ev);
|
||||
void IN_COMBAT(Event ev);
|
||||
void COMBAT_ROTATE(Event ev);
|
||||
void NEXT_LEVEL(Event ev);
|
||||
void LOOTING(Event ev);
|
||||
void END(Event ev);
|
||||
|
||||
void try_move(int dir, bool strafe);
|
||||
void keyboard_mouse();
|
||||
void draw_gui();
|
||||
void render();
|
||||
bool active();
|
||||
void run_systems();
|
||||
void handle_world_events();
|
||||
void next_level();
|
||||
};
|
||||
}
|
51
gui/loot_ui.cpp
Normal file
51
gui/loot_ui.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "gui/loot_ui.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "color.hpp"
|
||||
#include <fmt/xchar.h>
|
||||
#include "guecstra.hpp"
|
||||
|
||||
namespace gui {
|
||||
using namespace guecs;
|
||||
|
||||
LootUI::LootUI(GameLevel level) :
|
||||
$level(level)
|
||||
{
|
||||
$gui.position(RAY_VIEW_X+RAY_VIEW_WIDTH/2-200,
|
||||
RAY_VIEW_Y+RAY_VIEW_HEIGHT/2-200, 400, 400);
|
||||
|
||||
$gui.layout(
|
||||
"[button_0 | button_1|button_2 | button_3]"
|
||||
"[button_4 | button_5|button_6 | button_7]"
|
||||
"[button_8 | button_9|button_10 | button_11]"
|
||||
"[button_12 | button_13|button_14 | button_15]"
|
||||
);
|
||||
}
|
||||
|
||||
void LootUI::init() {
|
||||
$gui.set<Background>($gui.MAIN, {$gui.$parser, ColorValue::DARK_MID});
|
||||
for(auto [name, cell] : $gui.cells()) {
|
||||
auto id = $gui.entity(name);
|
||||
$gui.set<guecs::Rectangle>(id, {});
|
||||
if(id < 4) {
|
||||
$gui.set<guecs::Clickable>(id, {
|
||||
[=](auto, auto) { fmt::println("clicked {}", name); }
|
||||
});
|
||||
$gui.set<guecs::Sprite>(id, {"broken_yoyo-64"});
|
||||
}
|
||||
}
|
||||
$gui.init();
|
||||
}
|
||||
|
||||
void LootUI::render(sf::RenderWindow& window) {
|
||||
$gui.render(window);
|
||||
}
|
||||
|
||||
void LootUI::update_level(GameLevel &level) {
|
||||
$level = level;
|
||||
init();
|
||||
}
|
||||
|
||||
bool LootUI::mouse(float x, float y, bool hover) {
|
||||
return $gui.mouse(x, y, hover);
|
||||
}
|
||||
}
|
22
gui/loot_ui.hpp
Normal file
22
gui/loot_ui.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include "levelmanager.hpp"
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Graphics/Font.hpp>
|
||||
#include <guecs/ui.hpp>
|
||||
#include "events.hpp"
|
||||
|
||||
namespace gui {
|
||||
class LootUI {
|
||||
public:
|
||||
bool active = false;
|
||||
guecs::UI $gui;
|
||||
GameLevel $level;
|
||||
|
||||
LootUI(GameLevel level);
|
||||
|
||||
void init();
|
||||
void render(sf::RenderWindow& window);
|
||||
void update_level(GameLevel &level);
|
||||
bool mouse(float x, float y, bool hover);
|
||||
};
|
||||
}
|
115
gui/main_ui.cpp
Normal file
115
gui/main_ui.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include "gui/main_ui.hpp"
|
||||
#include "components.hpp"
|
||||
#include "easings.hpp"
|
||||
#include <fmt/xchar.h>
|
||||
#include "constants.hpp"
|
||||
|
||||
namespace gui {
|
||||
using namespace components;
|
||||
|
||||
MainUI::MainUI(sf::RenderWindow& window) :
|
||||
$window(window),
|
||||
$rayview(RAY_VIEW_WIDTH, RAY_VIEW_HEIGHT),
|
||||
$camera($rayview)
|
||||
{
|
||||
$window.setVerticalSyncEnabled(VSYNC);
|
||||
$window.setFramerateLimit(FRAME_LIMIT);
|
||||
}
|
||||
|
||||
void MainUI::dirty() {
|
||||
$needs_render = true;
|
||||
}
|
||||
|
||||
void MainUI::init() {
|
||||
auto& player_position = $level.world->get<Position>($level.player);
|
||||
auto player = player_position.location;
|
||||
|
||||
$rayview.init_shaders();
|
||||
$rayview.set_position(RAY_VIEW_X, RAY_VIEW_Y);
|
||||
$rayview.position_camera(player.x + 0.5, player.y + 0.5);
|
||||
|
||||
auto st = textures::get("down_the_well");
|
||||
auto bounds = st.sprite->getLocalBounds();
|
||||
st.sprite->setPosition({RAY_VIEW_X + bounds.size.x / 2,
|
||||
RAY_VIEW_Y + bounds.size.y / 2});
|
||||
st.sprite->setOrigin({bounds.size.x / 2, bounds.size.y / 2});
|
||||
|
||||
$overlay_ui.init();
|
||||
}
|
||||
|
||||
void MainUI::render() {
|
||||
auto aimed_at = $camera.aimed_at();
|
||||
if($level.collision->occupied(aimed_at)) {
|
||||
$rayview.aiming_at = $level.collision->get(aimed_at);
|
||||
} else {
|
||||
$rayview.aiming_at = 0;
|
||||
}
|
||||
|
||||
if($needs_render) $rayview.render();
|
||||
$rayview.draw($window);
|
||||
|
||||
$overlay_ui.render($window);
|
||||
}
|
||||
|
||||
void MainUI::health_low() {
|
||||
$overlay_ui.show_sprite("middle", "blood_splatter");
|
||||
}
|
||||
|
||||
bool MainUI::play_rotate() {
|
||||
bool done = $camera.play_rotate();
|
||||
$needs_render = !done;
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
// this could be an optional that returs a Point
|
||||
std::optional<Point> MainUI::play_move() {
|
||||
if($camera.play_move()) {
|
||||
$needs_render = false;
|
||||
Point pos{
|
||||
size_t($camera.target_x),
|
||||
size_t($camera.target_y)};
|
||||
return std::make_optional<Point>(pos);
|
||||
|
||||
} else {
|
||||
$needs_render = true;
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
void MainUI::plan_rotate(int dir) {
|
||||
// -1 is left, 1 is right
|
||||
$compass_dir = ($compass_dir + dir) % COMPASS.size();
|
||||
$camera.plan_rotate(dir);
|
||||
}
|
||||
|
||||
Point MainUI::plan_move(int dir, bool strafe) {
|
||||
return $camera.plan_move(dir, strafe);
|
||||
}
|
||||
|
||||
void MainUI::abort_plan() {
|
||||
$camera.abort_plan();
|
||||
}
|
||||
|
||||
void MainUI::dead_entity(DinkyECS::Entity entity) {
|
||||
auto &sprite = $level.world->get<components::Sprite>(entity);
|
||||
$rayview.update_sprite(entity, sprite);
|
||||
}
|
||||
|
||||
void MainUI::update_level(GameLevel level) {
|
||||
$level = level;
|
||||
auto& player_position = $level.world->get<Position>($level.player);
|
||||
auto player = player_position.location;
|
||||
|
||||
$rayview.update_level($level);
|
||||
$rayview.position_camera(player.x + 0.5, player.y + 0.5);
|
||||
|
||||
$compass_dir = 0;
|
||||
|
||||
dirty();
|
||||
}
|
||||
|
||||
void MainUI::mouse(int x, int y, bool hover) {
|
||||
$overlay_ui.$gui.mouse(x, y, hover);
|
||||
}
|
||||
}
|
46
gui/main_ui.hpp
Normal file
46
gui/main_ui.hpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
#include "levelmanager.hpp"
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/System/Clock.hpp>
|
||||
#include "stats.hpp"
|
||||
#include <guecs/ui.hpp>
|
||||
#include "gui/overlay_ui.hpp"
|
||||
#include "gui/debug_ui.hpp"
|
||||
#include "raycaster.hpp"
|
||||
#include "camera.hpp"
|
||||
#include <optional>
|
||||
|
||||
namespace gui {
|
||||
|
||||
class MainUI {
|
||||
public:
|
||||
int $compass_dir = 0;
|
||||
bool $needs_render = true;
|
||||
sf::Clock $clock;
|
||||
sf::RenderWindow& $window;
|
||||
GameLevel $level;
|
||||
OverlayUI $overlay_ui;
|
||||
Raycaster $rayview;
|
||||
CameraLOL $camera;
|
||||
|
||||
MainUI(sf::RenderWindow& window);
|
||||
|
||||
void mouse(int x, int y, bool hover);
|
||||
void debug();
|
||||
void render_debug();
|
||||
|
||||
void plan_rotate(int dir);
|
||||
bool play_rotate();
|
||||
std::optional<Point> play_move();
|
||||
Point plan_move(int dir, bool strafe);
|
||||
void abort_plan();
|
||||
void update_level(GameLevel level);
|
||||
|
||||
void init();
|
||||
void render();
|
||||
void dirty();
|
||||
|
||||
void health_low();
|
||||
void dead_entity(DinkyECS::Entity entity);
|
||||
};
|
||||
}
|
51
gui/overlay_ui.cpp
Normal file
51
gui/overlay_ui.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "gui/overlay_ui.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "color.hpp"
|
||||
#include "events.hpp"
|
||||
#include <optional>
|
||||
|
||||
namespace gui {
|
||||
using namespace guecs;
|
||||
|
||||
OverlayUI::OverlayUI() {
|
||||
$gui.position(RAY_VIEW_X, RAY_VIEW_Y, RAY_VIEW_WIDTH, RAY_VIEW_HEIGHT);
|
||||
$gui.layout(
|
||||
"[*%(100,300)left|top|>(170,170)top_right]"
|
||||
"[_|middle|middle_right]"
|
||||
"[_|bottom|bottom_right]"
|
||||
);
|
||||
}
|
||||
|
||||
void OverlayUI::init() {
|
||||
$gui.init();
|
||||
}
|
||||
|
||||
void OverlayUI::render(sf::RenderWindow& window) {
|
||||
$gui.render(window);
|
||||
// $gui.debug_layout(window);
|
||||
}
|
||||
|
||||
void OverlayUI::show_sprite(string region, string sprite_name) {
|
||||
$gui.show_sprite(region, sprite_name);
|
||||
}
|
||||
|
||||
void OverlayUI::close_sprite(string region) {
|
||||
$gui.close<Sprite>(region);
|
||||
}
|
||||
|
||||
void OverlayUI::show_text(string region, wstring content) {
|
||||
$gui.show_text(region, content);
|
||||
}
|
||||
|
||||
void OverlayUI::close_text(string region) {
|
||||
$gui.close<Textual>(region);
|
||||
}
|
||||
|
||||
void OverlayUI::show_label(string region, wstring content) {
|
||||
$gui.show_label(region, content);
|
||||
}
|
||||
|
||||
void OverlayUI::close_label(string region) {
|
||||
$gui.close<Label>(region);
|
||||
}
|
||||
}
|
26
gui/overlay_ui.hpp
Normal file
26
gui/overlay_ui.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Graphics/Font.hpp>
|
||||
#include <guecs/ui.hpp>
|
||||
|
||||
namespace gui {
|
||||
using std::string;
|
||||
|
||||
class OverlayUI {
|
||||
public:
|
||||
guecs::UI $gui;
|
||||
|
||||
OverlayUI();
|
||||
|
||||
void init();
|
||||
void render(sf::RenderWindow& window);
|
||||
void show_sprite(string region, string sprite_name);
|
||||
void close_sprite(string region);
|
||||
void show_text(std::string region, std::wstring content);
|
||||
void update_text(std::string region, std::wstring content);
|
||||
void close_text(std::string region);
|
||||
void show_label(std::string region, std::wstring content);
|
||||
void update_label(std::string region, std::wstring content);
|
||||
void close_label(std::string region);
|
||||
};
|
||||
}
|
252
gui/ritual_ui.cpp
Normal file
252
gui/ritual_ui.cpp
Normal file
|
@ -0,0 +1,252 @@
|
|||
#include "gui/ritual_ui.hpp"
|
||||
#include "components.hpp"
|
||||
#include <guecs/ui.hpp>
|
||||
#include "rand.hpp"
|
||||
#include "animation.hpp"
|
||||
#include "rand.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "events.hpp"
|
||||
|
||||
namespace gui {
|
||||
namespace ritual {
|
||||
using namespace guecs;
|
||||
using std::any, std::any_cast, std::string, std::make_any;
|
||||
|
||||
UI::UI(GameLevel level) :
|
||||
$level(level),
|
||||
$blanket($level.world->get_the<::ritual::Blanket>())
|
||||
{
|
||||
$gui.position(STATUS_UI_X, STATUS_UI_Y, STATUS_UI_WIDTH, STATUS_UI_HEIGHT);
|
||||
$gui.layout(
|
||||
"[_]"
|
||||
"[inv_slot0 | inv_slot1 | inv_slot2| inv_slot3]"
|
||||
"[inv_slot4 | inv_slot5 | inv_slot6| inv_slot7]"
|
||||
"[inv_slot8 | inv_slot9 | inv_slot10| inv_slot11]"
|
||||
"[inv_slot12 | inv_slot13 | inv_slot14| inv_slot15]"
|
||||
"[inv_slot16 | inv_slot17 | inv_slot18| inv_slot19]"
|
||||
"[_ |*%(200,400)result_text|_]"
|
||||
"[*%(100,200)result_image|_ |_]"
|
||||
"[_|_|_]"
|
||||
"[_|_|_]"
|
||||
"[_]"
|
||||
"[ ritual_ui ]");
|
||||
}
|
||||
|
||||
void UI::event(Event ev, std::any data) {
|
||||
switch($state) {
|
||||
FSM_STATE(State, START, ev);
|
||||
FSM_STATE(State, OPENED, ev, data);
|
||||
FSM_STATE(State, CRAFTING, ev, data);
|
||||
FSM_STATE(State, CLOSED, ev);
|
||||
FSM_STATE(State, OPENING, ev);
|
||||
FSM_STATE(State, CLOSING, ev);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::START(Event) {
|
||||
$ritual_ui = textures::get("ritual_crafting_area");
|
||||
$ritual_ui.sprite->setPosition($gui.get_position());
|
||||
$ritual_ui.sprite->setTextureRect($ritual_closed_rect);
|
||||
state(State::CLOSED);
|
||||
$ritual_anim = animation::load("ritual_blanket");
|
||||
|
||||
auto open_close_toggle = $gui.entity("ritual_ui");
|
||||
$gui.set<Clickable>(open_close_toggle, {
|
||||
[&](auto, auto){ event(Event::TOGGLE); }
|
||||
});
|
||||
|
||||
|
||||
$craft_state = $ritual_engine.start();
|
||||
$gui.init();
|
||||
|
||||
state(State::CLOSED);
|
||||
}
|
||||
|
||||
void UI::OPENED(Event ev, std::any data) {
|
||||
if(ev == Event::TOGGLE) {
|
||||
clear_blanket();
|
||||
state(State::CLOSING);
|
||||
} else if(ev == Event::SELECT) {
|
||||
// do this before transitioning
|
||||
state(State::CRAFTING);
|
||||
UI::CRAFTING(ev, data);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::CRAFTING(Event ev, std::any data) {
|
||||
if(ev == Event::TOGGLE) {
|
||||
clear_blanket();
|
||||
state(State::CLOSING);
|
||||
} else if(ev == Event::COMBINE) {
|
||||
complete_combine();
|
||||
} else if(ev == Event::SELECT) {
|
||||
dbc::check(data.has_value(), "OPENED state given SELECT with no data");
|
||||
auto pair = std::any_cast<SelectedItem>(data);
|
||||
select_item(pair);
|
||||
update_selection_state();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UI::CLOSED(Event ev) {
|
||||
if(ev == Event::TOGGLE) {
|
||||
$ritual_anim.play();
|
||||
load_blanket();
|
||||
state(State::OPENING);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::OPENING(Event ev) {
|
||||
if(ev == Event::TICK) {
|
||||
if(!animation::apply($ritual_anim, $ritual_ui)) {
|
||||
state(State::OPENED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UI::CLOSING(Event ev) {
|
||||
if(ev == Event::TICK) {
|
||||
$ritual_ui.sprite->setTextureRect($ritual_closed_rect);
|
||||
state(State::CLOSED);
|
||||
}
|
||||
}
|
||||
|
||||
bool UI::mouse(float x, float y, bool hover) {
|
||||
return $gui.mouse(x, y, hover);
|
||||
}
|
||||
|
||||
bool UI::is_open() {
|
||||
return !in_state(State::CLOSED);
|
||||
}
|
||||
|
||||
void UI::render(sf::RenderWindow &window) {
|
||||
event(Event::TICK);
|
||||
|
||||
window.draw(*$ritual_ui.sprite);
|
||||
|
||||
if(in_state(State::OPENED) || in_state(State::CRAFTING)) {
|
||||
$gui.render(window);
|
||||
// $gui.debug_layout(window);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::clear_blanket() {
|
||||
for(int i = 0; i < INV_SLOTS; i++) {
|
||||
auto slot_id = $gui.entity("inv_slot", i);
|
||||
|
||||
if($gui.has<Sprite>(slot_id)) {
|
||||
$gui.remove<Sprite>(slot_id);
|
||||
$gui.remove<Clickable>(slot_id);
|
||||
}
|
||||
}
|
||||
|
||||
$blanket.reset();
|
||||
}
|
||||
|
||||
void UI::select_item(SelectedItem pair) {
|
||||
auto& sprite = $gui.get<Sprite>(pair.slot_id);
|
||||
|
||||
if($blanket.is_selected(pair.item_id)) {
|
||||
$blanket.deselect(pair.item_id);
|
||||
sprite.sprite->setColor({255, 255, 255, 255});
|
||||
} else {
|
||||
$blanket.select(pair.item_id);
|
||||
sprite.sprite->setColor({255, 200, 200, 200});
|
||||
}
|
||||
}
|
||||
|
||||
void UI::update_selection_state() {
|
||||
if($blanket.no_selections()) {
|
||||
clear_craft_result();
|
||||
state(State::OPENED);
|
||||
} else {
|
||||
run_crafting_engine();
|
||||
show_craft_result();
|
||||
}
|
||||
}
|
||||
|
||||
void UI::load_blanket() {
|
||||
// update the list of available items
|
||||
int i = 0;
|
||||
for(auto& [item_id, item] : $blanket.contents) {
|
||||
auto slot_id = $gui.entity("inv_slot", i++);
|
||||
auto icon_name = fmt::format("{}-64", item);
|
||||
|
||||
$gui.set_init<Sprite>(slot_id, {icon_name});
|
||||
$gui.set<Clickable>(slot_id, {
|
||||
[&, slot_id, item_id](auto, auto) {
|
||||
auto data = std::make_any<SelectedItem>(slot_id, item_id);
|
||||
event(Event::SELECT, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(; i < INV_SLOTS; i++) {
|
||||
auto slot_id = $gui.entity("inv_slot", i);
|
||||
$gui.remove<Sprite>(slot_id);
|
||||
$gui.remove<Clickable>(slot_id);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::complete_combine() {
|
||||
if($craft_state.is_combined()) {
|
||||
auto ritual = $ritual_engine.finalize($craft_state);
|
||||
auto& belt = $level.world->get_the<::ritual::Belt>();
|
||||
belt.equip(belt.next(), ritual);
|
||||
$level.world->send<Events::GUI>(Events::GUI::NEW_RITUAL, $level.player, {});
|
||||
$blanket.consume_crafting();
|
||||
clear_craft_result();
|
||||
|
||||
load_blanket();
|
||||
state(State::OPENED);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::run_crafting_engine() {
|
||||
$craft_state.reset();
|
||||
|
||||
for(auto [item_id, setting] : $blanket.selected) {
|
||||
auto& item = $blanket.get(item_id);
|
||||
$ritual_engine.load_junk($craft_state, item);
|
||||
}
|
||||
|
||||
$ritual_engine.plan($craft_state);
|
||||
}
|
||||
|
||||
void UI::show_craft_result() {
|
||||
using enum ::ritual::Element;
|
||||
auto ritual = $ritual_engine.finalize($craft_state);
|
||||
auto combine = $gui.entity("result_image");
|
||||
|
||||
if($craft_state.is_combined()) {
|
||||
$gui.show_label("result_text", L"This might work...");
|
||||
|
||||
switch(ritual.element) {
|
||||
case FIRE:
|
||||
$gui.show_sprite("result_image", "broken_yoyo-64");
|
||||
break;
|
||||
case LIGHTNING:
|
||||
$gui.show_sprite("result_image", "pocket_watch-64");
|
||||
break;
|
||||
default:
|
||||
$gui.show_sprite("result_image", "severed_finger-64");
|
||||
}
|
||||
|
||||
$gui.set<Clickable>(combine, {
|
||||
[&](auto, auto){ event(Event::COMBINE); }
|
||||
});
|
||||
} else {
|
||||
$gui.show_label("result_text", L"That won't work.");
|
||||
$gui.show_sprite("result_image", "dubious_combination-128");
|
||||
$gui.remove<Clickable>(combine);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void UI::clear_craft_result() {
|
||||
$blanket.reset();
|
||||
$gui.close<Label>("result_text");
|
||||
$gui.close<Sprite>("result_image");
|
||||
}
|
||||
}
|
||||
}
|
69
gui/ritual_ui.hpp
Normal file
69
gui/ritual_ui.hpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
#include "levelmanager.hpp"
|
||||
#include "constants.hpp"
|
||||
#include <deque>
|
||||
#include "textures.hpp"
|
||||
#include <guecs/ui.hpp>
|
||||
#include "rituals.hpp"
|
||||
#include "fsm.hpp"
|
||||
|
||||
namespace gui {
|
||||
namespace ritual {
|
||||
enum class State {
|
||||
START=0,
|
||||
OPENED=1,
|
||||
CLOSED=2,
|
||||
OPENING=3,
|
||||
CLOSING=4,
|
||||
CRAFTING=5
|
||||
};
|
||||
|
||||
enum class Event {
|
||||
STARTED=0,
|
||||
TOGGLE=1,
|
||||
TICK=2,
|
||||
SELECT=3,
|
||||
COMBINE=4
|
||||
};
|
||||
|
||||
struct SelectedItem {
|
||||
DinkyECS::Entity slot_id;
|
||||
DinkyECS::Entity item_id;
|
||||
};
|
||||
|
||||
class UI : public DeadSimpleFSM<State, Event> {
|
||||
public:
|
||||
sf::IntRect $ritual_closed_rect{{0,0},{380,720}};
|
||||
sf::IntRect $ritual_open_rect{{380 * 2,0},{380,720}};
|
||||
components::Animation $ritual_anim;
|
||||
guecs::UI $gui;
|
||||
GameLevel $level;
|
||||
textures::SpriteTexture $ritual_ui;
|
||||
::ritual::Blanket& $blanket;
|
||||
::ritual::Engine $ritual_engine;
|
||||
::ritual::CraftingState $craft_state;
|
||||
|
||||
UI(GameLevel level);
|
||||
|
||||
void event(Event ev, std::any data={});
|
||||
void START(Event);
|
||||
void OPENED(Event, std::any data={});
|
||||
void CRAFTING(Event, std::any data={});
|
||||
void CLOSED(Event);
|
||||
void OPENING(Event);
|
||||
void CLOSING(Event);
|
||||
|
||||
bool mouse(float x, float y, bool hover);
|
||||
void render(sf::RenderWindow &window);
|
||||
bool is_open();
|
||||
void load_blanket();
|
||||
void clear_blanket();
|
||||
void select_item(SelectedItem pair);
|
||||
void show_craft_result();
|
||||
void clear_craft_result();
|
||||
void run_crafting_engine();
|
||||
void complete_combine();
|
||||
void update_selection_state();
|
||||
};
|
||||
}
|
||||
}
|
155
gui/status_ui.cpp
Normal file
155
gui/status_ui.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
#include "gui/status_ui.hpp"
|
||||
#include "components.hpp"
|
||||
#include "inventory.hpp"
|
||||
#include "color.hpp"
|
||||
#include <guecs/ui.hpp>
|
||||
#include "rand.hpp"
|
||||
#include <fmt/xchar.h>
|
||||
|
||||
namespace gui {
|
||||
using namespace guecs;
|
||||
using std::any, std::any_cast, std::string, std::make_any;
|
||||
|
||||
StatusUI::StatusUI(GameLevel level) :
|
||||
$level(level), $ritual_ui(level)
|
||||
{
|
||||
$gui.position(STATUS_UI_X, STATUS_UI_Y, STATUS_UI_WIDTH, STATUS_UI_HEIGHT);
|
||||
$gui.layout(
|
||||
"[ ritual_ui ]"
|
||||
"[inv_slot1 | inv_slot2 | inv_slot3]"
|
||||
"[inv_slot4 | inv_slot5 | inv_slot6]"
|
||||
"[*%(100,300)log_view]"
|
||||
"[_]"
|
||||
"[_]");
|
||||
|
||||
size_t inv_id = 0;
|
||||
for(auto [name, entity] : $gui.$name_ents) {
|
||||
if(name.starts_with("inv_")) {
|
||||
$slots[name] = inv_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StatusUI::init() {
|
||||
$gui.set<Background>($gui.MAIN, {$gui.$parser});
|
||||
|
||||
for(auto& [name, cell] : $gui.cells()) {
|
||||
if(name == "log_view") {
|
||||
$log_to = $gui.entity("log_view");
|
||||
$gui.set<Rectangle>($log_to, {});
|
||||
$gui.set<Textual>($log_to, {L"Welcome to the Game!", 20});
|
||||
} else {
|
||||
auto button = $gui.entity(name);
|
||||
$gui.set<Rectangle>(button, {});
|
||||
$gui.set<Textual>(button, {L""});
|
||||
$gui.set<ActionData>(button, {make_any<string>(name)});
|
||||
|
||||
if(name == "ritual_ui") {
|
||||
$gui.set<Clickable>(button, {
|
||||
[this](auto, auto){ select_ritual(); }
|
||||
});
|
||||
$gui.set<Sound>(button, {"pickup"});
|
||||
} else {
|
||||
$gui.set<Clickable>(button, {
|
||||
[this](auto ent, auto data){ select_slot(ent, data); }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ritual_ui.event(ritual::Event::STARTED);
|
||||
$gui.init();
|
||||
}
|
||||
|
||||
bool StatusUI::mouse(float x, float y, bool hover) {
|
||||
if($ritual_ui.is_open()) {
|
||||
return $ritual_ui.mouse(x, y, hover);
|
||||
} else {
|
||||
return $gui.mouse(x, y, hover);
|
||||
}
|
||||
}
|
||||
|
||||
void StatusUI::select_ritual() {
|
||||
$ritual_ui.event(ritual::Event::TOGGLE);
|
||||
}
|
||||
|
||||
void StatusUI::select_slot(DinkyECS::Entity ent, any slot_name) {
|
||||
dbc::check(slot_name.has_value(), "passed select_slot an any without a value");
|
||||
|
||||
auto cn = $gui.get<CellName>(ent);
|
||||
auto world = $level.world;
|
||||
|
||||
if(world->has<components::Inventory>($level.player)) {
|
||||
auto& inventory = world->get<components::Inventory>($level.player);
|
||||
size_t inv_id = $slots[any_cast<string>(slot_name)];
|
||||
|
||||
if(inventory.has_item(inv_id)) {
|
||||
auto [used, name] = inventory.use($level, inv_id);
|
||||
|
||||
if(used) {
|
||||
// log(fmt::format(L"Used item: {}", name));
|
||||
log(fmt::format(L"Used item: {}", L"FIX ME ZED"));
|
||||
} else {
|
||||
// log(fmt::format(L"You are out of {}.", name));
|
||||
log(fmt::format(L"Used item: {}", L"FIX ME ZED"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* WARNING: This is really not the greatest way to do this. */
|
||||
void StatusUI::update() {
|
||||
if($gui.has<Textual>($log_to)) {
|
||||
auto& text = $gui.get<Textual>($log_to);
|
||||
//BUG: I'm calling this what it is, fix it
|
||||
wstring log_garbage;
|
||||
for(auto msg : $messages) {
|
||||
log_garbage += msg + L"\n";
|
||||
}
|
||||
text.update(log_garbage);
|
||||
}
|
||||
|
||||
auto world = $level.world;
|
||||
if(world->has<components::Inventory>($level.player)) {
|
||||
auto& inventory = world->get<components::Inventory>($level.player);
|
||||
|
||||
for(auto& [slot_name, inv_id] : $slots) {
|
||||
if(inventory.has_item(inv_id)) {
|
||||
auto slot = $gui.entity(slot_name);
|
||||
auto& item = inventory.get(inv_id);
|
||||
auto comp_sprite = components::get<components::Sprite>(item.data);
|
||||
$gui.set_init<guecs::Sprite>(slot, {comp_sprite.name});
|
||||
string count_label = fmt::format("{}", item.count);
|
||||
auto& label = $gui.get<Textual>(slot);
|
||||
label.text->setString(count_label);
|
||||
|
||||
auto& sprite = $gui.get<guecs::Sprite>(slot);
|
||||
|
||||
if(item.count == 0) {
|
||||
sprite.sprite->setColor({125, 125, 125});
|
||||
} else {
|
||||
sprite.sprite->setColor({255, 255, 255});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StatusUI::render(sf::RenderWindow &window) {
|
||||
$gui.render(window);
|
||||
$ritual_ui.render(window);
|
||||
}
|
||||
|
||||
void StatusUI::log(wstring msg) {
|
||||
$messages.push_front(msg);
|
||||
if($messages.size() > MAX_LOG_MESSAGES) {
|
||||
$messages.pop_back();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void StatusUI::update_level(GameLevel &level) {
|
||||
$level = level;
|
||||
init();
|
||||
}
|
||||
}
|
29
gui/status_ui.hpp
Normal file
29
gui/status_ui.hpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
#include "levelmanager.hpp"
|
||||
#include "constants.hpp"
|
||||
#include <deque>
|
||||
#include "textures.hpp"
|
||||
#include <guecs/ui.hpp>
|
||||
#include "gui/ritual_ui.hpp"
|
||||
|
||||
namespace gui {
|
||||
class StatusUI {
|
||||
public:
|
||||
guecs::UI $gui;
|
||||
DinkyECS::Entity $log_to;
|
||||
std::map<std::string, size_t> $slots;
|
||||
std::deque<std::wstring> $messages;
|
||||
GameLevel $level;
|
||||
ritual::UI $ritual_ui;
|
||||
|
||||
StatusUI(GameLevel level);
|
||||
void select_slot(DinkyECS::Entity ent, std::any data);
|
||||
void select_ritual();
|
||||
void update_level(GameLevel &level);
|
||||
bool mouse(float x, float y, bool hover);
|
||||
void log(std::wstring msg);
|
||||
void init();
|
||||
void render(sf::RenderWindow &window);
|
||||
void update();
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue