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.
This commit is contained in:
parent
5f1a453fb4
commit
4eaf3c35d6
11 changed files with 55 additions and 45 deletions
|
@ -14,21 +14,6 @@
|
||||||
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
{"_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": {
|
"BARREL_SMALL": {
|
||||||
"id": "BARREL_SMALL",
|
"id": "BARREL_SMALL",
|
||||||
"name": "Small Barrel",
|
"name": "Small Barrel",
|
||||||
|
|
|
@ -15,9 +15,9 @@ Point CameraLOL::plan_move(int dir, bool strafe) {
|
||||||
return {size_t(target_x), size_t(target_y)};
|
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;
|
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_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);
|
target_dir_y = rayview.$dir_x * sin(angle_dir) + rayview.$dir_y * cos(angle_dir);
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct CameraLOL {
|
||||||
rayview(rv) {}
|
rayview(rv) {}
|
||||||
|
|
||||||
Point plan_move(int dir, bool strafe);
|
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_rotate();
|
||||||
bool play_move();
|
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_WIDTH = RAY_VIEW_WIDTH ;
|
||||||
constexpr int COMBAT_UI_HEIGHT = SCREEN_HEIGHT - RAY_VIEW_HEIGHT;
|
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
|
// for the panels/renderer
|
||||||
constexpr wchar_t BG_TILE = L'█';
|
constexpr wchar_t BG_TILE = L'█';
|
||||||
|
|
|
@ -152,11 +152,11 @@ namespace gui {
|
||||||
try_move(1, true);
|
try_move(1, true);
|
||||||
break;
|
break;
|
||||||
case ROTATE_LEFT:
|
case ROTATE_LEFT:
|
||||||
$main_ui.plan_rotate(-1);
|
$main_ui.plan_rotate(-1, 0.5f);
|
||||||
state(State::ROTATING);
|
state(State::ROTATING);
|
||||||
break;
|
break;
|
||||||
case ROTATE_RIGHT:
|
case ROTATE_RIGHT:
|
||||||
$main_ui.plan_rotate(1);
|
$main_ui.plan_rotate(1, 0.5f);
|
||||||
state(State::ROTATING);
|
state(State::ROTATING);
|
||||||
break;
|
break;
|
||||||
case MAP_OPEN:
|
case MAP_OPEN:
|
||||||
|
@ -356,7 +356,7 @@ namespace gui {
|
||||||
if($map_open) {
|
if($map_open) {
|
||||||
$map_ui.render($window, $main_ui.$compass_dir);
|
$map_ui.render($window, $main_ui.$compass_dir);
|
||||||
} else {
|
} 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
|
// -1 is left, 1 is right
|
||||||
$compass_dir = ($compass_dir + dir) % COMPASS.size();
|
int extra = (amount == 0.5) * dir;
|
||||||
$camera.plan_rotate(dir);
|
$compass_dir = ($compass_dir + dir + extra) % COMPASS.size();
|
||||||
|
$camera.plan_rotate(dir, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point MainUI::plan_move(int dir, bool strafe) {
|
Point MainUI::plan_move(int dir, bool strafe) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace gui {
|
||||||
void debug();
|
void debug();
|
||||||
void render_debug();
|
void render_debug();
|
||||||
|
|
||||||
void plan_rotate(int dir);
|
void plan_rotate(int dir, float amount=0.5f);
|
||||||
bool play_rotate();
|
bool play_rotate();
|
||||||
std::optional<Point> play_move();
|
std::optional<Point> play_move();
|
||||||
Point plan_move(int dir, bool strafe);
|
Point plan_move(int dir, bool strafe);
|
||||||
|
|
|
@ -17,8 +17,8 @@ LevelManager::LevelManager() {
|
||||||
|
|
||||||
LevelScaling LevelManager::scale_level() {
|
LevelScaling LevelManager::scale_level() {
|
||||||
return {
|
return {
|
||||||
21,
|
INITIAL_MAP_W + int($current_level * 2),
|
||||||
21
|
INITIAL_MAP_H + int($current_level * 2)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
maze.cpp
16
maze.cpp
|
@ -95,16 +95,12 @@ namespace maze {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::randomize_rooms() {
|
void Builder::randomize_rooms() {
|
||||||
dbc::check($dead_ends.size() >= 2, "must have at least two possible points to place rooms");
|
// use those dead ends to randomly place rooms
|
||||||
|
for(auto at : $dead_ends) {
|
||||||
while($rooms.size() < 2) {
|
if(Random::uniform(0,1)) {
|
||||||
// use those dead ends to randomly place rooms
|
size_t offset = Random::uniform(0,1);
|
||||||
for(auto at : $dead_ends) {
|
Room cur{at.x+offset, at.y+offset, 1, 1};
|
||||||
if(Random::uniform(0,1)) {
|
$rooms.push_back(cur);
|
||||||
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() {
|
void WorldBuilder::generate_map() {
|
||||||
maze::Builder maze($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.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.expand();
|
||||||
$map.load_tiles();
|
$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();
|
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) {
|
if(entity_data["inventory_count"] > 0) {
|
||||||
world.set<InventoryItem>(item, {entity_data["inventory_count"], entity_data});
|
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"]);
|
components::configure_entity($components, world, item, entity_data["components"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$collision.insert(pos, item);
|
||||||
|
|
||||||
return 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) {
|
void WorldBuilder::place_stairs(DinkyECS::World& world, GameConfig& config) {
|
||||||
auto& device_config = config.devices.json();
|
auto& device_config = config.devices.json();
|
||||||
auto entity_data = device_config["STAIRS_DOWN"];
|
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) {
|
void WorldBuilder::configure_starting_items(DinkyECS::World &world) {
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
#include "map.hpp"
|
#include "map.hpp"
|
||||||
#include "dinkyecs.hpp"
|
#include "dinkyecs.hpp"
|
||||||
#include "components.hpp"
|
#include "components.hpp"
|
||||||
|
#include "spatialmap.hpp"
|
||||||
|
|
||||||
class WorldBuilder {
|
class WorldBuilder {
|
||||||
public:
|
public:
|
||||||
Map& $map;
|
Map& $map;
|
||||||
components::ComponentMap& $components;
|
components::ComponentMap& $components;
|
||||||
|
SpatialMap $collision;
|
||||||
|
|
||||||
WorldBuilder(Map &map, components::ComponentMap& components) :
|
WorldBuilder(Map &map, components::ComponentMap& components) :
|
||||||
$map(map),
|
$map(map),
|
||||||
|
@ -20,6 +22,7 @@ class WorldBuilder {
|
||||||
|
|
||||||
DinkyECS::Entity configure_entity_in_room(DinkyECS::World &world, nlohmann::json &entity_data, int in_room);
|
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 place_entities(DinkyECS::World &world);
|
||||||
void generate(DinkyECS::World &world);
|
void generate(DinkyECS::World &world);
|
||||||
void randomize_entities(DinkyECS::World &world, components::GameConfig &config);
|
void randomize_entities(DinkyECS::World &world, components::GameConfig &config);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue