diff --git a/src/game-loop/CMakeLists.txt b/src/game-loop/CMakeLists.txt index dc9e5a25..1180abea 100644 --- a/src/game-loop/CMakeLists.txt +++ b/src/game-loop/CMakeLists.txt @@ -334,6 +334,10 @@ add_library(GameLoop STATIC src/other/ParticleGenerator.cpp src/other/Inventory.cpp + src/prefabs/ui/CheatConsole.cpp + src/populator/ItemFactory.cpp + src/populator/LootFactory.cpp + src/populator/NpcFactory.cpp interface/other/PhysicsComponentType.hpp interface/other/Inventory.hpp interface/other/InventoryEvent.hpp @@ -343,8 +347,10 @@ add_library(GameLoop STATIC include/other/ParticleGenerator.hpp include/components/generic/ImguiComponent.hpp include/prefabs/ui/CheatConsole.hpp - src/prefabs/ui/CheatConsole.cpp -) + include/populator/ItemFactory.hpp + include/populator/NpcFactory.hpp + include/populator/LootFactory.hpp + src/other/NpcType.cpp src/other/ItemType.cpp include/other/CheatConsoleInterpreter.h src/other/CheatConsoleInterpreter.cpp interface/game-loop/GameLoopState.hpp src/game-loop/GameLoopState.cpp) target_include_directories(GameLoop PRIVATE include interface diff --git a/src/game-loop/include/other/CheatConsoleInterpreter.h b/src/game-loop/include/other/CheatConsoleInterpreter.h new file mode 100644 index 00000000..1a4ab344 --- /dev/null +++ b/src/game-loop/include/other/CheatConsoleInterpreter.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include + +#include "other/ItemType.hpp" +#include "other/NpcType.hpp" +#include "game-loop/GameLoopState.hpp" +#include "LootType.hpp" + +class CheatConsoleInterpreter +{ +public: + using Command = std::vector; + using CommandHandlerResult = std::pair; + using CommandHandler = std::function; + CheatConsoleInterpreter(); + + const CommandHandler& get_spawn_command_handler() const; + const CommandHandler& get_enter_command_handler() const; +private: + std::map _string_to_item_type_map; + std::map _string_to_npc_type_map; + std::map _string_to_loot_type_map; + std::map _string_to_game_loop_state_map; + + CommandHandler _spawn_command_handler; + CommandHandler _enter_command_handler; +}; diff --git a/src/game-loop/include/other/NpcType.hpp b/src/game-loop/include/other/NpcType.hpp index 8d2adec5..9d70b50e 100644 --- a/src/game-loop/include/other/NpcType.hpp +++ b/src/game-loop/include/other/NpcType.hpp @@ -1,8 +1,13 @@ #pragma once -enum class NpcType +#include +#include + +using NpcType_t = std::uint16_t; + +enum class NpcType : NpcType_t { - NONE, + NONE = 0, SNAKE, BAT, CAVEMAN, @@ -11,5 +16,8 @@ enum class NpcType SHOPKEEPER, DAMSEL, BLUE_FROG, - RED_FROG + RED_FROG, + _SIZE }; + +const char* to_string(NpcType npc_type); \ No newline at end of file diff --git a/src/game-loop/include/populator/ItemFactory.hpp b/src/game-loop/include/populator/ItemFactory.hpp new file mode 100644 index 00000000..5d29ba1d --- /dev/null +++ b/src/game-loop/include/populator/ItemFactory.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "other/ItemType.hpp" +#include + +class ItemFactory { +public: + static entt::entity make(ItemType); + static entt::entity make(ItemType, float pos_x, float pos_y); +}; diff --git a/src/game-loop/include/populator/LootFactory.hpp b/src/game-loop/include/populator/LootFactory.hpp new file mode 100644 index 00000000..eea0b319 --- /dev/null +++ b/src/game-loop/include/populator/LootFactory.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include +#include "LootType.hpp" + +class LootFactory { +public: + static entt::entity make(LootType); + static entt::entity make(LootType, float pos_x, float pos_y); +}; diff --git a/src/game-loop/include/populator/NpcFactory.hpp b/src/game-loop/include/populator/NpcFactory.hpp new file mode 100644 index 00000000..1188e660 --- /dev/null +++ b/src/game-loop/include/populator/NpcFactory.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "other/NpcType.hpp" +#include + +class NpcFactory { +public: + static entt::entity make(NpcType); + static entt::entity make(NpcType, float pos_x, float pos_y); +}; diff --git a/src/game-loop/include/prefabs/ui/CheatConsole.hpp b/src/game-loop/include/prefabs/ui/CheatConsole.hpp index c85f92b1..141d30a2 100644 --- a/src/game-loop/include/prefabs/ui/CheatConsole.hpp +++ b/src/game-loop/include/prefabs/ui/CheatConsole.hpp @@ -4,17 +4,20 @@ #include "viewport/Viewport.hpp" #include "game-loop/GameLoop.hpp" +#include +#include + namespace prefabs { class CheatConsoleComponent { public: bool is_state_change_requested() const { return _state_change_requested; } - void request_state_change(GameLoop::State requested_state) { _requested_state = requested_state; _state_change_requested = true; } - GameLoop::State get_requested_state() const { return _requested_state;} + void request_state_change(GameLoopState requested_state) { _requested_state = requested_state; _state_change_requested = true; } + GameLoopState get_requested_state() const { return _requested_state;} private: bool _state_change_requested = false; - GameLoop::State _requested_state{GameLoop::State::CURRENT}; + GameLoopState _requested_state{GameLoopState::CURRENT}; }; struct CheatConsole diff --git a/src/game-loop/interface/game-loop/GameLoop.hpp b/src/game-loop/interface/game-loop/GameLoop.hpp index d5a94f68..da1a3970 100644 --- a/src/game-loop/interface/game-loop/GameLoop.hpp +++ b/src/game-loop/interface/game-loop/GameLoop.hpp @@ -14,6 +14,7 @@ #include "game-loop/GameLoopStartedState.hpp" #include "game-loop/GameLoopScoresState.hpp" #include "game-loop/GameLoopSandboxState.hpp" +#include "game-loop/GameLoopState.hpp" #include @@ -35,20 +36,9 @@ class ShoppingSystem; class GameLoop { public: - enum class State - { - MAIN_MENU = 0, - PLAYING, - STARTED, - LEVEL_SUMMARY, - SCORES, - SANDBOX, - CURRENT - }; - GameLoop(const std::shared_ptr&); std::function& get(); - GameLoopBaseState* get_game_loop_state_ptr(State); + GameLoopBaseState* get_game_loop_state_ptr(GameLoopState); private: diff --git a/src/game-loop/interface/game-loop/GameLoopBaseState.hpp b/src/game-loop/interface/game-loop/GameLoopBaseState.hpp index 9381b681..ed3bf66d 100644 --- a/src/game-loop/interface/game-loop/GameLoopBaseState.hpp +++ b/src/game-loop/interface/game-loop/GameLoopBaseState.hpp @@ -4,6 +4,7 @@ class GameLoop; +// TODO: Rename to IGameLoopState to not confuse with GameLoopState enum class GameLoopBaseState { public: diff --git a/src/game-loop/interface/game-loop/GameLoopState.hpp b/src/game-loop/interface/game-loop/GameLoopState.hpp new file mode 100644 index 00000000..d9794a5e --- /dev/null +++ b/src/game-loop/interface/game-loop/GameLoopState.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +using GameLoopState_t = std::uint16_t; +enum class GameLoopState : GameLoopState_t +{ + MAIN_MENU = 0, + PLAYING, + STARTED, + LEVEL_SUMMARY, + SCORES, + SANDBOX, + CURRENT, + _SIZE +}; + +const char* to_string(GameLoopState); \ No newline at end of file diff --git a/src/game-loop/interface/other/ItemType.hpp b/src/game-loop/interface/other/ItemType.hpp index 9586ba69..2d7c0e42 100644 --- a/src/game-loop/interface/other/ItemType.hpp +++ b/src/game-loop/interface/other/ItemType.hpp @@ -1,8 +1,12 @@ #pragma once -enum class ItemType +#include +#include + +using ItemType_t = std::uint16_t; +enum class ItemType : ItemType_t { - ARROW, + ARROW = 0, BOMB, CAPE, CHEST, @@ -30,3 +34,5 @@ enum class ItemType FLARE, _SIZE }; + +const char* to_string(ItemType item_type); \ No newline at end of file diff --git a/src/game-loop/src/game-loop/GameLoop.cpp b/src/game-loop/src/game-loop/GameLoop.cpp index 2ae4cc49..2e9d10d9 100644 --- a/src/game-loop/src/game-loop/GameLoop.cpp +++ b/src/game-loop/src/game-loop/GameLoop.cpp @@ -58,21 +58,21 @@ GameLoop::GameLoop(const std::shared_ptr& viewport) }; } -GameLoopBaseState *GameLoop::get_game_loop_state_ptr(GameLoop::State state) { +GameLoopBaseState *GameLoop::get_game_loop_state_ptr(GameLoopState state) { switch (state) { - case State::MAIN_MENU: + case GameLoopState::MAIN_MENU: return &_states.main_menu; - case State::PLAYING: + case GameLoopState::PLAYING: return &_states.playing; - case State::STARTED: + case GameLoopState::STARTED: return &_states.started; - case State::LEVEL_SUMMARY: + case GameLoopState::LEVEL_SUMMARY: return &_states.level_summary; - case State::SCORES: + case GameLoopState::SCORES: return &_states.scores; - case State::SANDBOX: + case GameLoopState::SANDBOX: return &_states.sandbox; - case State::CURRENT: + case GameLoopState::CURRENT: return _states.current; default: assert(false); } diff --git a/src/game-loop/src/game-loop/GameLoopState.cpp b/src/game-loop/src/game-loop/GameLoopState.cpp new file mode 100644 index 00000000..b9b06268 --- /dev/null +++ b/src/game-loop/src/game-loop/GameLoopState.cpp @@ -0,0 +1,18 @@ +#include "game-loop/GameLoopState.hpp" +#include + +const char *to_string(GameLoopState game_loop_state) { +#define TO_STRING(x) case GameLoopState::x: return #x; + switch (game_loop_state) { + TO_STRING(MAIN_MENU); + TO_STRING(PLAYING); + TO_STRING(STARTED); + TO_STRING(LEVEL_SUMMARY); + TO_STRING(SCORES); + TO_STRING(SANDBOX); + TO_STRING(CURRENT); + TO_STRING(_SIZE); + } + assert(false); + return "Failed to match passed GameLoopState"; +} \ No newline at end of file diff --git a/src/game-loop/src/other/CheatConsoleInterpreter.cpp b/src/game-loop/src/other/CheatConsoleInterpreter.cpp new file mode 100644 index 00000000..fee2887e --- /dev/null +++ b/src/game-loop/src/other/CheatConsoleInterpreter.cpp @@ -0,0 +1,115 @@ +#include "other/CheatConsoleInterpreter.h" +#include "game-loop/GameLoop.hpp" +#include "prefabs/ui/CheatConsole.hpp" +#include "patterns/Singleton.hpp" +#include "components/generic/PositionComponent.hpp" +#include "populator/NpcFactory.hpp" +#include "populator/ItemFactory.hpp" +#include "populator/LootFactory.hpp" +#include "EntityRegistry.hpp" +#include "components/specialized/MainDudeComponent.hpp" + +template +std::map populate_string_to_enum_map() +{ + std::map out; + Enumerator_t enumerator_index = 0; + while (enumerator_index < static_cast(Enumerator::_SIZE)) { + const auto enumerator = static_cast(enumerator_index); + out.emplace(to_string(enumerator), enumerator); + enumerator_index++; + } + return out; +} + +CheatConsoleInterpreter::CheatConsoleInterpreter() +{ + _string_to_item_type_map = populate_string_to_enum_map(); + _string_to_npc_type_map = populate_string_to_enum_map(); + _string_to_loot_type_map = populate_string_to_enum_map(); + _string_to_game_loop_state_map = populate_string_to_enum_map(); + + _spawn_command_handler = CommandHandler([&](const Command& command){ + if (command.size() != 2 && (command.at(0) == "HELP" || command.at(0) == "SPAWN")) { + return std::make_pair(false, "spawn "); + } + + if (command.at(0) != "SPAWN") { + return std::make_pair(false, ""); + } + + const auto& type = command.at(1); + const auto npc_type_match = _string_to_npc_type_map.find(type); + const auto item_type_match = _string_to_item_type_map.find(type); + const auto loot_type_match = _string_to_loot_type_map.find(type); + + auto& registry = EntityRegistry::instance().get_registry(); + auto dudes = registry.view(); + assert(dudes.size() == 1); + auto dude = dudes.front(); + auto &dude_position = registry.get(dude); + + const float offset_x = -2; + const float offset_y = -2; + + if (npc_type_match != _string_to_npc_type_map.end()) + { + const NpcType npc_type = npc_type_match->second; + NpcFactory::make(npc_type, dude_position.x_center + offset_x, dude_position.y_center + offset_y); + return std::make_pair(true, "spawning"); + } + + if (item_type_match != _string_to_item_type_map.end()) + { + const ItemType item_type = item_type_match->second; + ItemFactory::make(item_type, dude_position.x_center + offset_x, dude_position.y_center + offset_y); + return std::make_pair(true, "spawning"); + } + + if (loot_type_match != _string_to_loot_type_map.end()) + { + const LootType loot_type = loot_type_match->second; + LootFactory::make(loot_type, dude_position.x_center + offset_x, dude_position.y_center + offset_y); + return std::make_pair(true, "spawning"); + } + + return std::make_pair(true, "failed to match "); + }); + + _enter_command_handler = CommandHandler ([this](const Command& command){ + if (command.size() != 2 && (command.at(0) == "HELP" || command.at(0) == "ENTER")) { + return std::make_pair(false, "enter "); + } + + if (command.at(0) != "ENTER") { + return std::make_pair(false, ""); + } + + auto& registry = EntityRegistry::instance().get_registry(); + auto cheat_consoles = registry.view(); + assert(cheat_consoles.size() == 1); + auto cheat_console = cheat_consoles.front(); + auto& cheat_console_component = registry.get(cheat_console); + + const auto& requested_game_loop_state = command.at(1); + const auto game_loop_state_match = _string_to_game_loop_state_map.find(requested_game_loop_state); + + if (game_loop_state_match == _string_to_game_loop_state_map.end()) + { + return std::make_pair(true, "failed to match "); + } + + cheat_console_component.request_state_change(game_loop_state_match->second); + return std::make_pair(true, "entering"); + }); +} + +const CheatConsoleInterpreter::CommandHandler& CheatConsoleInterpreter::get_spawn_command_handler() const +{ + return _spawn_command_handler; +} + +const CheatConsoleInterpreter::CommandHandler& CheatConsoleInterpreter::get_enter_command_handler() const +{ + return _enter_command_handler; +} \ No newline at end of file diff --git a/src/game-loop/src/other/ItemType.cpp b/src/game-loop/src/other/ItemType.cpp new file mode 100644 index 00000000..97fdd60c --- /dev/null +++ b/src/game-loop/src/other/ItemType.cpp @@ -0,0 +1,36 @@ +#include "other/ItemType.hpp" + +const char *to_string(ItemType item_type) { +#define TO_STRING(x) case ItemType::x: return #x; + switch (item_type) { + TO_STRING(ARROW); + TO_STRING(BOMB); + TO_STRING(CAPE); + TO_STRING(CHEST); + TO_STRING(CRATE); + TO_STRING(JAR); + TO_STRING(JETPACK); + TO_STRING(PISTOL); + TO_STRING(ROCK); + TO_STRING(ROPE); + TO_STRING(SHOTGUN); + TO_STRING(SKULL); + TO_STRING(WHIP); + TO_STRING(BOMB_SPAWNER); + TO_STRING(ROPE_SPAWNER); + TO_STRING(WALLET); + TO_STRING(SPIKE_SHOES); + TO_STRING(SPRING_SHOES); + TO_STRING(MITT); + TO_STRING(GLOVE); + TO_STRING(COMPASS); + TO_STRING(BODY); + TO_STRING(BOMB_BAG); + TO_STRING(ROPE_PILE); + TO_STRING(GOLDEN_IDOL); + TO_STRING(FLARE); + TO_STRING(_SIZE); + } + assert(false); + return "Failed to match passed ItemType"; +} diff --git a/src/game-loop/src/other/NpcType.cpp b/src/game-loop/src/other/NpcType.cpp new file mode 100644 index 00000000..cf30f2b1 --- /dev/null +++ b/src/game-loop/src/other/NpcType.cpp @@ -0,0 +1,19 @@ +#include "other/NpcType.hpp" + +const char *to_string(NpcType npc_type) { +#define TO_STRING(x) case NpcType::x: return #x; + switch (npc_type) { + TO_STRING(NONE); + TO_STRING(SNAKE); + TO_STRING(BAT); + TO_STRING(CAVEMAN); + TO_STRING(SPIDER); + TO_STRING(SKELETON); + TO_STRING(SHOPKEEPER); + TO_STRING(DAMSEL); + TO_STRING(BLUE_FROG); + TO_STRING(RED_FROG); + } + assert(false); + return "Failed to match passed NpcType"; +} diff --git a/src/game-loop/src/populator/ItemFactory.cpp b/src/game-loop/src/populator/ItemFactory.cpp new file mode 100644 index 00000000..967e7542 --- /dev/null +++ b/src/game-loop/src/populator/ItemFactory.cpp @@ -0,0 +1,64 @@ +#include "populator/ItemFactory.hpp" +#include "EntityRegistry.hpp" +#include "prefabs/items/Arrow.hpp" +#include "components/generic/PositionComponent.hpp" +#include "prefabs/items/Bomb.hpp" +#include "prefabs/items/Cape.hpp" +#include "prefabs/items/Chest.hpp" +#include "prefabs/items/Crate.hpp" +#include "prefabs/items/Jar.hpp" +#include "prefabs/items/Jetpack.hpp" +#include "prefabs/items/Pistol.hpp" +#include "prefabs/items/Rock.hpp" +#include "prefabs/items/Rope.hpp" +#include "prefabs/items/Shotgun.hpp" +#include "prefabs/items/Skull.hpp" +#include "prefabs/items/Whip.hpp" +#include "prefabs/items/SpikeShoes.hpp" +#include "prefabs/items/SpringShoes.hpp" +#include "prefabs/items/Mitt.hpp" +#include "prefabs/items/Glove.hpp" +#include "prefabs/items/Compass.hpp" +#include "prefabs/items/BombBag.hpp" +#include "prefabs/items/RopePile.hpp" +#include "prefabs/items/GoldenIdol.hpp" +#include "prefabs/items/Flare.hpp" + +entt::entity ItemFactory::make(ItemType item_type) { + switch (item_type) + { + case ItemType::ARROW: return prefabs::Arrow::create(); + case ItemType::BOMB: return prefabs::Bomb::create(); + case ItemType::CAPE: return prefabs::Cape::create(); + case ItemType::CHEST: return prefabs::Chest::create(); + case ItemType::CRATE: return prefabs::Crate::create(); + case ItemType::JAR: return prefabs::Jar::create(); + case ItemType::JETPACK: return prefabs::Jetpack::create(); + case ItemType::PISTOL: return prefabs::Pistol::create(); + case ItemType::ROCK: return prefabs::Rock::create(); + case ItemType::ROPE: return prefabs::Rope::create(); + case ItemType::SHOTGUN: return prefabs::Shotgun::create(); + case ItemType::SKULL: return prefabs::Skull::create(); + case ItemType::WHIP: return prefabs::Whip::create(); + case ItemType::SPIKE_SHOES: return prefabs::SpikeShoes::create(); + case ItemType::SPRING_SHOES: return prefabs::SpringShoes::create(); + case ItemType::MITT: return prefabs::Mitt::create(); + case ItemType::GLOVE: return prefabs::Glove::create(); + case ItemType::COMPASS: return prefabs::Compass::create(); + case ItemType::BOMB_BAG: return prefabs::BombBag::create(); + case ItemType::ROPE_PILE: return prefabs::RopePile::create(); + case ItemType::GOLDEN_IDOL: return prefabs::GoldenIdol::create(); + case ItemType::FLARE: return prefabs::Flare::create(); + } + assert(false); + return {}; +} + +entt::entity ItemFactory::make(ItemType item_type, float pos_x, float pos_y) { + const auto out_entity = make(item_type); + auto& registry = EntityRegistry::instance().get_registry(); + auto& position = registry.get(out_entity); + position.x_center = pos_x; + position.y_center = pos_y; + return out_entity; +} \ No newline at end of file diff --git a/src/game-loop/src/populator/LootFactory.cpp b/src/game-loop/src/populator/LootFactory.cpp new file mode 100644 index 00000000..fb7b7449 --- /dev/null +++ b/src/game-loop/src/populator/LootFactory.cpp @@ -0,0 +1,24 @@ +#include "populator/LootFactory.hpp" +#include "EntityRegistry.hpp" +#include "components/generic/PositionComponent.hpp" + +entt::entity LootFactory::make(LootType loot_type) { + switch (loot_type) + { + case LootType::NOTHING:break; + case LootType::ANY:break; + case LootType::SHOP_ITEM:break; + case LootType::GOLDEN_IDOL:break; + } + assert(false); + return {}; +} + +entt::entity LootFactory::make(LootType loot_type, float pos_x, float pos_y) { + const auto out_entity = make(loot_type); + auto& registry = EntityRegistry::instance().get_registry(); + auto& position = registry.get(out_entity); + position.x_center = pos_x; + position.y_center = pos_y; + return out_entity; +} \ No newline at end of file diff --git a/src/game-loop/src/populator/NpcFactory.cpp b/src/game-loop/src/populator/NpcFactory.cpp new file mode 100644 index 00000000..4335d333 --- /dev/null +++ b/src/game-loop/src/populator/NpcFactory.cpp @@ -0,0 +1,37 @@ +#include "populator/NpcFactory.hpp" +#include "EntityRegistry.hpp" +#include "components/generic/PositionComponent.hpp" +#include "prefabs/npc/Snake.hpp" +#include "prefabs/npc/Bat.hpp" +#include "prefabs/npc/Caveman.hpp" +#include "prefabs/npc/Spider.hpp" +#include "prefabs/npc/Skeleton.hpp" +#include "prefabs/npc/Shopkeeper.hpp" +#include "prefabs/npc/Damsel.hpp" +#include "prefabs/npc/BlueFrog.hpp" +#include "prefabs/npc/RedFrog.hpp" + +entt::entity NpcFactory::make(NpcType npc_type) { + switch (npc_type) + { + case NpcType::SNAKE: return prefabs::Snake::create(); + case NpcType::BAT: return prefabs::Bat::create(); + case NpcType::CAVEMAN: return prefabs::Caveman::create(); + case NpcType::SPIDER: return prefabs::Spider::create(); + case NpcType::SKELETON: return prefabs::Skeleton::create(); + case NpcType::SHOPKEEPER: return prefabs::Shopkeeper::create(); + case NpcType::BLUE_FROG: return prefabs::BlueFrog::create(); + case NpcType::RED_FROG: return prefabs::RedFrog::create(); + } + assert(false); + return {}; +} + +entt::entity NpcFactory::make(NpcType npc_type, float pos_x, float pos_y) { + const auto out_entity = make(npc_type); + auto& registry = EntityRegistry::instance().get_registry(); + auto& position = registry.get(out_entity); + position.x_center = pos_x; + position.y_center = pos_y; + return out_entity; +} \ No newline at end of file diff --git a/src/game-loop/src/populator/Populator.cpp b/src/game-loop/src/populator/Populator.cpp index 9a663718..70842cb1 100644 --- a/src/game-loop/src/populator/Populator.cpp +++ b/src/game-loop/src/populator/Populator.cpp @@ -59,6 +59,8 @@ void Populator::generate_inventory_items(entt::entity main_dude) { entt::entity item = entt::null; + // TODO: ItemFactory, NpcFactory, LootFactory that takes an enum + switch (item_type) { case ItemType::ARROW: item = prefabs::Arrow::create(); break; diff --git a/src/game-loop/src/prefabs/ui/CheatConsole.cpp b/src/game-loop/src/prefabs/ui/CheatConsole.cpp index 70104d8e..b7bb61e9 100644 --- a/src/game-loop/src/prefabs/ui/CheatConsole.cpp +++ b/src/game-loop/src/prefabs/ui/CheatConsole.cpp @@ -4,17 +4,31 @@ #include "components/generic/ImguiComponent.hpp" #include "logger/log.h" #include "Input.hpp" -#include "prefabs/npc/RedFrog.hpp" #include "components/specialized/MainDudeComponent.hpp" -#include "game-loop/GameLoop.hpp" +#include "other/CheatConsoleInterpreter.h" +#include // TODO: Better way to handle this than if-defing as there will be more imgui-components #if defined(SPELUNKY_PSP_WITH_IMGUI) #include "imgui_impl_opengl2.h" -#include "imgui_impl_sdl2.h" +#include "spritesheet-frames/CaveLevelSpritesheetFrames.hpp" namespace { - // Based on ImGui's example console: + std::vector split_by_space(const std::string& line) + { + std::stringstream ss_line(line); + std::vector seglist; + std::string segment; + + while(std::getline(ss_line, segment, ' ')) + { + seglist.push_back(segment); + } + + return seglist; + } + + // Based on ImGui's example console static int Stricmp(const char *s1, const char *s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { @@ -38,22 +52,17 @@ namespace { *str_end = 0; } - using Command = std::string; - using CommandHandlerResult = std::pair; - using CommandHandler = std::function; - struct ImGuiConsole { char InputBuf[256]; ImVector Items; ImVector Commands; ImVector History; - ImGuiTextFilter Filter; bool AutoScroll; bool ScrollToBottom; - std::vector _command_handlers; + std::vector _command_handlers; - void add_command_handler(const CommandHandler& command_handler) { + void add_command_handler(const CheatConsoleInterpreter::CommandHandler& command_handler) { _command_handlers.push_back(command_handler); } @@ -100,8 +109,7 @@ namespace { } if (ImGui::BeginPopupContextItem()) { - if (ImGui::MenuItem("Close Console")) - *p_open = false; + if (ImGui::MenuItem("Close Console")) *p_open = false; ImGui::EndPopup(); } @@ -118,9 +126,6 @@ namespace { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing for (const char *item: Items) { - if (!Filter.PassFilter(item)) - continue; - // Normally you would store more information in your item than just a string. // (e.g. make Items[] an array of structure, store color/type etc.) ImVec4 color; @@ -144,7 +149,6 @@ namespace { if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) ImGui::SetScrollHereY(1.0f); ScrollToBottom = false; - ImGui::PopStyleVar(); } ImGui::EndChild(); @@ -166,10 +170,48 @@ namespace { // Auto-focus on window apparition ImGui::SetItemDefaultFocus(); - if (reclaim_focus) + if (reclaim_focus) { ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget + } ImGui::End(); + + // TODO: Move this section out to a separate window, added this just for testing + + ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); + ImGui::Begin("Tiles", p_open); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.25f, 0.25f, 0.25f, 0.25f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.5f, 0.5f, 0.5f, 0.5f)); + + std::size_t tex_index = 0; + std::size_t last_tex_index = static_cast(CaveLevelSpritesheetFrames::_SIZE); + + while (tex_index < last_tex_index) { + TextureID tiles_texture = TextureBank::instance().get_texture(TextureType::CAVE_LEVEL_TILES); + auto door_texture = TextureBank::instance().get_region(TextureType::CAVE_LEVEL_TILES, tex_index); + ImGui::SameLine(); + + ImGui::ImageButton( + reinterpret_cast(tiles_texture), + ImVec2((float) door_texture.width * 4, (float) door_texture.height * 4), + ImVec2(door_texture.uv_normalized[0][0], door_texture.uv_normalized[0][1]), + ImVec2(door_texture.uv_normalized[2][0], door_texture.uv_normalized[2][1]), + 1 + ); + tex_index++; + + if (tex_index % 6) { + ImGui::SameLine(); + } else + { + ImGui::NewLine(); + } + } + + ImGui::PopStyleColor(3); + ImGui::End(); } void ExecCommand(const char *command_line) { @@ -186,22 +228,31 @@ namespace { } History.push_back(Strdup(command_line)); + std::string command_str(command_line); + std::string command_str_upper; + std::transform(command_str.cbegin(), command_str.cend(), std::back_inserter(command_str_upper), [](char c){ return std::toupper(c);}); + const CheatConsoleInterpreter::Command command = split_by_space(command_str_upper); + // Process command bool handled = false; + bool any_logs = false; for (auto& handler : _command_handlers) { - const auto result = handler(command_line); + const auto result = handler(command); + if (!result.second.empty()) + { + AddLog(result.second.c_str()); + any_logs = true; + } if (result.first) { handled = true; - AddLog(result.second.c_str()); break; } } - if (handled) { - // ... - } - else if (Stricmp(command_line, "CLEAR") == 0) { + if (handled || any_logs) { + // Do nothing + } else if (Stricmp(command_line, "CLEAR") == 0) { ClearLog(); } else if (Stricmp(command_line, "HELP") == 0) { AddLog("Commands:"); @@ -224,63 +275,13 @@ namespace { class CheatConsoleScript final : public ScriptBase { public: explicit CheatConsoleScript(entt::entity self) : _self(self) { - // TODO: Helper for splitting into tokens - _imgui_console.add_command_handler([](const Command& command){ - Command upper_cased; - std::transform(command.cbegin(), command.cend(), std::back_inserter(upper_cased), [](char c){ return std::toupper(c);}); - if (upper_cased == "EXIT") { - return std::make_pair(true, "exiting"); - } else { - return std::make_pair(false, ""); - } - }); - _imgui_console.add_command_handler([this](const Command& command){ - Command upper_cased; - std::transform(command.cbegin(), command.cend(), std::back_inserter(upper_cased), [](char c){ return std::toupper(c);}); - if (upper_cased == "ENTER SCORES") { - auto& registry = EntityRegistry::instance().get_registry(); - auto& cheat_console_component = registry.get(_self); - cheat_console_component.request_state_change(GameLoop::State::SCORES); - return std::make_pair(true, "entering scores"); - } else if (upper_cased == "ENTER MAIN_MENU") { - auto& registry = EntityRegistry::instance().get_registry(); - auto& cheat_console_component = registry.get(_self); - cheat_console_component.request_state_change(GameLoop::State::MAIN_MENU); - return std::make_pair(true, "entering main_menu"); - } else if (upper_cased == "ENTER SANDBOX") { - auto& registry = EntityRegistry::instance().get_registry(); - auto& cheat_console_component = registry.get(_self); - cheat_console_component.request_state_change(GameLoop::State::SANDBOX); - return std::make_pair(true, "entering sanbox"); - } else if (upper_cased == "ENTER PLAYING") { - auto& registry = EntityRegistry::instance().get_registry(); - auto& cheat_console_component = registry.get(_self); - cheat_console_component.request_state_change(GameLoop::State::PLAYING); - return std::make_pair(true, "entering playing"); - } else { - return std::make_pair(false, ""); - } - }); - _imgui_console.add_command_handler([](const Command& command){ - Command upper_cased; - std::transform(command.cbegin(), command.cend(), std::back_inserter(upper_cased), [](char c){ return std::toupper(c);}); - if (upper_cased == "SPAWN REDFROG") { - - auto& registry = EntityRegistry::instance().get_registry(); - auto dudes = registry.view(); - assert(dudes.size() == 1); - auto dude = dudes.front(); - auto &dude_position = registry.get(dude); - - const float pos_x = dude_position.x_center - 2; - const float pos_y = dude_position.y_center - 2; - prefabs::RedFrog::create(pos_x, pos_y); - - return std::make_pair(true, "spawning"); - } else { - return std::make_pair(false, ""); - } - }); + _imgui_console.add_command_handler(_cheat_console_interpreter.get_enter_command_handler()); + _imgui_console.add_command_handler(_cheat_console_interpreter.get_spawn_command_handler()); + _dont_render_callback = [](){}; + _render_console_callback = [this](){ + bool dummy = false; + _imgui_console.Draw("Cheat console", &dummy); + }; } void update(entt::entity owner, uint32_t delta_time_ms) override { @@ -290,26 +291,20 @@ namespace { _visible = !_visible; auto &imgui_component = registry.get(_self); if (_visible) { - imgui_component.render_callback = render_console_callback; + imgui_component.render_callback = _render_console_callback; } else { - imgui_component.render_callback = dont_render_callback; + imgui_component.render_callback = _dont_render_callback; } } } private: - // Returns commands, i.e - // i.e - // To be interpreted later - entt::entity _self; ImGuiConsole _imgui_console; bool _visible = false; - const std::function render_console_callback = [this](){ - bool dummy = false; - _imgui_console.Draw("Cheat console", &dummy); - }; - const std::function dont_render_callback = [](){}; + std::function _render_console_callback; + std::function _dont_render_callback; + CheatConsoleInterpreter _cheat_console_interpreter; }; } #else diff --git a/src/level/CMakeLists.txt b/src/level/CMakeLists.txt index bf505a18..7707b3d9 100644 --- a/src/level/CMakeLists.txt +++ b/src/level/CMakeLists.txt @@ -21,7 +21,7 @@ add_library(Level STATIC include/ShopRooms.hpp include/SplashScreenRooms.hpp interface/NPCType.hpp - ) + src/LootType.cpp) target_include_directories(Level PRIVATE include interface diff --git a/src/level/interface/LootType.hpp b/src/level/interface/LootType.hpp index 2a399b07..52ef5741 100644 --- a/src/level/interface/LootType.hpp +++ b/src/level/interface/LootType.hpp @@ -2,10 +2,14 @@ #include -enum class LootType : std::uint16_t +using LootType_t = std::uint16_t; +enum class LootType : LootType_t // FIXME { NOTHING = 0, ANY = 1, SHOP_ITEM = 2, - GOLDEN_IDOL = 3 + GOLDEN_IDOL = 3, + _SIZE = 4 }; + +const char* to_string(LootType); \ No newline at end of file diff --git a/src/level/src/LootType.cpp b/src/level/src/LootType.cpp new file mode 100644 index 00000000..950a3d7b --- /dev/null +++ b/src/level/src/LootType.cpp @@ -0,0 +1,15 @@ +#include "LootType.hpp" +#include + +const char *to_string(LootType loot_type) { +#define TO_STRING(x) case LootType::x: return #x; + switch (loot_type) { + TO_STRING(NOTHING); + TO_STRING(ANY); + TO_STRING(SHOP_ITEM); + TO_STRING(GOLDEN_IDOL); + TO_STRING(_SIZE); + } + assert(false); + return "Failed to match passed LootType"; +} diff --git a/src/texture-bank/CMakeLists.txt b/src/texture-bank/CMakeLists.txt index dc3846ba..6c2edb5c 100644 --- a/src/texture-bank/CMakeLists.txt +++ b/src/texture-bank/CMakeLists.txt @@ -13,7 +13,7 @@ add_library(TextureBank STATIC interface/spritesheet-frames/MainDudeSpritesheetFrames.hpp interface/spritesheet-frames/FontSpritesheetFrames.hpp interface/spritesheet-frames/NPCSpritesheetFrames.hpp - ) + interface/spritesheet-frames/CaveLevelSpritesheetFrames.hpp) target_include_directories(TextureBank PRIVATE include interface diff --git a/src/texture-bank/interface/spritesheet-frames/CaveLevelSpritesheetFrames.hpp b/src/texture-bank/interface/spritesheet-frames/CaveLevelSpritesheetFrames.hpp new file mode 100644 index 00000000..817f785d --- /dev/null +++ b/src/texture-bank/interface/spritesheet-frames/CaveLevelSpritesheetFrames.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include + +enum class CaveLevelSpritesheetFrames : std::uint32_t { + NOTHING = 0, // 0 NON_COLLIDABLE + CAVE_ROCK, // 1 + CAVE_REGULAR, // 2 + STONE_BLOCK, // 3 + CAVE_DOWN_ORIENTED, // 4 + CAVE_SOME_GOLD, // 5 + CAVE_MUCH_GOLD, // 6 + CAVE_UP_ORIENTED, // 7 + CAVE_UP_DOWN_ORIENTED, // 8 + LADDER, // 9 NON_COLLIDABLE + LADDER_DECK, // 10 NON_COLLIDABLE + ARROW_TRAP_LEFT, // 11 + ARROW_TRAP_RIGHT, // 12 + ENTRANCE, // 13 NON_COLLIDABLE + EXIT, // 14 NON_COLLIDABLE + CONSOLE_LEFT_BAR_TOP_ROUNDED, // 15 + CONSOLE_RIGHT_BAR_TOP_ROUNDED, // 16 + CONSOLE_LEFT_BAR_BOT_ROUNDED, // 17 + CONSOLE_RIGHT_BAR_BOT_ROUNDED, // 18 + CONSOLE_TOP_BAR, // 19 + CONSOLE_BOTTOM_BAR, // 20 + CONSOLE_LEFT_BAR, // 21 + CONSOLE_RIGHT_BAR, // 22 + CONSOLE_BLACK_BACKGROUND, // 23 + CAVE_SMOOTH, // 24 + SCORES_STAR_DOOR, // 25 + SCORES_SUN_DOOR, // 26 + SCORES_MOON_DOOR, // 27 + SCORES_CHANGING_DOOR, // 28 + SHOP_SIGN_RARE, // 29 + SHOP_SIGN_WEAPON, // 30 + SHOP_SIGN_BOMBS, // 31 + SHOP_SIGN_CLOTHING, // 32 + SHOP_SIGN_CRAPS, // 33 + SHOP_SIGN_GENERAL, // 34 + SHOP_SIGN_KISSING, // 35 + NA, // 36 + SHOP_MUGSHOT_1, // 37 + SHOP_MUGSHOT_2, // 38 + SHOP_MUGSHOT_3, // 39 + SHOP_MUGSHOT_4, // 40 + ALTAR_LEFT, // 41 + ALTAR_RIGHT, // 42 + CAVE_BG_1, // 43 + CAVE_BG_2, // 44 + CAVE_BG_3, // 45 + CAVE_BG_4, // 46 + _SIZE // 47 Total elements +};