Fixed up the map generator so that it's placing entities in non-overlapping tiles and adapting the style for the size. It can also deal with maps that have no rooms better and places the stairs better.

master
Zed A. Shaw 1 week ago
parent 5f1a453fb4
commit 4eaf3c35d6
  1. 15
      assets/items.json
  2. 4
      camera.cpp
  3. 2
      camera.hpp
  4. 2
      constants.hpp
  5. 6
      gui/fsm.cpp
  6. 7
      gui/main_ui.cpp
  7. 2
      gui/main_ui.hpp
  8. 4
      levelmanager.cpp
  9. 16
      maze.cpp
  10. 39
      worldbuilder.cpp
  11. 3
      worldbuilder.hpp

@ -14,21 +14,6 @@
{"_type": "Sound", "attack": "pickup", "death": "blank"}
]
},
"SWORD_RUSTY": {
"id": "SWORD_RUSTY",
"name": "Rusty Junk Sword",
"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.",
"inventory_count": 1,
"components": [
{"_type": "Weapon", "damage": 15},
{"_type": "Tile", "display": 7735,
"foreground": [24, 120, 189],
"background": [24, 120, 189]
},
{"_type": "Sprite", "name": "cinqueda", "width": 256, "height": 256, "scale": 1.0},
{"_type": "Sound", "attack": "pickup", "death": "blank"}
]
},
"BARREL_SMALL": {
"id": "BARREL_SMALL",
"name": "Small Barrel",

@ -15,9 +15,9 @@ Point CameraLOL::plan_move(int dir, bool strafe) {
return {size_t(target_x), size_t(target_y)};
}
void CameraLOL::plan_rotate(int dir) {
void CameraLOL::plan_rotate(int dir, float amount) {
t = 0.0;
double angle_dir = std::numbers::pi * 0.25 * dir;
double angle_dir = std::numbers::pi * amount * float(dir);
target_dir_x = rayview.$dir_x * cos(angle_dir) - rayview.$dir_y * sin(angle_dir);
target_dir_y = rayview.$dir_x * sin(angle_dir) + rayview.$dir_y * cos(angle_dir);

@ -17,7 +17,7 @@ struct CameraLOL {
rayview(rv) {}
Point plan_move(int dir, bool strafe);
void plan_rotate(int dir);
void plan_rotate(int dir, float amount=0.5f);
bool play_rotate();
bool play_move();

@ -60,6 +60,8 @@ constexpr int COMBAT_UI_Y = RAY_VIEW_HEIGHT;
constexpr int COMBAT_UI_WIDTH = RAY_VIEW_WIDTH ;
constexpr int COMBAT_UI_HEIGHT = SCREEN_HEIGHT - RAY_VIEW_HEIGHT;
constexpr int INITIAL_MAP_W = 17;
constexpr int INITIAL_MAP_H = 15;
// for the panels/renderer
constexpr wchar_t BG_TILE = L'';

@ -152,11 +152,11 @@ namespace gui {
try_move(1, true);
break;
case ROTATE_LEFT:
$main_ui.plan_rotate(-1);
$main_ui.plan_rotate(-1, 0.5f);
state(State::ROTATING);
break;
case ROTATE_RIGHT:
$main_ui.plan_rotate(1);
$main_ui.plan_rotate(1, 0.5f);
state(State::ROTATING);
break;
case MAP_OPEN:
@ -356,7 +356,7 @@ namespace gui {
if($map_open) {
$map_ui.render($window, $main_ui.$compass_dir);
} else {
// $mini_map.render($window, $main_ui.$compass_dir);
$mini_map.render($window, $main_ui.$compass_dir);
}
}
}

@ -77,10 +77,11 @@ namespace gui {
}
}
void MainUI::plan_rotate(int dir) {
void MainUI::plan_rotate(int dir, float amount) {
// -1 is left, 1 is right
$compass_dir = ($compass_dir + dir) % COMPASS.size();
$camera.plan_rotate(dir);
int extra = (amount == 0.5) * dir;
$compass_dir = ($compass_dir + dir + extra) % COMPASS.size();
$camera.plan_rotate(dir, amount);
}
Point MainUI::plan_move(int dir, bool strafe) {

@ -29,7 +29,7 @@ namespace gui {
void debug();
void render_debug();
void plan_rotate(int dir);
void plan_rotate(int dir, float amount=0.5f);
bool play_rotate();
std::optional<Point> play_move();
Point plan_move(int dir, bool strafe);

@ -17,8 +17,8 @@ LevelManager::LevelManager() {
LevelScaling LevelManager::scale_level() {
return {
21,
21
INITIAL_MAP_W + int($current_level * 2),
INITIAL_MAP_H + int($current_level * 2)
};
}

@ -95,16 +95,12 @@ namespace maze {
}
void Builder::randomize_rooms() {
dbc::check($dead_ends.size() >= 2, "must have at least two possible points to place rooms");
while($rooms.size() < 2) {
// use those dead ends to randomly place rooms
for(auto at : $dead_ends) {
if(Random::uniform(0,1)) {
size_t offset = Random::uniform(0,1);
Room cur{at.x+offset, at.y+offset, 1, 1};
$rooms.push_back(cur);
}
// use those dead ends to randomly place rooms
for(auto at : $dead_ends) {
if(Random::uniform(0,1)) {
size_t offset = Random::uniform(0,1);
Room cur{at.x+offset, at.y+offset, 1, 1};
$rooms.push_back(cur);
}
}
}

@ -12,21 +12,41 @@ using namespace components;
void WorldBuilder::generate_map() {
maze::Builder maze($map);
size_t x_diff = $map.width() / 4;
size_t y_diff = $map.height() / 4;
maze.divide({x_diff, y_diff}, {$map.width() - x_diff, $map.height() - y_diff});
maze.hunt_and_kill();
maze.randomize_rooms();
dbc::check($map.$dead_ends.size() > 0, "world builder/maze builder made a map with no dead ends.");
if($map.width() > 20) {
maze.inner_box(4, 2);
}
maze.hunt_and_kill();
$map.expand();
$map.load_tiles();
}
DinkyECS::Entity WorldBuilder::configure_entity_in_map(DinkyECS::World &world, json &entity_data, Point pos_out) {
bool WorldBuilder::find_open_spot(Point& pos_out) {
// NOTE: still spawning near a player but not sure if this is the place
// to solve that. Idea: Get the player, don't place anything too close.
for(matrix::rando_rect it{$map.walls(), pos_out.x, pos_out.y, 3}; it.next();) {
Point test{size_t(it.x), size_t(it.y)};
if($map.can_move(test) && !$collision.occupied(test)) {
pos_out = test;
return true;
}
}
return false;
}
DinkyECS::Entity WorldBuilder::configure_entity_in_map(DinkyECS::World &world, json &entity_data, Point pos) {
bool found = find_open_spot(pos);
dbc::check(found, "Failed to find a place for this thing.");
auto item = world.entity();
world.set<Position>(item, {pos_out.x+1, pos_out.y+1});
world.set<Position>(item, {pos.x, pos.y});
if(entity_data["inventory_count"] > 0) {
world.set<InventoryItem>(item, {entity_data["inventory_count"], entity_data});
@ -36,6 +56,8 @@ DinkyECS::Entity WorldBuilder::configure_entity_in_map(DinkyECS::World &world, j
components::configure_entity($components, world, item, entity_data["components"]);
}
$collision.insert(pos, item);
return item;
}
@ -97,8 +119,9 @@ void WorldBuilder::randomize_entities(DinkyECS::World &world, GameConfig &config
void WorldBuilder::place_stairs(DinkyECS::World& world, GameConfig& config) {
auto& device_config = config.devices.json();
auto entity_data = device_config["STAIRS_DOWN"];
int last_room = $map.room_count() - 1;
configure_entity_in_room(world, entity_data, last_room);
auto at_end = $map.$dead_ends.back();
configure_entity_in_map(world, entity_data, at_end);
}
void WorldBuilder::configure_starting_items(DinkyECS::World &world) {

@ -3,11 +3,13 @@
#include "map.hpp"
#include "dinkyecs.hpp"
#include "components.hpp"
#include "spatialmap.hpp"
class WorldBuilder {
public:
Map& $map;
components::ComponentMap& $components;
SpatialMap $collision;
WorldBuilder(Map &map, components::ComponentMap& components) :
$map(map),
@ -20,6 +22,7 @@ class WorldBuilder {
DinkyECS::Entity configure_entity_in_room(DinkyECS::World &world, nlohmann::json &entity_data, int in_room);
bool find_open_spot(Point& pos_out);
void place_entities(DinkyECS::World &world);
void generate(DinkyECS::World &world);
void randomize_entities(DinkyECS::World &world, components::GameConfig &config);

Loading…
Cancel
Save