Very simple items system to get into the inventory work.

main
Zed A. Shaw 1 week ago
parent 1962b0c24e
commit 3d461bce6d
  1. 22
      assets/items.json
  2. 2
      assets/tiles.json
  3. 2
      combat.hpp
  4. 15
      components.hpp
  5. 4
      config.cpp
  6. 7
      gui.cpp
  7. 1
      gui.hpp
  8. 26
      main.cpp
  9. 12
      save.cpp
  10. 2
      status.txt
  11. 24
      systems.cpp
  12. 2
      tests/config.cpp
  13. 4
      tests/gui.cpp
  14. 2
      tests/sound.cpp
  15. 1
      worldbuilder.cpp

@ -0,0 +1,22 @@
{
"TORCH": {
"foreground": [24, 205, 189],
"background": [230, 20, 120],
"display": "\u0f08"
},
"SWORD": {
"foreground": [24, 205, 189],
"background": [24, 205, 189],
"display":"\u1e37"
},
"CHEST": {
"foreground": [24, 205, 189],
"background": [24, 205, 189],
"display":"\uaaea"
},
"WALL_TORCH": {
"foreground": [24, 205, 189],
"background": [24, 205, 189],
"display": "☀"
}
}

@ -56,7 +56,7 @@
"BROKEN_TILE": {
"foreground": [159, 164, 15],
"background": [199, 15, 79],
"collision": false,
"collision": true,
"display":"\u2274"
}
}

@ -6,7 +6,7 @@ namespace components {
int damage;
/* NOTE: This is used to _mark_ entities as dead, to detect ones that have just died. Don't make attack automatically set it.*/
bool dead;
bool dead = false;
int attack(Combat &target);
};

