Fixed up building enemies and items using componentsin the JSON.

main
Zed A. Shaw 2 weeks ago
parent 9ce4fbd552
commit 222b39c403
  1. 15
      assets/enemies.json
  2. 8
      assets/items.json
  3. 28
      components.hpp
  4. 13
      dbc.cpp
  5. 3
      gui.cpp
  6. 22
      matrix.hpp
  7. 5
      save.cpp
  8. 1
      save.hpp
  9. 1
      status.txt
  10. 6
      systems.cpp
  11. 6
      tests/components.cpp
  12. 2
      tests/matrix.cpp
  13. 26
      worldbuilder.cpp

@ -4,7 +4,8 @@
"background": [30, 20, 75],
"components": [
{"type": "Tile", "config": {"chr": "\ua66b"}},
{"type": "Combat", "config": {"hp": 200, "damage": 15}}
{"type": "Combat", "config": {"hp": 200, "damage": 15}},
{"type": "EnemyConfig", "config": {"hearing_distance": 5}}
]
},
"SNAKE": {
@ -12,7 +13,8 @@
"background": [30, 20, 75],
"components": [
{"type": "Tile", "config": {"chr": "\u06b1"}},
{"type": "Combat", "config": {"hp": 20, "damage": 15}}
{"type": "Combat", "config": {"hp": 20, "damage": 15}},
{"type": "EnemyConfig", "config": {"hearing_distance": 6}}
]
},
"GOBLIN": {
@ -21,7 +23,8 @@
"components": [
{"type": "LightSource", "config": {"strength": 70, "radius": 1.8}},
{"type": "Tile", "config": {"chr": "\u06bf"}},
{"type": "Combat", "config": {"hp": 50, "damage": 35}}
{"type": "Combat", "config": {"hp": 50, "damage": 35}},
{"type": "EnemyConfig", "config": {"hearing_distance": 4}}
]
},
"UNICORN": {
@ -29,7 +32,8 @@
"background": [30, 20, 75],
"components": [
{"type": "Tile", "config": {"chr": "\u17a5"}},
{"type": "Combat", "config": {"hp": 2000, "damage": 5}}
{"type": "Combat", "config": {"hp": 100, "damage": 5}},
{"type": "EnemyConfig", "config": {"hearing_distance": 3}}
]
},
"RAT": {
@ -37,7 +41,8 @@
"background": [30, 20, 75],
"components": [
{"type": "Tile", "config": {"chr": "\u08ac"}},
{"type": "Combat", "config": {"hp": 10, "damage": 5}}
{"type": "Combat", "config": {"hp": 10, "damage": 5}},
{"type": "EnemyConfig", "config": {"hearing_distance": 10}}
]
}
}

@ -8,8 +8,7 @@
"inventory_count": 1,
"components": [
{"type": "LightSource", "config": {"strength": 70, "radius": 2.0}},
{"type": "Tile", "config": {"chr": "\u0f08"}},
{"type": "Weapon", "config": {"damage": 35}}
{"type": "Tile", "config": {"chr": "\u0f08"}}
]
},
"SWORD_RUSTY": {
@ -57,9 +56,8 @@
"description": "A torch on a wall you can't pick up.",
"inventory_count": 0,
"components": [
{"type": "Tile", "config": {"chr": "\u06bf"}},
{"type": "Tile", "config": {"chr": "\u077e"}},
{"type": "LightSource", "config": {"strength": 60, "radius": 1.8}}
],
"display": "☀"
]
}
}

