diff --git a/combat.cpp b/combat.cpp new file mode 100644 index 0000000..6333a1a --- /dev/null +++ b/combat.cpp @@ -0,0 +1,14 @@ +#include "combat.hpp" +#include "rand.hpp" + +int Combat::fight(Combat &target) { + int attack = Random::uniform(0,1); + int my_dmg = 0; + + if(attack) { + my_dmg = Random::uniform(1, damage); + target.hp -= my_dmg; + } + + return my_dmg; +} diff --git a/combat.hpp b/combat.hpp new file mode 100644 index 0000000..ef30add --- /dev/null +++ b/combat.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "components.hpp" + +struct Combat { + int hp; + int damage; + bool dead; + + int fight(Combat &target); +}; diff --git a/components.hpp b/components.hpp index 4890267..047941c 100644 --- a/components.hpp +++ b/components.hpp @@ -1,6 +1,7 @@ #pragma once #include "dinkyecs.hpp" #include "map.hpp" +#include "combat.hpp" #include namespace Components { @@ -17,11 +18,6 @@ namespace Components { int dy; }; - struct Combat { - int hp; - int damage; - }; - struct Treasure { int amount; }; diff --git a/gui.cpp b/gui.cpp index f72d166..dabd33e 100644 --- a/gui.cpp +++ b/gui.cpp @@ -164,6 +164,7 @@ void GUI::run_systems() { System::enemy_pathing($world, $game_map, player); System::motion($world, $game_map); System::combat($world, player); + System::death($world); } void GUI::resize_map(int new_size) { diff --git a/map.hpp b/map.hpp index e263ae0..4815c53 100644 --- a/map.hpp +++ b/map.hpp @@ -57,6 +57,7 @@ public: int limit() { return $limit; } size_t width() { return $walls[0].size(); } size_t height() { return $walls.size(); } + int distance(Point to) { return $paths[to.y][to.x]; } Room &room(size_t at) { return $rooms[at]; } diff --git a/meson.build b/meson.build index 4ab33f3..e8f3673 100644 --- a/meson.build +++ b/meson.build @@ -32,6 +32,7 @@ roguish = executable('roguish', [ 'gui.cpp', 'rand.cpp', 'collider.cpp', + 'combat.cpp', 'systems.cpp', ], dependencies: dependencies) diff --git a/status.txt b/status.txt index a88f067..4e03869 100644 --- a/status.txt +++ b/status.txt @@ -10,7 +10,9 @@ TODO: * Write a test that generates a ton of maps then confirms there's a path from one room to every other room? * Lua integration? -* Combat system and simple loot system. +* BUG: If map is < 90 zome out crashes. + +* Simple loot system. * Actually render FTXUI ansi output instead of the gui.cpp hack. * Remove entity from world, _or_ mark them dead, switch their icon, and make them an entity the player walks over? * Bring back sounds, check out SoLoud. diff --git a/systems.cpp b/systems.cpp index f1f0871..bcc7a54 100644 --- a/systems.cpp +++ b/systems.cpp @@ -10,6 +10,8 @@ using namespace fmt; using namespace Components; +#define HEARING_DISTANCE 8 + void System::enemy_pathing(DinkyECS::World &world, Map &game_map, Player &player) { const auto &player_position = world.component(player.entity); game_map.set_target(player_position.location); @@ -17,9 +19,11 @@ void System::enemy_pathing(DinkyECS::World &world, Map &game_map, Player &player world.system([&](const auto &ent, auto &position, auto &motion) { if(ent != player.entity) { - Point out = position.location; - game_map.neighbors(out, false); - motion = { int(out.x - position.location.x), int(out.y - position.location.y)}; + Point out = position.location; // copy + if(game_map.distance(out) < HEARING_DISTANCE) { + game_map.neighbors(out, false); + motion = { int(out.x - position.location.x), int(out.y - position.location.y)}; + } } }); game_map.clear_target(player_position.location); @@ -64,6 +68,22 @@ void System::motion(DinkyECS::World &world, Map &game_map) { }); } +void System::death(DinkyECS::World &world) { + auto &collider = world.get(); + + world.system([&](const auto &ent, auto &position, auto &combat) { + // bring out yer dead + if(combat.hp <= 0 && !combat.dead) { + combat.dead = true; + // take them out of collision map + collider.remove(position.location); + + // remove their motion so they're dead + world.remove(ent); + } + }); +} + void System::combat(DinkyECS::World &world, Player &player) { auto& collider = world.get(); @@ -77,25 +97,24 @@ void System::combat(DinkyECS::World &world, Player &player) { if(found) { for(auto entity : nearby) { auto& enemy_combat = world.component(entity); - int player_dmg = Random::uniform(1, enemy_combat.damage); - enemy_combat.hp -= player_dmg; - log.log(format("YOU HIT {} damage! Enemy has {} HP left.", - player_dmg, enemy_combat.hp)); - - if(enemy_combat.hp <= 0) { - log.log("--- ENEMY DEAD!---"); - auto enemy_position = world.component(entity); - collider.remove(enemy_position.location); - world.remove(entity); + int player_dmg = player_combat.fight(enemy_combat); + + if(player_dmg > 0) { + log.log(format("You HIT for {} damage, HP left {}.", player_dmg, enemy_combat.hp)); } else { - int attack = Random::uniform(0,1); - if(attack) { - int dmg = Random::uniform(1, enemy_combat.damage); - player_combat.hp -= dmg; - log.log(format("HIT! You took {} damage.", dmg)); + log.log("You missed! They're quick!"); + } + + if(enemy_combat.hp > 0) { + int enemy_dmg = enemy_combat.fight(player_combat); + + if(enemy_dmg > 0) { + log.log(format("Enemy HIT YOU for {} damage.", enemy_dmg)); } else { - log.log("You dodged! Run!"); + log.log("Enemy MISSED, you dodged it."); } + } else { + log.log("ENEMY DEAD! YOU WIN!"); } } } diff --git a/systems.hpp b/systems.hpp index e572523..732fe29 100644 --- a/systems.hpp +++ b/systems.hpp @@ -9,6 +9,7 @@ using namespace Components; namespace System { void motion(DinkyECS::World &world, Map &game_map); void combat(DinkyECS::World &world, Player &player); + void death(DinkyECS::World &world); void enemy_pathing(DinkyECS::World &world, Map &game_map, Player &player); void draw_map(DinkyECS::World &world, Map &game_map, ftxui::Canvas &canvas, size_t view_x, size_t view_y); void draw_entities(DinkyECS::World &world, Map &game_map, ftxui::Canvas &canvas, const Point &cam_orig, size_t view_x, size_t view_y);