Created a combat system to start with and also added a 'HEARING' mechanic where enemies can hear you from a certain distance before moving to you.

main
Zed A. Shaw 4 weeks ago
parent 753bc70b77
commit 9102bdc8ad
  1. 14
      combat.cpp
  2. 11
      combat.hpp
  3. 6
      components.hpp
  4. 1
      gui.cpp
  5. 1
      map.hpp
  6. 1
      meson.build
  7. 4
      status.txt
  8. 57
      systems.cpp
  9. 1
      systems.hpp

@ -0,0 +1,14 @@
#include "combat.hpp"
#include "rand.hpp"
int Combat::fight(Combat &target) {
int attack = Random::uniform<int>(0,1);
int my_dmg = 0;
if(attack) {
my_dmg = Random::uniform<int>(1, damage);
target.hp -= my_dmg;
}
return my_dmg;
}

@ -0,0 +1,11 @@
#pragma once
#include "components.hpp"
struct Combat {
int hp;
int damage;
bool dead;
int fight(Combat &target);
};

@ -1,6 +1,7 @@
#pragma once
#include "dinkyecs.hpp"
#include "map.hpp"
#include "combat.hpp"
#include <deque>
namespace Components {
@ -17,11 +18,6 @@ namespace Components {
int dy;
};
struct Combat {
int hp;
int damage;
};
struct Treasure {
int amount;
};

@ -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) {

@ -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];
}

@ -32,6 +32,7 @@ roguish = executable('roguish', [
'gui.cpp',
'rand.cpp',
'collider.cpp',
'combat.cpp',
'systems.cpp',
],
dependencies: dependencies)

@ -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.

@ -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<Position>(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<Position, Motion>([&](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<spatial_map>();
world.system<Position, Combat>([&](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<Motion>(ent);
}
});
}
void System::combat(DinkyECS::World &world, Player &player) {
auto& collider = world.get<spatial_map>();
@ -77,25 +97,24 @@ void System::combat(DinkyECS::World &world, Player &player) {
if(found) {
for(auto entity : nearby) {
auto& enemy_combat = world.component<Combat>(entity);
int player_dmg = Random::uniform<int>(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<Position>(entity);
collider.remove(enemy_position.location);
world.remove<Motion>(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<int>(0,1);
if(attack) {
int dmg = Random::uniform<int>(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!");
}
}
}

@ -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);

Loading…
Cancel
Save