@ -29,7 +29,8 @@ namespace components {
struct Inventory {
int gold;
DEFINE_SERIALIZABLE(Inventory, gold);
LightSource light;
DEFINE_SERIALIZABLE(Inventory, gold, light);
};
struct Tile {
@ -37,9 +38,11 @@ namespace components {
DEFINE_SERIALIZABLE(Tile, chr);
};
struct MapConfig {
std::string PLAYER_TILE;
std::string ENEMY_TILE;
struct GameConfig {
Config game;
Config enemies;
Config items;
Config tiles;
};
struct EnemyConfig {
@ -50,4 +53,8 @@ namespace components {
bool PATHS=false;
bool LIGHT=false;
};
struct Weapon {
int damage = 0;
};
}

@ -1,6 +1,9 @@
#include "config.hpp"
#include "dbc.hpp"
#include <fmt/core.h>
using nlohmann::json;
using fmt::format;
Config::Config(const std::string src_path) : $src_path(src_path) {
std::ifstream infile($src_path);
@ -8,6 +11,7 @@ Config::Config(const std::string src_path) : $src_path(src_path) {
}
json &Config::operator[](const std::string &key) {
dbc::check($config.contains(key), format("ERROR in config, key {} doesn't exist.", key));
return $config[key];
}

@ -52,6 +52,7 @@ void StatusUI::create_render() {
auto status_rend = Renderer([&, player]{
const auto& player_combat = $world.get<Combat>(player.entity);
const auto& inventory = $world.get<Inventory>(player.entity);
const auto& combat = $world.get<Combat>(player.entity);
$status_text = player_combat.hp > 0 ? "NOT DEAD" : "DEAD!!!!!!";
std::vector<Element> log_list;
@ -64,8 +65,10 @@ void StatusUI::create_render() {
return hbox({
hflow(
vbox(
text(format("HP: {: >3} GOLD: {: >3}",
player_combat.hp, inventory.gold)) | border,
text(format("HP: {: >3} GOLD: {: >3} DMG: {: >3}",
player_combat.hp,
inventory.gold,
combat.damage)) | border,
text($status_text) | border,
separator(),
log_box

@ -40,7 +40,6 @@ struct UnDumbTSS {
sf::Sprite sprite;
sf::Shader shader;
sf::Shader& load_shader(string filename) {
bool good = shader.loadFromFile(filename, sf::Shader::Fragment);
dbc::check(good, "shader could not be loaded");

@ -24,7 +24,7 @@ namespace fs = std::filesystem;
* system.
*/
void configure_world(DinkyECS::World &world, Map &game_map) {
const auto &config = world.get_the<MapConfig>();
auto &config = world.get_the<GameConfig>();
// configure a player as a fact of the world
Player player{world.entity()};
world.set_the<Player>(player);
@ -32,7 +32,7 @@ void configure_world(DinkyECS::World &world, Map &game_map) {
world.set<Position>(player.entity, {game_map.place_entity(0)});
world.set<Motion>(player.entity, {0, 0});
world.set<Combat>(player.entity, {100, 10});
world.set<Tile>(player.entity, {config.PLAYER_TILE});
world.set<Tile>(player.entity, {config.enemies["PLAYER_TILE"]["display"]});
world.set<Inventory>(player.entity, {5});
world.set<LightSource>(player.entity, {70,1.0});
@ -40,24 +40,38 @@ void configure_world(DinkyECS::World &world, Map &game_map) {
world.set<Position>(enemy, {game_map.place_entity(1)});
world.set<Motion>(enemy, {0,0});
world.set<Combat>(enemy, {20, 10});
world.set<Tile>(enemy, {config.ENEMY_TILE});
world.set<Tile>(enemy, {config.enemies["UNICORN"]["display"]});
auto enemy2 = world.entity();
world.set<Position>(enemy2, {game_map.place_entity(2)});
world.set<Motion>(enemy2, {0,0});
world.set<Combat>(enemy2, {20, 10});
world.set<Tile>(enemy2, {"*"});
world.set<Tile>(enemy2, {config.enemies["SNAKE"]["display"]});
world.set<LightSource>(enemy2, {60,0.2f});
auto gold = world.entity();
world.set<Position>(gold, {game_map.place_entity(3)});
world.set<Loot>(gold, {100});
world.set<Tile>(gold, {"$"});
world.set<Tile>(gold, {config.items["CHEST"]["display"]});
auto wall_torch = world.entity();
world.set<Position>(wall_torch, {game_map.place_entity(4)});
world.set<LightSource>(wall_torch, {90,3.0f});
world.set<Tile>(wall_torch, {""});
world.set<Tile>(wall_torch, {config.items["WALL_TORCH"]["display"]});
auto torch = world.entity();
Point at = game_map.place_entity(2);
world.set<Position>(torch, {{at.x+1, at.y+1}});
world.set<Loot>(torch, {{0}});
world.set<LightSource>(torch, {70,1.5f});
world.set<Tile>(torch, {config.items["TORCH"]["display"]});
auto sword = world.entity();
at = game_map.place_entity(1);
world.set<Position>(sword, {at.x+1, at.y+1});
world.set<Weapon>(sword, {.damage=20});
world.set<Loot>(sword, {{0}});
world.set<Tile>(sword, {config.items["SWORD"]["display"]});
}
int main(int argc, char *argv[]) {

@ -84,16 +84,16 @@ void save::from_file(fs::path path, DinkyECS::World &world_out, Map &map_out) {
}
void save::load_configs(DinkyECS::World &world) {
Config config("./assets/config.json");
Config game("./assets/config.json");
Config enemies("./assets/enemies.json");
Config items("./assets/items.json");
Config tiles("./assets/tiles.json");
world.set_the<Config>(config);
world.set_the<MapConfig>({
enemies["PLAYER_TILE"]["display"],
enemies["UNICORN"]["display"],
world.set_the<GameConfig>({
game, enemies, items, tiles
});
auto enemy = config["enemy"];
auto enemy = game["enemy"];
world.set_the<EnemyConfig>({
enemy["HEARING_DISTANCE"]
});

@ -1,5 +1,7 @@
TODAY'S GOAL:
* Colision fails when you place two entities on the same square, but the init_positions adds them and one deletes the other.
* Config needs to do asserts that the key exists
* Create a move function for iterators that recalculates their position to make it easy to move them inside the matrix. This can then be used in lighting. Just make an iterator once, and move it around after.
* Components::Tile must also die.
* MapConfig must die.

@ -138,14 +138,25 @@ void System::collision(DinkyECS::World &world, Player &player) {
auto loot = world.get<Loot>(entity);
auto &loot_pos = world.get<Position>(entity);
auto &inventory = world.get<Inventory>(player.entity);
// BUG: this should go away and be a part of inventory
auto &light = world.get<LightSource>(player.entity);
world.send<Events::GUI>(Events::GUI::LOOT, entity, loot);
inventory.gold += loot.amount;
light.strength = 70;
light.radius = 2;
if(world.has<LightSource>(entity)) {
auto &new_light = world.get<LightSource>(entity);
world.set<LightSource>(player.entity, new_light);
inventory.light = new_light;
world.remove<LightSource>(entity);
} else if(world.has<Weapon>(entity)) {
auto &weapon = world.get<Weapon>(entity);
player_combat.damage = weapon.damage;
world.remove<Weapon>(entity);
} else {
// it's just gold
inventory.gold += loot.amount;
}
collider.remove(loot_pos.location);
world.remove<Tile>(entity);
world.remove<Loot>(entity);
world.send<Events::GUI>(Events::GUI::LOOT, entity, loot);
} else {
println("UNKNOWN COLLISION TYPE {}", entity);
}
@ -153,7 +164,6 @@ void System::collision(DinkyECS::World &world, Player &player) {
}
}
// BUG: this is kind of massive, need to maybe rethink how systems are designed. I mean...can each system be a callable class instead?
void System::draw_entities(DinkyECS::World &world, Map &game_map, const Matrix &lighting, ftxui::Canvas &canvas, const Point &cam_orig, size_t view_x, size_t view_y) {
auto &tiles = game_map.tiles();

@ -13,6 +13,8 @@ using std::string;
TEST_CASE("basic configuration system", "[config]") {
Config config("./tests/config.json");
REQUIRE_THROWS([&]{ config["blahblah"]; }());
auto not_found = config["types"]["NOTFOUND"];
REQUIRE(not_found == nullptr);

@ -20,7 +20,7 @@ TEST_CASE("load a basic gui run but don't loop", "[gui]") {
WorldBuilder builder(game_map);
builder.generate();
const auto &config = world.get_the<MapConfig>();
auto &config = world.get_the<GameConfig>();
// configure a player as a fact of the world
Player player{world.entity()};
world.set_the<Player>(player);
@ -28,7 +28,7 @@ TEST_CASE("load a basic gui run but don't loop", "[gui]") {
world.set<Position>(player.entity, {game_map.place_entity(0)});
world.set<Motion>(player.entity, {0, 0});
world.set<Combat>(player.entity, {100, 10});
world.set<Tile>(player.entity, {config.PLAYER_TILE});
world.set<Tile>(player.entity, {config.enemies["PLAYER_TILE"]["display"]});
world.set<Inventory>(player.entity, {5});
world.set<LightSource>(player.entity, {6,1});

@ -8,7 +8,7 @@ using DinkyECS::Entity;
using namespace fmt;
TEST_CASE("confirm basic functionality", "[sounds]") {
REQUIRE_THROWS([&](){SoundManager sounds("./BADassets");}());
REQUIRE_THROWS([&]{SoundManager sounds("./BADassets");}());
SoundManager sounds("./assets");

@ -164,7 +164,6 @@ void WorldBuilder::generate() {
string tile_name = room_types[room_type];
stylize_room(i, tile_name, room_size * 0.01f);
}
}
void WorldBuilder::make_room(size_t origin_x, size_t origin_y, size_t w, size_t h) {

Loading…
Cancel
Save