adg5/Map.cpp
2025-04-20 10:05:21 +10:00

102 lines
2.9 KiB
C++

#include "libtcod.hpp"
#include "Map.h"
#include "Actor.h"
#include "Engine.h"
static const int ROOM_MAX_SIZE = 12;
static const int ROOM_MIN_SIZE = 6;
class BspListener : public ITCODBspCallback {
private:
Map& map; // a map to dig
int roomNum; // room number
int lastx = 0, lasty = 0; // center of the last room
public:
BspListener(Map& map) : map(map), roomNum(0) {}
bool visitNode(TCODBsp* node, void* userData) {
if (node->isLeaf()) {
int x, y, w, h;
// dig a room
TCODRandom* rng = TCODRandom::getInstance();
w = rng->getInt(ROOM_MIN_SIZE, node->w - 2);
h = rng->getInt(ROOM_MIN_SIZE, node->h - 2);
x = rng->getInt(node->x + 1, node->x + node->w - w - 1);
y = rng->getInt(node->y + 1, node->y + node->h - h - 1);
map.createRoom(roomNum == 0, x, y, x + w - 1, y + h - 1);
if (roomNum != 0) {
// dig a corridor from last room
map.dig(lastx, lasty, x + w / 2, lasty);
map.dig(x + w / 2, lasty, x + w / 2, y + h / 2);
}
lastx = x + w / 2;
lasty = y + h / 2;
roomNum++;
}
return true;
}
};
Map::Map(int width, int height) : width(width), height(height) {
tiles = new Tile[width * height];
TCODBsp bsp(0, 0, width, height);
bsp.splitRecursive(NULL, 8, ROOM_MAX_SIZE, ROOM_MAX_SIZE, 1.5f, 1.5f);
BspListener listener(*this);
bsp.traverseInvertedLevelOrder(&listener, NULL);
}
Map::~Map() {
delete[] tiles;
}
bool Map::isWall(int x, int y) const {
return !tiles[x + y * width].canWalk;
}
void Map::setWall(int x, int y) {
tiles[x + y * width].canWalk = false;
}
void Map::render(TCOD_Console& cons) const {
static const TCOD_ColorRGB darkWall(0, 0, 100);
static const TCOD_ColorRGB darkGround(50, 50, 150);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
tcod::print(cons, { x, y }, " ", std::nullopt, isWall(x, y) ? darkWall : darkGround);
}
}
}
void Map::dig(int x1, int y1, int x2, int y2) {
if (x2 < x1) {
int tmp = x2;
x2 = x1;
x1 = tmp;
}
if (y2 < y1) {
int tmp = y2;
y2 = y1;
y1 = tmp;
}
for (int tilex = x1; tilex <= x2; tilex++) {
for (int tiley = y1; tiley <= y2; tiley++) {
tiles[tilex + tiley * width].canWalk = true;
}
}
}
void Map::createRoom(bool first, int x1, int y1, int x2, int y2) {
dig(x1, y1, x2, y2);
if (first) {
// put the player in the first room
engine->player->x = (x1 + x2) / 2;
engine->player->y = (y1 + y2) / 2;
}
else {
TCODRandom* rng = TCODRandom::getInstance();
if (rng->getInt(0, 3) == 0) {
engine->actors.push(new Actor((x1 + x2) / 2, (y1 + y2) / 2, "@",
TCOD_ColorRGB(255, 255, 0)));
}
}
}