Browse Source

Clean up initial room generation

pull/4920/head
Anders Jenbo 4 years ago
parent
commit
8ed3cb476b
  1. 255
      Source/levels/drlg_l1.cpp
  2. 8
      Source/levels/drlg_l2.cpp
  3. 339
      Source/levels/drlg_l4.cpp
  4. 1
      Source/levels/gendung.cpp
  5. 2
      Source/levels/gendung.h

255
Source/levels/drlg_l1.cpp

@ -8,6 +8,7 @@
#include "engine/load_file.hpp" #include "engine/load_file.hpp"
#include "engine/point.hpp" #include "engine/point.hpp"
#include "engine/random.hpp" #include "engine/random.hpp"
#include "engine/rectangle.hpp"
#include "levels/gendung.h" #include "levels/gendung.h"
#include "player.h" #include "player.h"
#include "quests.h" #include "quests.h"
@ -23,8 +24,6 @@ int UberDiabloMonsterIndex;
namespace { namespace {
/** Represents a tile ID map of twice the size, repeating each tile of the original map in blocks of 4. */
BYTE L5dungeon[80][80];
/** Marks where walls may not be added to the level */ /** Marks where walls may not be added to the level */
Bitset2d<DMAXX, DMAXY> Chamber; Bitset2d<DMAXX, DMAXY> Chamber;
/** Specifies whether to generate a horizontal or vertical layout. */ /** Specifies whether to generate a horizontal or vertical layout. */
@ -864,28 +863,28 @@ void InitDungeonPieces()
void InitDungeonFlags() void InitDungeonFlags()
{ {
memset(dungeon, 0, sizeof(dungeon)); memset(dungeon, 22, sizeof(dungeon));
Protected.reset(); Protected.reset();
Chamber.reset(); Chamber.reset();
} }
void MapRoom(int x, int y, int width, int height) void MapRoom(Rectangle room)
{ {
for (int j = 0; j < height; j++) { for (int y = 0; y < room.size.height; y++) {
for (int i = 0; i < width; i++) { for (int x = 0; x < room.size.width; x++) {
dungeon[x + i][y + j] = Tile::VWall; DungeonMask.set(room.position.x + x, room.position.y + y);
} }
} }
} }
bool CheckRoom(int x, int y, int width, int height) bool CheckRoom(Rectangle room)
{ {
for (int j = 0; j < height; j++) { for (int j = 0; j < room.size.height; j++) {
for (int i = 0; i < width; i++) { for (int i = 0; i < room.size.width; i++) {
if (i + x < 0 || i + x >= DMAXX || j + y < 0 || j + y >= DMAXY) { if (i + room.position.x < 0 || i + room.position.x >= DMAXX || j + room.position.y < 0 || j + room.position.y >= DMAXY) {
return false; return false;
} }
if (dungeon[i + x][j + y] != 0) { if (DungeonMask.test(i + room.position.x, j + room.position.y)) {
return false; return false;
} }
} }
@ -894,66 +893,56 @@ bool CheckRoom(int x, int y, int width, int height)
return true; return true;
} }
void GenerateRoom(int x, int y, int w, int h, int dir) void GenerateRoom(Rectangle area, bool verticalLayout)
{ {
int dirProb = GenerateRnd(4); bool rotate = GenerateRnd(4) == 0;
int num = 0; verticalLayout = (!verticalLayout && rotate) || (verticalLayout && !rotate);
bool ran; bool placeRoom1;
if ((dir == 1 && dirProb == 0) || (dir != 1 && dirProb != 0)) { Rectangle room1;
int cw;
int ch; for (int num = 0; num < 20; num++) {
int cx1; room1.size = { (GenerateRnd(5) + 2) & ~1, (GenerateRnd(5) + 2) & ~1 };
int cy1; room1.position = area.position;
do { if (verticalLayout) {
cw = (GenerateRnd(5) + 2) & ~1; room1.position += Displacement { -room1.size.width, area.size.height / 2 - room1.size.height / 2 };
ch = (GenerateRnd(5) + 2) & ~1; placeRoom1 = CheckRoom({ room1.position + Displacement { -1, -1 }, { room1.size.height + 2, room1.size.width + 1 } }); /// BUGFIX: swap height and width ({ room1.size.width + 1, room1.size.height + 2 }) (workaround applied below)
cx1 = x - cw; } else {
cy1 = h / 2 + y - ch / 2; room1.position += Displacement { area.size.width / 2 - room1.size.width / 2, -room1.size.height };
ran = CheckRoom(cx1 - 1, cy1 - 1, ch + 2, cw + 1); /// BUGFIX: swap args 3 and 4 ("ch+2" and "cw+1") (workaround applied below) placeRoom1 = CheckRoom({ room1.position + Displacement { -1, -1 }, { room1.size.width + 2, room1.size.height + 1 } });
num++; }
} while (!ran && num < 20); if (placeRoom1)
break;
if (ran)
MapRoom(cx1, cy1, std::min(DMAXX - cx1, cw), std::min(DMAXX - cy1, ch));
int cx2 = x + w;
bool ran2 = CheckRoom(cx2, cy1 - 1, cw + 1, ch + 2);
if (ran2)
MapRoom(cx2, cy1, cw, ch);
if (ran)
GenerateRoom(cx1, cy1, cw, ch, 1);
if (ran2)
GenerateRoom(cx2, cy1, cw, ch, 1);
return;
} }
int width; if (placeRoom1)
int height; MapRoom({ room1.position, { std::min(DMAXX - room1.position.x, room1.size.width), std::min(DMAXX - room1.position.y, room1.size.height) } });
int rx;
int ry; bool placeRoom2;
do { Rectangle room2 = room1;
width = (GenerateRnd(5) + 2) & ~1; if (verticalLayout) {
height = (GenerateRnd(5) + 2) & ~1; room2.position.x = area.position.x + area.size.width;
rx = w / 2 + x - width / 2; placeRoom2 = CheckRoom({ room2.position + Displacement { 0, -1 }, { room2.size.width + 1, room2.size.height + 2 } });
ry = y - height; } else {
ran = CheckRoom(rx - 1, ry - 1, width + 2, height + 1); room2.position.y = area.position.y + area.size.height;
num++; placeRoom2 = CheckRoom({ room2.position + Displacement { -1, 0 }, { room2.size.width + 2, room2.size.height + 1 } });
} while (!ran && num < 20); }
if (ran) if (placeRoom2)
MapRoom(rx, ry, width, height); MapRoom(room2);
int ry2 = y + h; if (placeRoom1)
bool ran2 = CheckRoom(rx - 1, ry2, width + 2, height + 1); GenerateRoom(room1, !verticalLayout);
if (ran2) if (placeRoom2)
MapRoom(rx, ry2, width, height); GenerateRoom(room2, !verticalLayout);
if (ran)
GenerateRoom(rx, ry, width, height, 0);
if (ran2)
GenerateRoom(rx, ry2, width, height, 0);
} }
/**
* @brief Generate a boolean dungoen room layout
*/
void FirstRoom() void FirstRoom()
{ {
DungeonMask.reset();
VerticalLayout = !FlipCoin(); VerticalLayout = !FlipCoin();
HasChamber1 = FlipCoin(); HasChamber1 = FlipCoin();
HasChamber2 = FlipCoin(); HasChamber2 = FlipCoin();
@ -962,78 +951,66 @@ void FirstRoom()
if (!HasChamber1 || !HasChamber3) if (!HasChamber1 || !HasChamber3)
HasChamber2 = true; HasChamber2 = true;
if (VerticalLayout) { Rectangle chamber1 { { 15, 15 }, { 10, 10 } };
int ys = 1; Rectangle chamber2 { { 15, 15 }, { 10, 10 } };
int ye = DMAXY - 1; Rectangle chamber3 { { 15, 15 }, { 10, 10 } };
Rectangle hallway { { 1, 1 }, { DMAXX - 2, DMAXY - 2 } };
if (HasChamber1)
MapRoom(15, 1, 10, 10);
else
ys = 18;
if (HasChamber2) if (VerticalLayout) {
MapRoom(15, 15, 10, 10); chamber1.position.y = 1;
if (HasChamber3) chamber3.position.y = 29;
MapRoom(15, 29, 10, 10); hallway.position.x = 17;
else hallway.size.width = 6;
ye = 22;
if (!HasChamber1) {
for (int y = ys; y < ye; y++) { hallway.position.y += 17;
dungeon[17][y] = Tile::VWall; hallway.size.height -= 17;
dungeon[18][y] = Tile::VWall;
dungeon[19][y] = Tile::VWall;
dungeon[20][y] = Tile::VWall;
dungeon[21][y] = Tile::VWall;
dungeon[22][y] = Tile::VWall;
} }
if (HasChamber1) if (!HasChamber3)
GenerateRoom(15, 1, 10, 10, 0); hallway.size.height -= 16;
if (HasChamber2)
GenerateRoom(15, 15, 10, 10, 0);
if (HasChamber3)
GenerateRoom(15, 29, 10, 10, 0);
} else { } else {
int xs = 1; chamber1.position.x = 1;
int xe = DMAXX - 1; chamber3.position.x = 29;
hallway.position.y = 17;
if (HasChamber1) hallway.size.height = 6;
MapRoom(1, 15, 10, 10);
else if (!HasChamber1) {
xs = 18; hallway.position.x += 17;
hallway.size.width -= 17;
if (HasChamber2)
MapRoom(15, 15, 10, 10);
if (HasChamber3)
MapRoom(29, 15, 10, 10);
else
xe = 22;
for (int x = xs; x < xe; x++) {
dungeon[x][17] = Tile::VWall;
dungeon[x][18] = Tile::VWall;
dungeon[x][19] = Tile::VWall;
dungeon[x][20] = Tile::VWall;
dungeon[x][21] = Tile::VWall;
dungeon[x][22] = Tile::VWall;
} }
if (HasChamber1) if (!HasChamber3)
GenerateRoom(1, 15, 10, 10, 1); hallway.size.width -= 16;
if (HasChamber2)
GenerateRoom(15, 15, 10, 10, 1);
if (HasChamber3)
GenerateRoom(29, 15, 10, 10, 1);
} }
if (HasChamber1)
MapRoom(chamber1);
if (HasChamber2)
MapRoom(chamber2);
if (HasChamber3)
MapRoom(chamber3);
MapRoom(hallway);
if (HasChamber1)
GenerateRoom(chamber1, VerticalLayout);
if (HasChamber2)
GenerateRoom(chamber2, VerticalLayout);
if (HasChamber3)
GenerateRoom(chamber3, VerticalLayout);
} }
/**
* @brief Find the number of mega tiles used by layout
*/
int FindArea() int FindArea()
{ {
int rv = 0; int rv = 0;
for (int j = 0; j < DMAXY; j++) { for (int j = 0; j < DMAXY; j++) {
for (int i = 0; i < DMAXX; i++) { // NOLINT(modernize-loop-convert) for (int i = 0; i < DMAXX; i++) { // NOLINT(modernize-loop-convert)
if (dungeon[i][j] == Tile::VWall) if (DungeonMask.test(i, j))
rv++; rv++;
} }
} }
@ -1041,36 +1018,11 @@ int FindArea()
return rv; return rv;
} }
void MakeDungeon()
{
for (int j = 0; j < DMAXY; j++) {
for (int i = 0; i < DMAXX; i++) {
int i2 = i * 2;
int j2 = j * 2;
L5dungeon[i2][j2] = dungeon[i][j];
L5dungeon[i2][j2 + 1] = dungeon[i][j];
L5dungeon[i2 + 1][j2] = dungeon[i][j];
L5dungeon[i2 + 1][j2 + 1] = dungeon[i][j];
}
}
}
void MakeDmt() void MakeDmt()
{ {
for (int j = 0; j < DMAXY; j++) { for (int j = 0; j < DMAXY - 1; j++) {
for (int i = 0; i < DMAXX; i++) { // NOLINT(modernize-loop-convert) for (int i = 0; i < DMAXX - 1; i++) {
dungeon[i][j] = 22; int val = (DungeonMask.test(i + 1, j + 1) << 3) | (DungeonMask.test(i, j + 1) << 2) | (DungeonMask.test(i + 1, j) << 1) | DungeonMask.test(i, j);
}
}
int dmty = 1;
for (int j = 0; dmty <= 77; j++, dmty += 2) {
int dmtx = 1;
for (int i = 0; dmtx <= 77; i++, dmtx += 2) {
int val = 8 * L5dungeon[dmtx + 1][dmty + 1]
+ 4 * L5dungeon[dmtx][dmty + 1]
+ 2 * L5dungeon[dmtx + 1][dmty]
+ L5dungeon[dmtx][dmty];
dungeon[i][j] = L5ConvTbl[val]; dungeon[i][j] = L5ConvTbl[val];
} }
} }
@ -1916,11 +1868,10 @@ void GenerateLevel(lvl_entry entry)
DRLG_InitTrans(); DRLG_InitTrans();
do { do {
InitDungeonFlags();
FirstRoom(); FirstRoom();
} while (FindArea() < minarea); } while (FindArea() < minarea);
MakeDungeon(); InitDungeonFlags();
MakeDmt(); MakeDmt();
FillChambers(); FillChambers();
FixTilesPatterns(); FixTilesPatterns();

8
Source/levels/drlg_l2.cpp

@ -1643,12 +1643,8 @@ void InitDungeonPieces()
void InitDungeonFlags() void InitDungeonFlags()
{ {
for (int j = 0; j < DMAXY; j++) { Protected.reset();
for (int i = 0; i < DMAXX; i++) { memset(predungeon, 32, sizeof(predungeon));
predungeon[i][j] = 32;
Protected.reset(i, j);
}
}
} }
void MapRoom(int x1, int y1, int x2, int y2) void MapRoom(int x1, int y1, int x2, int y2)

339
Source/levels/drlg_l4.cpp

@ -23,9 +23,6 @@ namespace {
bool hallok[20]; bool hallok[20];
Point L4Hold; Point L4Hold;
BYTE L4dungeon[80][80];
BYTE dung[20][20];
// int dword_52A4DC;
/** /**
* A lookup table for the 16 possible patterns of a 2x2 area, * A lookup table for the 16 possible patterns of a 2x2 area,
@ -170,38 +167,32 @@ void LoadQuestSetPieces()
void InitDungeonFlags() void InitDungeonFlags()
{ {
memset(dung, 0, sizeof(dung)); DungeonMask.reset();
memset(L4dungeon, 0, sizeof(L4dungeon)); Protected.reset();
memset(dungeon, 30, sizeof(dungeon));
for (int j = 0; j < DMAXY; j++) {
for (int i = 0; i < DMAXX; i++) {
dungeon[i][j] = 30;
Protected.reset(i, j);
}
}
} }
void MapRoom(int x, int y, int width, int height) void MapRoom(Rectangle room)
{ {
for (int j = 0; j < height && j + y < 20; j++) { for (int y = 0; y < room.size.height && y + room.position.y < 20; y++) {
for (int i = 0; i < width && i + x < 20; i++) { for (int x = 0; x < room.size.width && x + room.position.x < 20; x++) {
dung[i + x][j + y] = 1; DungeonMask.set(room.position.x + x, room.position.y + y);
} }
} }
} }
bool CheckRoom(int x, int y, int width, int height) bool CheckRoom(Rectangle room)
{ {
if (x <= 0 || y <= 0) { if (room.position.x <= 0 || room.position.y <= 0) {
return false; return false;
} }
for (int j = 0; j < height; j++) { for (int y = 0; y < room.size.height; y++) {
for (int i = 0; i < width; i++) { for (int x = 0; x < room.size.width; x++) {
if (i + x < 0 || i + x >= 20 || j + y < 0 || j + y >= 20) { if (x + room.position.x < 0 || x + room.position.x >= DMAXX / 2 || y + room.position.y < 0 || y + room.position.y >= DMAXY / 2) {
return false; return false;
} }
if (dung[i + x][j + y] != 0) { if (DungeonMask.test(room.position.x + x, room.position.y + y)) {
return false; return false;
} }
} }
@ -210,158 +201,101 @@ bool CheckRoom(int x, int y, int width, int height)
return true; return true;
} }
void GenerateRoom(int x, int y, int w, int h, int dir) void GenerateRoom(Rectangle area, bool verticalLayout)
{ {
int dirProb = GenerateRnd(4); bool rotate = GenerateRnd(4) != 0;
int num = 0; verticalLayout = (!verticalLayout && rotate) || (verticalLayout && !rotate);
bool ran; bool placeRoom1;
if ((dir == 1 && dirProb == 0) || (dir != 1 && dirProb != 0)) { Rectangle room1;
int cw;
int ch; for (int num = 0; num < 20; num++) {
int cx1; room1.size = { (GenerateRnd(5) + 2) & ~1, (GenerateRnd(5) + 2) & ~1 };
int cy1; room1.position = area.position;
do { if (verticalLayout) {
cw = (GenerateRnd(5) + 2) & ~1; room1.position += Displacement { -room1.size.width, area.size.height / 2 - room1.size.height / 2 };
ch = (GenerateRnd(5) + 2) & ~1; placeRoom1 = CheckRoom({ room1.position + Displacement { -1, -1 }, { room1.size.height + 2, room1.size.width + 1 } }); /// BUGFIX: swap height and width ({ room1.size.width + 1, room1.size.height + 2 }) (workaround applied below)
cx1 = x - cw; } else {
cy1 = h / 2 + y - ch / 2; room1.position += Displacement { area.size.width / 2 - room1.size.width / 2, -room1.size.height };
ran = CheckRoom(cx1 - 1, cy1 - 1, ch + 2, cw + 1); /// BUGFIX: swap args 3 and 4 ("ch+2" and "cw+1") placeRoom1 = CheckRoom({ room1.position + Displacement { -1, -1 }, { room1.size.width + 2, room1.size.height + 1 } });
num++; }
} while (!ran && num < 20); if (placeRoom1)
break;
if (ran) }
MapRoom(cx1, cy1, cw, ch);
int cx2 = x + w; if (placeRoom1)
bool ran2 = CheckRoom(cx2, cy1 - 1, cw + 1, ch + 2); MapRoom({ room1.position, { std::min(DMAXX - room1.position.x, room1.size.width), std::min(DMAXX - room1.position.y, room1.size.height) } });
if (ran2)
MapRoom(cx2, cy1, cw, ch); bool placeRoom2;
if (ran) Rectangle room2 = room1;
GenerateRoom(cx1, cy1, cw, ch, 1); if (verticalLayout) {
if (ran2) room2.position.x = area.position.x + area.size.width;
GenerateRoom(cx2, cy1, cw, ch, 1); placeRoom2 = CheckRoom({ room2.position + Displacement { 0, -1 }, { room2.size.width + 1, room2.size.height + 2 } });
return; } else {
} room2.position.y = area.position.y + area.size.height;
placeRoom2 = CheckRoom({ room2.position + Displacement { -1, 0 }, { room2.size.width + 2, room2.size.height + 1 } });
int width; }
int height;
int rx; if (placeRoom2)
int ry; MapRoom(room2);
do { if (placeRoom1)
width = (GenerateRnd(5) + 2) & ~1; GenerateRoom(room1, verticalLayout);
height = (GenerateRnd(5) + 2) & ~1; if (placeRoom2)
rx = w / 2 + x - width / 2; GenerateRoom(room2, verticalLayout);
ry = y - height;
ran = CheckRoom(rx - 1, ry - 1, width + 2, height + 1);
num++;
} while (!ran && num < 20);
if (ran)
MapRoom(rx, ry, width, height);
int ry2 = y + h;
bool ran2 = CheckRoom(rx - 1, ry2, width + 2, height + 1);
if (ran2)
MapRoom(rx, ry2, width, height);
if (ran)
GenerateRoom(rx, ry, width, height, 0);
if (ran2)
GenerateRoom(rx, ry2, width, height, 0);
} }
void FirstRoom() void FirstRoom()
{ {
int w = 14; Rectangle room { { 0, 0 }, { 14, 14 } };
int h = 14;
if (currlevel != 16) { if (currlevel != 16) {
if (currlevel == Quests[Q_WARLORD]._qlevel && Quests[Q_WARLORD]._qactive != QUEST_NOTAVAIL) { if (currlevel == Quests[Q_WARLORD]._qlevel && Quests[Q_WARLORD]._qactive != QUEST_NOTAVAIL) {
assert(!gbIsMultiplayer); assert(!gbIsMultiplayer);
w = 11; room.size = { 11, 11 };
h = 11;
} else if (currlevel == Quests[Q_BETRAYER]._qlevel && gbIsMultiplayer) { } else if (currlevel == Quests[Q_BETRAYER]._qlevel && gbIsMultiplayer) {
w = 11; room.size = { 11, 11 };
h = 11;
} else { } else {
w = GenerateRnd(5) + 2; room.size = { GenerateRnd(5) + 2, GenerateRnd(5) + 2 };
h = GenerateRnd(5) + 2;
} }
} }
int xmin = (20 - w) / 2; int xmin = (DMAXX / 2 - room.size.width) / 2;
int xmax = 19 - w; int xmax = DMAXX / 2 - 1 - room.size.width;
int x = GenerateRnd(xmax - xmin + 1) + xmin; int ymin = (DMAXY / 2 - room.size.height) / 2;
int ymax = DMAXY / 2 - 1 - room.size.height;
int ymin = (20 - h) / 2; room.position = { GenerateRnd(xmax - xmin + 1) + xmin, GenerateRnd(ymax - ymin + 1) + ymin };
int ymax = 19 - h;
int y = GenerateRnd(ymax - ymin + 1) + ymin;
if (currlevel == 16) { if (currlevel == 16) {
L4Hold = { x, y }; L4Hold = room.position;
} }
if (Quests[Q_WARLORD].IsAvailable() || (currlevel == Quests[Q_BETRAYER]._qlevel && gbIsMultiplayer)) { if (Quests[Q_WARLORD].IsAvailable() || (currlevel == Quests[Q_BETRAYER]._qlevel && gbIsMultiplayer)) {
SetPieceRoom = { { x + 1, y + 1 }, { w + 1, h + 1 } }; SetPieceRoom = { room.position + Displacement { 1, 1 }, { room.size.width + 1, room.size.height + 1 } };
} else { } else {
SetPieceRoom = {}; SetPieceRoom = {};
} }
MapRoom(x, y, w, h); MapRoom(room);
GenerateRoom(x, y, w, h, GenerateRnd(2)); GenerateRoom(room, GenerateRnd(2));
} }
void MakeDungeon() void MakeDungeon()
{ {
for (int j = 0; j < 20; j++) { for (int y = 0; y < DMAXY / 2; y++) {
for (int i = 0; i < 20; i++) { for (int x = 0; x < DMAXX / 2; x++) {
int k = i * 2; if (DungeonMask.test(x, y)) {
int l = j * 2; DungeonMask.set(x, DMAXY - 1 - y);
L4dungeon[k][l] = dung[i][j]; DungeonMask.set(DMAXX - 1 - x, y);
L4dungeon[k][l + 1] = dung[i][j]; DungeonMask.set(DMAXX - 1 - x, DMAXY - 1 - y);
L4dungeon[k + 1][l] = dung[i][j]; }
L4dungeon[k + 1][l + 1] = dung[i][j];
}
}
for (int j = 0; j < 20; j++) {
for (int i = 0; i < 20; i++) {
int k = i * 2;
int l = j * 2;
L4dungeon[k][l + 40] = dung[i][19 - j];
L4dungeon[k][l + 41] = dung[i][19 - j];
L4dungeon[k + 1][l + 40] = dung[i][19 - j];
L4dungeon[k + 1][l + 41] = dung[i][19 - j];
}
}
for (int j = 0; j < 20; j++) {
for (int i = 0; i < 20; i++) {
int k = i * 2;
int l = j * 2;
L4dungeon[k + 40][l] = dung[19 - i][j];
L4dungeon[k + 40][l + 1] = dung[19 - i][j];
L4dungeon[k + 41][l] = dung[19 - i][j];
L4dungeon[k + 41][l + 1] = dung[19 - i][j];
}
}
for (int j = 0; j < 20; j++) {
for (int i = 0; i < 20; i++) {
int k = i * 2;
int l = j * 2;
L4dungeon[k + 40][l + 40] = dung[19 - i][19 - j];
L4dungeon[k + 40][l + 41] = dung[19 - i][19 - j];
L4dungeon[k + 41][l + 40] = dung[19 - i][19 - j];
L4dungeon[k + 41][l + 41] = dung[19 - i][19 - j];
} }
} }
} }
void MakeDmt() void MakeDmt()
{ {
int dmty = 1; for (int y = 0; y < DMAXY - 1; y++) {
for (int j = 0; dmty <= 77; j++, dmty += 2) { for (int x = 0; x < DMAXX - 1; x++) {
int dmtx = 1; int val = (DungeonMask.test(x + 1, y + 1) << 3) | (DungeonMask.test(x, y + 1) << 2) | (DungeonMask.test(x + 1, y) << 1) | DungeonMask.test(x, y);
for (int i = 0; dmtx <= 77; i++, dmtx += 2) { dungeon[x][y] = L4ConvTbl[val];
int val = 8 * L4dungeon[dmtx + 1][dmty + 1]
+ 4 * L4dungeon[dmtx][dmty + 1]
+ 2 * L4dungeon[dmtx + 1][dmty]
+ L4dungeon[dmtx][dmty];
dungeon[i][j] = L4ConvTbl[val];
} }
} }
} }
@ -912,96 +846,85 @@ void Substitution()
void UShape() void UShape()
{ {
for (int j = 19; j >= 0; j--) { for (int y = DMAXY / 2 - 1; y >= 0; y--) {
for (int i = 19; i >= 0; i--) { for (int x = DMAXX / 2 - 1; x >= 0; x--) {
if (dung[i][j] != 1) { if (!DungeonMask.test(x, y)) {
hallok[j] = false; hallok[y] = false;
} } else {
if (dung[i][j] == 1) { hallok[y] = x + 1 < DMAXX / 2 && y + 1 < DMAXY / 2 && DungeonMask.test(x, y + 1) && !DungeonMask.test(x + 1, y + 1);
// BUGFIX: check that i + 1 < 20 and j + 1 < 20 (fixed) x = 0;
if (i + 1 < 20 && j + 1 < 20
&& dung[i][j + 1] == 1 && dung[i + 1][j + 1] == 0) {
hallok[j] = true;
} else {
hallok[j] = false;
}
i = 0;
} }
} }
} }
int rv = GenerateRnd(19) + 1; int ry = GenerateRnd(DMAXY / 2 - 1) + 1;
do { do {
if (hallok[rv]) { if (hallok[ry]) {
for (int i = 19; i >= 0; i--) { for (int x = DMAXX / 2 - 1; x >= 0; x--) {
if (dung[i][rv] == 1) { if (DungeonMask.test(x, ry)) {
i = -1; x = -1;
rv = 0; ry = 0;
} else { } else {
dung[i][rv] = 1; DungeonMask.set(x, ry);
dung[i][rv + 1] = 1; DungeonMask.set(x, ry + 1);
} }
} }
} else { } else {
rv++; ry++;
if (rv == 20) { if (ry == DMAXY / 2) {
rv = 1; ry = 1;
} }
} }
} while (rv != 0); } while (ry != 0);
for (int i = 19; i >= 0; i--) { for (int x = DMAXX / 2 - 1; x >= 0; x--) {
for (int j = 19; j >= 0; j--) { for (int y = DMAXY / 2 - 1; y >= 0; y--) {
if (dung[i][j] != 1) { if (!DungeonMask.test(x, y)) {
hallok[i] = false; hallok[x] = false;
} } else {
if (dung[i][j] == 1) { hallok[x] = x + 1 < DMAXX / 2 && y + 1 < DMAXY / 2 && DungeonMask.test(x + 1, y) && !DungeonMask.test(x + 1, y + 1);
// BUGFIX: check that i + 1 < 20 and j + 1 < 20 (fixed) y = 0;
if (i + 1 < 20 && j + 1 < 20
&& dung[i + 1][j] == 1 && dung[i + 1][j + 1] == 0) {
hallok[i] = true;
} else {
hallok[i] = false;
}
j = 0;
} }
} }
} }
rv = GenerateRnd(19) + 1; int rx = GenerateRnd(DMAXX / 2 - 1) + 1;
do { do {
if (hallok[rv]) { if (hallok[rx]) {
for (int j = 19; j >= 0; j--) { for (int y = DMAXY / 2 - 1; y >= 0; y--) {
if (dung[rv][j] == 1) { if (DungeonMask.test(rx, y)) {
j = -1; y = -1;
rv = 0; rx = 0;
} else { } else {
dung[rv][j] = 1; DungeonMask.set(rx, y);
dung[rv + 1][j] = 1; DungeonMask.set(rx + 1, y);
} }
} }
} else { } else {
rv++; rx++;
if (rv == 20) { if (rx == DMAXX / 2) {
rv = 1; rx = 1;
} }
} }
} while (rv != 0); } while (rx != 0);
} }
int GetArea() /**
* @brief Find the number of mega tiles used by layout
*/
int FindArea()
{ {
int rv = 0; int area = 0;
for (int j = 0; j < 20; j++) { for (int y = 0; y < DMAXY / 2; y++) {
for (int i = 0; i < 20; i++) { // NOLINT(modernize-loop-convert) for (int x = 0; x < DMAXX / 2; x++) { // NOLINT(modernize-loop-convert)
if (dung[i][j] == 1) { if (DungeonMask.test(x, y)) {
rv++; area++;
} }
} }
} }
return rv; return area * 4;
} }
void ProtectQuads() void ProtectQuads()
@ -1128,11 +1051,11 @@ void FixCornerTiles()
void FixRim() void FixRim()
{ {
for (int i = 0; i < 20; i++) { // NOLINT(modernize-loop-convert) for (int x = 0; x < DMAXX / 2; x++) { // NOLINT(modernize-loop-convert)
dung[i][0] = 0; DungeonMask.reset(x, 0);
} }
for (int j = 0; j < 20; j++) { for (int y = 0; y < DMAXY / 2; y++) {
dung[0][j] = 0; DungeonMask.reset(0, y);
} }
} }
@ -1201,12 +1124,12 @@ void GenerateLevel(lvl_entry entry)
while (true) { while (true) {
DRLG_InitTrans(); DRLG_InitTrans();
constexpr int Minarea = 173; constexpr int Minarea = 692;
do { do {
InitDungeonFlags(); InitDungeonFlags();
FirstRoom(); FirstRoom();
FixRim(); FixRim();
} while (GetArea() < Minarea); } while (FindArea() < Minarea);
UShape(); UShape();
MakeDungeon(); MakeDungeon();

1
Source/levels/gendung.cpp

@ -15,6 +15,7 @@
namespace devilution { namespace devilution {
Bitset2d<DMAXX, DMAXY> DungeonMask;
uint8_t dungeon[DMAXX][DMAXY]; uint8_t dungeon[DMAXX][DMAXY];
uint8_t pdungeon[DMAXX][DMAXY]; uint8_t pdungeon[DMAXX][DMAXY];
Bitset2d<DMAXX, DMAXY> Protected; Bitset2d<DMAXX, DMAXY> Protected;

2
Source/levels/gendung.h

@ -137,6 +137,8 @@ struct ShadowStruct {
uint8_t nv3; uint8_t nv3;
}; };
/** Reprecents what tiles are being utilized in the generated map. */
extern Bitset2d<DMAXX, DMAXY> DungeonMask;
/** Contains the tile IDs of the map. */ /** Contains the tile IDs of the map. */
extern DVL_API_FOR_TEST uint8_t dungeon[DMAXX][DMAXY]; extern DVL_API_FOR_TEST uint8_t dungeon[DMAXX][DMAXY];
/** Contains a backup of the tile IDs of the map. */ /** Contains a backup of the tile IDs of the map. */

Loading…
Cancel
Save