Fixed up building enemies and items using componentsin the JSON.
This commit is contained in:
parent
9ce4fbd552
commit
222b39c403
13 changed files with 76 additions and 60 deletions
|
@ -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"])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
dbc.cpp
13
dbc.cpp
|
@ -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};
|
||||
}
|
||||
}
|
||||
|
|
3
gui.cpp
3
gui.cpp
|
@ -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));
|
||||
|
||||
|
|
22
matrix.hpp
22
matrix.hpp
|
@ -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);
|
||||
}
|
||||
|
|
5
save.cpp
5
save.cpp
|
@ -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
save.hpp
1
save.hpp
|
@ -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…
Add table
Add a link
Reference in a new issue