@ -1,10 +1,9 @@
#pragma once
#include "dinkyecs.hpp"
#include "map.hpp"
#include "combat.hpp"
#include "inventory.hpp"
#include <deque>
#include "tser.hpp"
#include "config.hpp"
namespace components {
struct Player {
@ -41,7 +40,7 @@ namespace components {
};
struct EnemyConfig {
int HEARING_DISTANCE;
int hearing_distance = 10;
};
struct Debug {
@ -52,4 +51,27 @@ namespace components {
struct Weapon {
int damage = 0;
};
inline void configure(DinkyECS::World &world, DinkyECS::Entity entity, json& entity_data) {
for(auto &comp : entity_data["components"]) {
json& config = comp["config"];
if(comp["type"] == "Weapon") {
world.set<Weapon>(entity, {config["damage"]});
} else if(comp["type"] == "LightSource") {
world.set<LightSource>(entity, {config["strength"], config["radius"]});
} else if(comp["type"] == "Loot") {
world.set<Loot>(entity, {config["amount"]});
} else if(comp["type"] == "Tile") {
world.set<Tile>(entity, {config["chr"]});
} else if(comp["type"] == "EnemyConfig") {
world.set<EnemyConfig>(entity, {config["hearing_distance"]});
} else if(comp["type"] == "Combat") {
world.set<Combat>(entity, {config["hp"], config["damage"]});
} else {
dbc::sentinel(fmt::format("ITEM COMPONENT TYPE MISSING: {}",
std::string(comp["type"])));
}
}
}
}

@ -2,17 +2,19 @@
#include <iostream>
void dbc::log(const string &message) {
fmt::print("{}\n", message);
std::cerr << message << std::endl;
}
void dbc::sentinel(const string &message) {
string err = fmt::format("[SENTINEL!] {}\n", message);
string err = fmt::format("[SENTINEL!] {}", message);
dbc::log(err);
throw dbc::SentinelError{err};
}
void dbc::pre(const string &message, bool test) {
if(!test) {
string err = fmt::format("[PRE!] {}\n", message);
string err = fmt::format("[PRE!] {}", message);
dbc::log(err);
throw dbc::PreCondError{err};
}
}
@ -23,7 +25,8 @@ void dbc::pre(const string &message, std::function<bool()> tester) {
void dbc::post(const string &message, bool test) {
if(!test) {
string err = fmt::format("[POST!] {}\n", message);
string err = fmt::format("[POST!] {}", message);
dbc::log(err);
throw dbc::PostCondError{err};
}
}
@ -35,7 +38,7 @@ void dbc::post(const string &message, std::function<bool()> tester) {
void dbc::check(bool test, const string &message) {
if(!test) {
string err = fmt::format("[CHECK!] {}\n", message);
fmt::println("{}", err);
dbc::log(err);
throw dbc::CheckError{err};
}
}

@ -72,8 +72,7 @@ void InventoryUI::update_menu_list(Inventory& inventory) {
$menu_list.clear();
for(size_t i = 0; i < inventory.count(); i++) {
auto& item = inventory.get(i);
$menu_list.push_back(fmt::format("{} {} ({})",
string(item.data["display"]),
$menu_list.push_back(fmt::format("{} ({})",
string(item.data["name"]),
item.count));

@ -10,8 +10,15 @@ namespace matrix {
using std::vector, std::queue, std::array;
using std::min, std::max, std::floor;
typedef vector<int> Row;
typedef vector<Row> Matrix;
template<typename T>
using BaseRow = vector<T>;
template<typename T>
using Base = vector<BaseRow<T>>;
using Row = vector<int>;
using Matrix = vector<Row>;
/*
* Just a quick thing to reset a matrix to a value.
@ -40,6 +47,17 @@ namespace matrix {
return mat.size();
}
template<typename T>
inline Base<T> make_base(size_t width, size_t height) {
Base<T> result(height, BaseRow<T>(width));
return result;
}
inline Matrix make(size_t width, size_t height) {
Matrix result(height, Row(width));
return result;
}
inline size_t next_x(size_t x, size_t width) {
return (x + 1) * ((x + 1) < width);
}

@ -92,9 +92,4 @@ void save::load_configs(DinkyECS::World &world) {
world.set_the<GameConfig>({
game, enemies, items, tiles
});
auto enemy = game["enemy"];
world.set_the<EnemyConfig>({
enemy["HEARING_DISTANCE"]
});
}

@ -1,6 +1,7 @@
#pragma once
#include "components.hpp"
#include "map.hpp"
#include "dinkyecs.hpp"
#include "tser.hpp"
#include <filesystem>

@ -1,5 +1,6 @@
TODAY'S GOAL:
* Goblins will be in the world and not move or are already dead.
* https://pkl-lang.org/
* Check out https://github.com/stephenberry/glaze
* Things are still in walls because I +1 the x,y if they're colliding.

@ -32,15 +32,17 @@ void System::lighting(DinkyECS::World &world, Map &game_map, LightRender &light,
void System::enemy_pathing(DinkyECS::World &world, Map &game_map, Player &player) {
// TODO: this will be on each enemy not a global thing
const auto &config = world.get_the<EnemyConfig>();
const auto &player_position = world.get<Position>(player.entity);
game_map.set_target(player_position.location);
game_map.make_paths();
world.query<Position, Motion>([&](const auto &ent, auto &position, auto &motion) {
if(ent != player.entity) {
dbc::check(world.has<EnemyConfig>(ent), "enemy is missing config");
const auto &config = world.get<EnemyConfig>(ent);
Point out = position.location; // copy
if(game_map.distance(out) < config.HEARING_DISTANCE) {
if(game_map.distance(out) < config.hearing_distance) {
game_map.neighbors(out);
motion = { int(out.x - position.location.x), int(out.y - position.location.y)};
}

@ -36,9 +36,6 @@ TEST_CASE("all components can work in the world", "[components]") {
auto tile = world.get<Tile>(ent1);
REQUIRE(tile.chr == "Z");
auto enemy = world.get<EnemyConfig>(ent1);
REQUIRE(enemy.HEARING_DISTANCE == 4);
}
TEST_CASE("all components can be facts", "[components]") {
@ -72,9 +69,6 @@ TEST_CASE("all components can be facts", "[components]") {
auto tile = world.get_the<Tile>();
REQUIRE(tile.chr == "Z");
auto enemy = world.get_the<EnemyConfig>();
REQUIRE(enemy.HEARING_DISTANCE == 4);
}
TEST_CASE("confirm combat works", "[components]") {

@ -86,7 +86,7 @@ TEST_CASE("thrash matrix iterators", "[matrix]") {
size_t width = Random::uniform<size_t>(1, 100);
size_t height = Random::uniform<size_t>(1, 100);
Matrix test(width, matrix::Row(height));
Matrix test(height, matrix::Row(width));
random_matrix(test);
// first make a randomized matrix

@ -168,28 +168,6 @@ void WorldBuilder::generate_map() {
}
}
void configure_components(DinkyECS::World &world, DinkyECS::Entity entity, json& entity_data) {
for(auto &comp : entity_data["components"]) {
json& config = comp["config"];
if(comp["type"] == "Weapon") {
world.set<Weapon>(entity, {config["damage"]});
} else if(comp["type"] == "LightSource") {
world.set<LightSource>(entity, {config["strength"], config["radius"]});
} else if(comp["type"] == "Loot") {
world.set<Loot>(entity, {config["amount"]});
} else if(comp["type"] == "Tile") {
world.set<Tile>(entity, {config["chr"]});
} else if(comp["type"] == "EnemyConfig") {
world.set<EnemyConfig>(entity, {config["hearing_distance"]});
} else if(comp["type"] == "Combat") {
world.set<Combat>(entity, {config["hp"], config["damage"]});
} else {
dbc::sentinel(format("ITEM COMPONENT TYPE MISSING: {}",
std::string(comp["type"])));
}
}
}
DinkyECS::Entity place_item(DinkyECS::World &world, Map &game_map, std::string name, int in_room) {
auto &config = world.get_the<GameConfig>();
@ -203,7 +181,7 @@ DinkyECS::Entity place_item(DinkyECS::World &world, Map &game_map, std::string n
}
if(item_data.contains("components")) {
configure_components(world, item, item_data);
components::configure(world, item, item_data);
}
return item;
}
@ -217,7 +195,7 @@ DinkyECS::Entity place_combatant(DinkyECS::World &world, Map &game_map, std::str
world.set<Motion>(enemy, {0,0});
if(enemy_data.contains("components")) {
configure_components(world, enemy, enemy_data);
components::configure(world, enemy, enemy_data);
}
return enemy;
}

Loading…
Cancel
Save