diff --git a/assets/enemies.json b/assets/enemies.json index e19e47d..2633ab4 100644 --- a/assets/enemies.json +++ b/assets/enemies.json @@ -2,31 +2,36 @@ "PLAYER_TILE": { "foreground": [255, 200, 125], "background": [30, 20, 75], + "hp": 100, + "damage": 10, "display":"\ua66b" }, - "ENEMY_TILE": { - "foreground": [100, 200, 125], - "background": [30, 20, 75], - "display":"\u1d5c" - }, "SNAKE": { "foreground": [90, 172, 74], "background": [30, 20, 75], + "hp": 15, + "damage": 5, "display":"\u06b1" }, "GOBLIN": { "foreground": [50, 200, 125], "background": [30, 20, 75], + "hp": 75, + "damage": 30, "display":"\u06bf" }, "UNICORN": { "foreground": [25, 200, 125], "background": [30, 20, 75], + "hp": 50, + "damage": 20, "display":"\u17a5" }, "RAT": { "foreground": [75, 200, 125], "background": [30, 20, 75], + "hp": 5, + "damage": 1, "display":"\u08ac" } } diff --git a/assets/items.json b/assets/items.json index 04d5137..f8b675f 100644 --- a/assets/items.json +++ b/assets/items.json @@ -5,6 +5,7 @@ "foreground": [24, 205, 189], "background": [230, 20, 120], "description": "A torch that barely lights the way. You wonder if it'd be better to not see the person who murders you.", + "type": "LIGHT", "display": "\u0f08" }, "SWORD_RUSTY": { @@ -13,6 +14,7 @@ "foreground": [24, 205, 189], "background": [24, 205, 189], "description": "A sword left to rot in a deep hole where it acquired a patina of dirt and tetanus. You aren't sure if it's more deadly for you to hold it or for the people you stab with it.", + "type": "WEAPON", "display":"\u1e37" }, "CHEST_SMALL": { @@ -20,8 +22,9 @@ "name": "Small Chest", "foreground": [24, 205, 189], "background": [24, 205, 189], - "display":"\uaaea", - "description": "A small chest of gold. You wonder who would leave something like this around." + "description": "A small chest of gold. You wonder who would leave something like this around.", + "type": "LOOT", + "display":"\uaaea" }, "WALL_TORCH": { "id": "WALL_TORCH", @@ -29,6 +32,7 @@ "foreground": [24, 205, 189], "background": [24, 205, 189], "description": "A torch on a wall you can't pick up.", + "type": "FIXED_LIGHT", "display": "☀" } } diff --git a/main.cpp b/main.cpp index 305bf0e..c63e042 100644 --- a/main.cpp +++ b/main.cpp @@ -20,62 +20,6 @@ using namespace components; using lighting::LightSource; namespace fs = std::filesystem; -/* - * This needs to be turned into a real world generator - * system. - */ -void configure_world(DinkyECS::World &world, Map &game_map) { - auto &config = world.get_the(); - // configure a player as a fact of the world - Player player{world.entity()}; - world.set_the(player); - - world.set(player.entity, {game_map.place_entity(0)}); - world.set(player.entity, {0, 0}); - world.set(player.entity, {100, 10}); - world.set(player.entity, {config.enemies["PLAYER_TILE"]["display"]}); - world.set(player.entity, {50,1.0}); - world.set(player.entity, {5}); - - auto sword = world.entity(); - auto pos = game_map.place_entity(1); - world.set(sword, {pos.x+1, pos.y+1}); - world.set(sword, {config.items["SWORD_RUSTY"]["display"]}); - world.set(sword, {1, config.items["SWORD_RUSTY"]}); - world.set(sword, {20}); - - auto torch = world.entity(); - pos = game_map.place_entity(2); - world.set(torch, {pos.x+1, pos.y+1}); - world.set(torch, {config.items["TORCH_BAD"]["display"]}); - world.set(torch, {1, config.items["TORCH_BAD"]}); - world.set(torch, {70,2.0f}); - - auto enemy = world.entity(); - world.set(enemy, {game_map.place_entity(1)}); - world.set(enemy, {0,0}); - world.set(enemy, {20, 10}); - world.set(enemy, {config.enemies["UNICORN"]["display"]}); - - auto enemy2 = world.entity(); - world.set(enemy2, {game_map.place_entity(2)}); - world.set(enemy2, {0,0}); - world.set(enemy2, {20, 10}); - world.set(enemy2, {config.enemies["SNAKE"]["display"]}); - world.set(enemy2, {60,0.2f}); - - auto gold = world.entity(); - world.set(gold, {game_map.place_entity(3)}); - world.set(gold, {100}); - world.set(gold, {config.items["CHEST_SMALL"]["display"]}); - world.set(gold, {1, config.items["CHEST_SMALL"]}); - - auto wall_torch = world.entity(); - world.set(wall_torch, {game_map.place_entity(4)}); - world.set(wall_torch, {90,3.0f}); - world.set(wall_torch, {config.items["WALL_TORCH"]["display"]}); -} - int main(int argc, char *argv[]) { DinkyECS::World world; Map game_map(GAME_MAP_X, GAME_MAP_Y); @@ -87,8 +31,7 @@ int main(int argc, char *argv[]) { save::from_file(save_path, world, game_map); } else { WorldBuilder builder(game_map); - builder.generate(); - configure_world(world, game_map); + builder.generate(world); } SpatialMap collider; diff --git a/status.txt b/status.txt index 095f43a..da160f1 100644 --- a/status.txt +++ b/status.txt @@ -1,5 +1,8 @@ TODAY'S GOAL: +* I don't handle death at all. It crashes when I die. +* 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. * Config loader should setup the "id" based on the key to avoid errors. * Colision fails when you place two entities on the same square, but the init_positions adds them and one deletes the other. diff --git a/tests/gui.cpp b/tests/gui.cpp index 9107cb6..1544163 100644 --- a/tests/gui.cpp +++ b/tests/gui.cpp @@ -18,7 +18,7 @@ TEST_CASE("load a basic gui run but don't loop", "[gui]") { save::load_configs(world); Map game_map(40, 40); WorldBuilder builder(game_map); - builder.generate(); + builder.generate_map(); auto &config = world.get_the(); // configure a player as a fact of the world diff --git a/tests/lighting.cpp b/tests/lighting.cpp index f9d348e..1ce4583 100644 --- a/tests/lighting.cpp +++ b/tests/lighting.cpp @@ -12,7 +12,7 @@ using namespace lighting; TEST_CASE("lighting a map works", "[lighting]") { Map map(20,23); WorldBuilder builder(map); - builder.generate(); + builder.generate_map(); Point light1 = map.place_entity(0); Point light2 = map.place_entity(1); diff --git a/tests/map.cpp b/tests/map.cpp index 2ac78d8..1fa2fc7 100644 --- a/tests/map.cpp +++ b/tests/map.cpp @@ -17,7 +17,7 @@ json load_test_data(const string &fname) { TEST_CASE("camera control", "[map]") { Map map(20, 20); WorldBuilder builder(map); - builder.generate(); + builder.generate_map(); Point center = map.center_camera({10,10}, 5, 5); diff --git a/tests/matrix.cpp b/tests/matrix.cpp index 3533524..20c4b3b 100644 --- a/tests/matrix.cpp +++ b/tests/matrix.cpp @@ -190,7 +190,7 @@ TEST_CASE("prototype flood algorithm", "[matrix:flood]") { Map map(width,height); WorldBuilder builder(map); - builder.generate(); + builder.generate_map(); if(map.room_count() < 2) continue; @@ -282,7 +282,7 @@ TEST_CASE("viewport iterator", "[matrix:viewport]") { size_t height = Random::uniform(21, 25); Map map(width,height); WorldBuilder builder(map); - builder.generate(); + builder.generate_map(); size_t view_width = width/2; size_t view_height = height/2; diff --git a/tests/save.cpp b/tests/save.cpp index 3ec1996..c70d6dd 100644 --- a/tests/save.cpp +++ b/tests/save.cpp @@ -58,7 +58,7 @@ TEST_CASE("basic save a world", "[save]") { DinkyECS::World world; Map map(20, 20); WorldBuilder builder(map); - builder.generate(); + builder.generate_map(); // configure a player as a fact of the world Player player{world.entity()}; diff --git a/tests/tilemap.cpp b/tests/tilemap.cpp index 86185c9..bae4b20 100644 --- a/tests/tilemap.cpp +++ b/tests/tilemap.cpp @@ -15,7 +15,7 @@ TEST_CASE("tilemap can load tiles and make a map", "[tilemap]") { Map map(width,height); WorldBuilder builder(map); - builder.generate(); + builder.generate_map(); TileMap tiles(map.width(), map.height()); auto& walls = map.walls(); diff --git a/tests/worldbuilder.cpp b/tests/worldbuilder.cpp index 916f60b..ff97012 100644 --- a/tests/worldbuilder.cpp +++ b/tests/worldbuilder.cpp @@ -12,13 +12,13 @@ using std::string; TEST_CASE("bsp algo test", "[builder]") { Map map(31, 20); WorldBuilder builder(map); - builder.generate(); + builder.generate_map(); } TEST_CASE("pathing", "[builder]") { Map map(23, 14); WorldBuilder builder(map); - builder.generate(); + builder.generate_map(); matrix::dump("WALLS", map.$walls, 0,0); println("wall at 0,0=={}", map.$walls[0][0]); diff --git a/worldbuilder.cpp b/worldbuilder.cpp index 68b3763..377f374 100644 --- a/worldbuilder.cpp +++ b/worldbuilder.cpp @@ -2,8 +2,10 @@ #include "rand.hpp" #include #include +#include "components.hpp" using namespace fmt; +using namespace components; inline int make_split(Room &cur, bool horiz) { size_t dimension = horiz ? cur.height : cur.width; @@ -119,7 +121,7 @@ void WorldBuilder::stylize_room(int room, string tile_name, float size) { } } -void WorldBuilder::generate() { +void WorldBuilder::generate_map() { PointList holes; Room root{ .x = 0, @@ -166,6 +168,89 @@ void WorldBuilder::generate() { } } +DinkyECS::Entity place_item(DinkyECS::World &world, Map &game_map, std::string name, int in_room) { + auto &config = world.get_the(); + auto item = world.entity(); + auto pos = game_map.place_entity(in_room); + json item_data = config.items[name]; + + world.set(item, {pos.x+1, pos.y+1}); + world.set(item, {item_data["display"]}); + + if(item_data["type"] == "WEAPON") { + world.set(item, {1, item_data}); + world.set(item, {20}); + } else if(item_data["type"] == "LIGHT") { + world.set(item, {1, item_data}); + world.set(item, {70,2.0f}); + } else if(item_data["type"] == "LOOT") { + world.set(item, {1, item_data}); + world.set(item, {100}); + } else if(item_data["type"] == "FIXED_LIGHT") { + world.set(item, {90,3.0f}); + } else { + dbc::sentinel(format("ITEM MISSING TYPE: {}", name)); + } + + return item; +} + + +DinkyECS::Entity place_combatant(DinkyECS::World &world, Map &game_map, std::string name, int in_room) { + auto &config = world.get_the(); + auto enemy = world.entity(); + auto enemy_data = config.enemies[name]; + world.set(enemy, {game_map.place_entity(in_room)}); + world.set(enemy, {0,0}); + world.set(enemy, {enemy_data["display"]}); + world.set(enemy, {enemy_data["hp"], enemy_data["damage"]}); + return enemy; +} + +void WorldBuilder::place_entities(DinkyECS::World &world) { + auto &config = world.get_the(); + // configure a player as a fact of the world + + auto player_ent = place_combatant(world, $map, "PLAYER_TILE", 0); + // configure player in the world + Player player{player_ent}; + world.set_the(player); + world.set(player.entity, {100, 10}); + world.set(player.entity, {50,1.0}); + world.set(player.entity, {5}); + + { + std::vector keys; + for(auto &el : config.items.json().items()) { + keys.push_back(el.key()); + } + + for(size_t room_num = 1; room_num < $map.room_count(); room_num++) { + std::string key = keys[room_num % keys.size()]; + place_item(world, $map, key, room_num); + } + } + + { + std::vector keys; + for(auto &el : config.enemies.json().items()) { + keys.push_back(el.key()); + } + + for(size_t room_num = $map.room_count() - 1; room_num > 0; room_num--) { + if(room_num % 2 == 0) { + std::string key = keys[room_num % keys.size()]; + place_combatant(world, $map, key, room_num); + } + } + } +} + +void WorldBuilder::generate(DinkyECS::World &world) { + generate_map(); + place_entities(world); +} + void WorldBuilder::make_room(size_t origin_x, size_t origin_y, size_t w, size_t h) { $map.INVARIANT(); dbc::pre("y out of bounds", origin_y + h < $map.$height); diff --git a/worldbuilder.hpp b/worldbuilder.hpp index 0f111ba..e4d39c6 100644 --- a/worldbuilder.hpp +++ b/worldbuilder.hpp @@ -1,6 +1,7 @@ #pragma once #include "map.hpp" +#include "dinkyecs.hpp" class WorldBuilder { public: @@ -11,11 +12,13 @@ class WorldBuilder { void partition_map(Room &cur, int depth); void make_room(size_t origin_y, size_t origin_x, size_t width, size_t height); void add_door(Room &room); - void generate(); void set_door(Room &room, int value); void place_rooms(); bool dig_tunnel(PointList &holes, Point &src, Point &target); void tunnel_doors(PointList &holes, Room &src, Room &target); void update_door(Point &at, int wall_or_space); void stylize_room(int room, string tile_name, float size); + void generate_map(); + void place_entities(DinkyECS::World &world); + void generate(DinkyECS::World &world); };