Game now loads random enemies and items into rooms but in rudimentary way. Need to now randomize more of it and make it more robust so only changing the .json is needed to get new effects and enemies.

main
Zed A. Shaw 2 weeks ago
parent 31e5eb7fce
commit f2864a62ee
  1. 15
      assets/enemies.json
  2. 8
      assets/items.json
  3. 59
      main.cpp
  4. 3
      status.txt
  5. 2
      tests/gui.cpp
  6. 2
      tests/lighting.cpp
  7. 2
      tests/map.cpp
  8. 4
      tests/matrix.cpp
  9. 2
      tests/save.cpp
  10. 2
      tests/tilemap.cpp
  11. 4
      tests/worldbuilder.cpp
  12. 87
      worldbuilder.cpp
  13. 5
      worldbuilder.hpp

@ -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"
}
}

@ -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": "☀"
}
}

@ -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<GameConfig>();
// configure a player as a fact of the world
Player player{world.entity()};
world.set_the<Player>(player);
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.enemies["PLAYER_TILE"]["display"]});
world.set<LightSource>(player.entity, {50,1.0});
world.set<Inventory>(player.entity, {5});
auto sword = world.entity();
auto pos = game_map.place_entity(1);
world.set<Position>(sword, {pos.x+1, pos.y+1});
world.set<Tile>(sword, {config.items["SWORD_RUSTY"]["display"]});
world.set<InventoryItem>(sword, {1, config.items["SWORD_RUSTY"]});
world.set<Weapon>(sword, {20});
auto torch = world.entity();
pos = game_map.place_entity(2);
world.set<Position>(torch, {pos.x+1, pos.y+1});
world.set<Tile>(torch, {config.items["TORCH_BAD"]["display"]});
world.set<InventoryItem>(torch, {1, config.items["TORCH_BAD"]});
world.set<LightSource>(torch, {70,2.0f});
auto enemy = world.entity();
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.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, {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, {config.items["CHEST_SMALL"]["display"]});
world.set<InventoryItem>(gold, {1, config.items["CHEST_SMALL"]});
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, {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;

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

@ -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<GameConfig>();
// configure a player as a fact of the world

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

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

@ -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<size_t>(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;

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

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

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

@ -2,8 +2,10 @@
#include "rand.hpp"
#include <fmt/core.h>
#include <iostream>
#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<GameConfig>();
auto item = world.entity();
auto pos = game_map.place_entity(in_room);
json item_data = config.items[name];
world.set<Position>(item, {pos.x+1, pos.y+1});
world.set<Tile>(item, {item_data["display"]});
if(item_data["type"] == "WEAPON") {
world.set<InventoryItem>(item, {1, item_data});
world.set<Weapon>(item, {20});
} else if(item_data["type"] == "LIGHT") {
world.set<InventoryItem>(item, {1, item_data});
world.set<LightSource>(item, {70,2.0f});
} else if(item_data["type"] == "LOOT") {
world.set<InventoryItem>(item, {1, item_data});
world.set<Loot>(item, {100});
} else if(item_data["type"] == "FIXED_LIGHT") {
world.set<LightSource>(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<GameConfig>();
auto enemy = world.entity();
auto enemy_data = config.enemies[name];
world.set<Position>(enemy, {game_map.place_entity(in_room)});
world.set<Motion>(enemy, {0,0});
world.set<Tile>(enemy, {enemy_data["display"]});
world.set<Combat>(enemy, {enemy_data["hp"], enemy_data["damage"]});
return enemy;
}
void WorldBuilder::place_entities(DinkyECS::World &world) {
auto &config = world.get_the<GameConfig>();
// 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>(player);
world.set<Combat>(player.entity, {100, 10});
world.set<LightSource>(player.entity, {50,1.0});
world.set<Inventory>(player.entity, {5});
{
std::vector<std::string> 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<std::string> 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);

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

Loading…
Cancel
Save