You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2482 lines
53 KiB
2482 lines
53 KiB
/** |
|
* @file drlg_l3.cpp |
|
* |
|
* Implementation of the caves level generation algorithms. |
|
*/ |
|
|
|
#include <algorithm> |
|
|
|
#include "engine/load_file.hpp" |
|
#include "engine/random.hpp" |
|
#include "gendung.h" |
|
#include "lighting.h" |
|
#include "monster.h" |
|
#include "objdat.h" |
|
#include "objects.h" |
|
#include "quests.h" |
|
#include "setmaps.h" |
|
|
|
namespace devilution { |
|
|
|
namespace { |
|
|
|
int lockoutcnt; |
|
bool lockout[DMAXX][DMAXY]; |
|
|
|
/** |
|
* A lookup table for the 16 possible patterns of a 2x2 area, |
|
* where each cell either contains a SW wall or it doesn't. |
|
*/ |
|
const BYTE L3ConvTbl[16] = { 8, 11, 3, 10, 1, 9, 12, 12, 6, 13, 4, 13, 2, 14, 5, 7 }; |
|
/** Miniset: Stairs up. */ |
|
const BYTE L3UP[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
8, 8, 0, // search |
|
10, 10, 0, |
|
7, 7, 0, |
|
|
|
51, 50, 0, // replace |
|
48, 49, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE L6UP[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
8, 8, 0, // search |
|
10, 10, 0, |
|
7, 7, 0, |
|
|
|
20, 19, 0, // replace |
|
17, 18, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stairs down. */ |
|
const BYTE L3DOWN[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
8, 9, 7, // search |
|
8, 9, 7, |
|
0, 0, 0, |
|
|
|
0, 47, 0, // replace |
|
0, 46, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE L6DOWN[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
8, 9, 7, // search |
|
8, 9, 7, |
|
0, 0, 0, |
|
|
|
0, 16, 0, // replace |
|
0, 15, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stairs up to town. */ |
|
const BYTE L3HOLDWARP[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
8, 8, 0, // search |
|
10, 10, 0, |
|
7, 7, 0, |
|
|
|
125, 125, 0, // replace |
|
125, 125, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE L6HOLDWARP[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
8, 8, 0, // search |
|
10, 10, 0, |
|
7, 7, 0, |
|
|
|
24, 23, 0, // replace |
|
21, 22, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite white stalactite 1. */ |
|
const BYTE L3TITE1[] = { |
|
// clang-format off |
|
4, 4, // width, height |
|
|
|
7, 7, 7, 7, // search |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
|
|
0, 0, 0, 0, // replace |
|
0, 57, 58, 0, |
|
0, 56, 55, 0, |
|
0, 0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite white stalactite 2. */ |
|
const BYTE L3TITE2[] = { |
|
// clang-format off |
|
4, 4, // width, height |
|
|
|
7, 7, 7, 7, // search |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
|
|
0, 0, 0, 0, // replace |
|
0, 61, 62, 0, |
|
0, 60, 59, 0, |
|
0, 0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite white stalactite 3. */ |
|
const BYTE L3TITE3[] = { |
|
// clang-format off |
|
4, 4, // width, height |
|
|
|
7, 7, 7, 7, // search |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
|
|
0, 0, 0, 0, // replace |
|
0, 65, 66, 0, |
|
0, 64, 63, 0, |
|
0, 0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite white stalactite horizontal. */ |
|
const BYTE L3TITE6[] = { |
|
// clang-format off |
|
5, 4, // width, height |
|
|
|
7, 7, 7, 7, 7, // search |
|
7, 7, 7, 0, 7, |
|
7, 7, 7, 0, 7, |
|
7, 7, 7, 7, 7, |
|
|
|
0, 0, 0, 0, 0, // replace |
|
0, 77, 78, 0, 0, |
|
0, 76, 74, 75, 0, |
|
0, 0, 0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite white stalactite vertical. */ |
|
const BYTE L3TITE7[] = { |
|
// clang-format off |
|
4, 5, // width, height |
|
|
|
7, 7, 7, 7, // search |
|
7, 7, 0, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
|
|
0, 0, 0, 0, // replace |
|
0, 83, 0, 0, |
|
0, 82, 80, 0, |
|
0, 81, 79, 0, |
|
0, 0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite 1. */ |
|
const BYTE L3TITE8[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
0, 0, 0, // replace |
|
0, 52, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite 2. */ |
|
const BYTE L3TITE9[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
0, 0, 0, // replace |
|
0, 53, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite 3. */ |
|
const BYTE L3TITE10[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
0, 0, 0, // replace |
|
0, 54, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite 4. */ |
|
const BYTE L3TITE11[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
0, 0, 0, // replace |
|
0, 67, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite on vertical wall. */ |
|
const BYTE L3TITE12[] = { |
|
// clang-format off |
|
2, 1, // width, height |
|
|
|
9, 7, // search |
|
|
|
68, 0, // replace |
|
// clang-format on |
|
}; |
|
/** Miniset: Stalagmite on horizontal wall. */ |
|
const BYTE L3TITE13[] = { |
|
// clang-format off |
|
1, 2, // width, height |
|
|
|
10, // search |
|
7, |
|
|
|
69, // replace |
|
0, |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked vertical wall 1. */ |
|
const BYTE L3CREV1[] = { |
|
// clang-format off |
|
2, 1, // width, height |
|
|
|
8, 7, // search |
|
|
|
84, 85, // replace |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked vertical wall - north corner. */ |
|
const BYTE L3CREV2[] = { |
|
// clang-format off |
|
2, 1, // width, height |
|
|
|
8, 11, // search |
|
|
|
86, 87, // replace |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked horizontal wall 1. */ |
|
const BYTE L3CREV3[] = { |
|
// clang-format off |
|
1, 2, // width, height |
|
|
|
8, // search |
|
10, |
|
|
|
89, // replace |
|
88, |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked vertical wall 2. */ |
|
const BYTE L3CREV4[] = { |
|
// clang-format off |
|
2, 1, // width, height |
|
|
|
8, 7, // search |
|
|
|
90, 91, // replace |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked horizontal wall - north corner. */ |
|
const BYTE L3CREV5[] = { |
|
// clang-format off |
|
1, 2, // width, height |
|
|
|
8, // search |
|
11, |
|
|
|
92, // replace |
|
93, |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked horizontal wall 2. */ |
|
const BYTE L3CREV6[] = { |
|
// clang-format off |
|
1, 2, // width, height |
|
|
|
8, // search |
|
10, |
|
|
|
95, // replace |
|
94, |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked vertical wall - west corner. */ |
|
const BYTE L3CREV7[] = { |
|
// clang-format off |
|
2, 1, // width, height |
|
|
|
8, 7, // search |
|
|
|
96, 101, // replace |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked horizontal wall - north. */ |
|
const BYTE L3CREV8[] = { |
|
// clang-format off |
|
1, 2, // width, height |
|
|
|
2, // search |
|
8, |
|
|
|
102, // replace |
|
97, |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked vertical wall - east corner. */ |
|
const BYTE L3CREV9[] = { |
|
// clang-format off |
|
2, 1, // width, height |
|
|
|
3, 8, // search |
|
|
|
103, 98, // replace |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked vertical wall - west. */ |
|
const BYTE L3CREV10[] = { |
|
// clang-format off |
|
2, 1, // width, height |
|
|
|
4, 8, // search |
|
|
|
104, 99, // replace |
|
// clang-format on |
|
}; |
|
/** Miniset: Cracked horizontal wall - south corner. */ |
|
const BYTE L3CREV11[] = { |
|
// clang-format off |
|
1, 2, // width, height |
|
|
|
6, // search |
|
8, |
|
|
|
105, // replace |
|
100, |
|
// clang-format on |
|
}; |
|
/** Miniset: Replace broken wall with floor 1. */ |
|
const BYTE L3ISLE1[] = { |
|
// clang-format off |
|
2, 3, // width, height |
|
|
|
5, 14, // search |
|
4, 9, |
|
13, 12, |
|
|
|
7, 7, // replace |
|
7, 7, |
|
7, 7, |
|
// clang-format on |
|
}; |
|
/** Miniset: Replace small wall with floor 2. */ |
|
const BYTE L3ISLE2[] = { |
|
// clang-format off |
|
3, 2, // width, height |
|
|
|
5, 2, 14, // search |
|
13, 10, 12, |
|
|
|
7, 7, 7, // replace |
|
7, 7, 7, |
|
// clang-format on |
|
}; |
|
/** Miniset: Replace small wall with lava 1. */ |
|
const BYTE L3ISLE3[] = { |
|
// clang-format off |
|
2, 3, // width, height |
|
|
|
5, 14, // search |
|
4, 9, |
|
13, 12, |
|
|
|
29, 30, // replace |
|
25, 28, |
|
31, 32, |
|
// clang-format on |
|
}; |
|
/** Miniset: Replace small wall with lava 2. */ |
|
const BYTE L3ISLE4[] = { |
|
// clang-format off |
|
3, 2, // width, height |
|
|
|
5, 2, 14, // search |
|
13, 10, 12, |
|
|
|
29, 26, 30, // replace |
|
31, 27, 32, |
|
// clang-format on |
|
}; |
|
/** Miniset: Replace small wall with floor 3. */ |
|
const BYTE L3ISLE5[] = { |
|
// clang-format off |
|
2, 2, // width, height |
|
|
|
5, 14, // search |
|
13, 12, |
|
|
|
7, 7, // replace |
|
7, 7, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern9[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
0, 0, 0, // replace |
|
0, 126, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern10[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
0, 0, 0, // replace |
|
0, 124, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern29[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
67, 0, 0, // replace |
|
66, 51, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern30[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
69, 0, 0, // replace |
|
68, 52, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern31[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
70, 0, 0, // replace |
|
71, 53, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern32[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
73, 0, 0, // replace |
|
72, 54, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern33[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
75, 0, 0, // replace |
|
74, 55, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern34[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
77, 0, 0, // replace |
|
76, 56, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern35[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
79, 0, 0, // replace |
|
78, 57, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern36[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
81, 0, 0, // replace |
|
80, 58, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern37[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
83, 0, 0, // replace |
|
82, 59, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern38[] = { |
|
// clang-format off |
|
3, 3, // width, height |
|
|
|
7, 7, 7, // search |
|
7, 7, 7, |
|
7, 7, 7, |
|
|
|
84, 0, 0, // replace |
|
85, 60, 0, |
|
0, 0, 0, |
|
// clang-format on |
|
}; |
|
const BYTE L6ISLE1[] = { |
|
// clang-format off |
|
2, 3, // width, height |
|
|
|
5, 14, // search |
|
4, 9, |
|
13, 12, |
|
|
|
7, 7, // replace |
|
7, 7, |
|
7, 7, |
|
// clang-format on |
|
}; |
|
const BYTE L6ISLE2[] = { |
|
// clang-format off |
|
3, 2, // width, height |
|
|
|
5, 2, 14, // search |
|
13, 10, 12, |
|
|
|
7, 7, 7, // replace |
|
7, 7, 7, |
|
// clang-format on |
|
}; |
|
const BYTE L6ISLE3[] = { |
|
// clang-format off |
|
2, 3, // width, height |
|
|
|
5, 14, // search |
|
4, 9, |
|
13, 12, |
|
|
|
107, 115, // replace |
|
119, 122, |
|
131, 123, |
|
// clang-format on |
|
}; |
|
const BYTE L6ISLE4[] = { |
|
// clang-format off |
|
3, 2, // width, height |
|
|
|
5, 2, 14, // search |
|
13, 10, 12, |
|
|
|
107, 120, 115, // replace |
|
131, 121, 123, |
|
// clang-format on |
|
}; |
|
const BYTE L6ISLE5[] = { |
|
// clang-format off |
|
2, 2, // width, height |
|
|
|
5, 14, // search |
|
13, 12, |
|
|
|
7, 7, // replace |
|
7, 7, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern39[] = { |
|
// clang-format off |
|
4, 4, // width, height |
|
|
|
7, 7, 7, 7, // search |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
|
|
7, 7, 7, 7, // replace |
|
7, 107, 115, 7, |
|
7, 131, 123, 7, |
|
7, 7, 7, 7, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern40[] = { |
|
// clang-format off |
|
4, 4, // width, height |
|
|
|
7, 7, 7, 7, // search |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
|
|
7, 7, 7, 7, // replace |
|
7, 7, 108, 7, |
|
7, 109, 112, 7, |
|
7, 7, 7, 7, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern41[] = { |
|
// clang-format off |
|
4, 5, // width, height |
|
|
|
7, 7, 7, 7, // search |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
|
|
7, 7, 7, 7, // replace |
|
7, 107, 115, 7, |
|
7, 119, 122, 7, |
|
7, 131, 123, 7, |
|
7, 7, 7, 7, |
|
// clang-format on |
|
}; |
|
const BYTE HivePattern42[] = { |
|
// clang-format off |
|
4, 5, // width, height |
|
|
|
7, 7, 7, 7, // search |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
7, 7, 7, 7, |
|
|
|
7, 7, 7, 7, // replace |
|
7, 126, 108, 7, |
|
7, 7, 117, 7, |
|
7, 109, 112, 7, |
|
7, 7, 7, 7, |
|
// clang-format on |
|
}; |
|
|
|
void InitDungeonFlags() |
|
{ |
|
memset(dungeon, 0, sizeof(dungeon)); |
|
memset(Protected, 0, sizeof(Protected)); |
|
} |
|
|
|
bool FillRoom(int x1, int y1, int x2, int y2) |
|
{ |
|
if (x1 <= 1 || x2 >= 34 || y1 <= 1 || y2 >= 38) { |
|
return false; |
|
} |
|
|
|
int v = 0; |
|
for (int j = y1; j <= y2; j++) { |
|
for (int i = x1; i <= x2; i++) { |
|
v += dungeon[i][j]; |
|
} |
|
} |
|
|
|
if (v != 0) { |
|
return false; |
|
} |
|
|
|
for (int j = y1 + 1; j < y2; j++) { |
|
for (int i = x1 + 1; i < x2; i++) { |
|
dungeon[i][j] = 1; |
|
} |
|
} |
|
for (int j = y1; j <= y2; j++) { |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[x1][j] = 1; |
|
} |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[x2][j] = 1; |
|
} |
|
} |
|
for (int i = x1; i <= x2; i++) { |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[i][y1] = 1; |
|
} |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[i][y2] = 1; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void CreateBlock(int x, int y, int obs, int dir) |
|
{ |
|
int x1; |
|
int y1; |
|
int x2; |
|
int y2; |
|
|
|
int blksizex = GenerateRnd(2) + 3; |
|
int blksizey = GenerateRnd(2) + 3; |
|
|
|
if (dir == 0) { |
|
y2 = y - 1; |
|
y1 = y2 - blksizey; |
|
if (blksizex < obs) { |
|
x1 = GenerateRnd(blksizex) + x; |
|
} |
|
if (blksizex == obs) { |
|
x1 = x; |
|
} |
|
if (blksizex > obs) { |
|
x1 = x - GenerateRnd(blksizex); |
|
} |
|
x2 = blksizex + x1; |
|
} |
|
if (dir == 1) { |
|
x1 = x + 1; |
|
x2 = x1 + blksizex; |
|
if (blksizey < obs) { |
|
y1 = GenerateRnd(blksizey) + y; |
|
} |
|
if (blksizey == obs) { |
|
y1 = y; |
|
} |
|
if (blksizey > obs) { |
|
y1 = y - GenerateRnd(blksizey); |
|
} |
|
y2 = y1 + blksizey; |
|
} |
|
if (dir == 2) { |
|
y1 = y + 1; |
|
y2 = y1 + blksizey; |
|
if (blksizex < obs) { |
|
x1 = GenerateRnd(blksizex) + x; |
|
} |
|
if (blksizex == obs) { |
|
x1 = x; |
|
} |
|
if (blksizex > obs) { |
|
x1 = x - GenerateRnd(blksizex); |
|
} |
|
x2 = blksizex + x1; |
|
} |
|
if (dir == 3) { |
|
x2 = x - 1; |
|
x1 = x2 - blksizex; |
|
if (blksizey < obs) { |
|
y1 = GenerateRnd(blksizey) + y; |
|
} |
|
if (blksizey == obs) { |
|
y1 = y; |
|
} |
|
if (blksizey > obs) { |
|
y1 = y - GenerateRnd(blksizey); |
|
} |
|
y2 = y1 + blksizey; |
|
} |
|
|
|
if (FillRoom(x1, y1, x2, y2)) { |
|
int contflag = GenerateRnd(4); |
|
if (contflag != 0 && dir != 2) { |
|
CreateBlock(x1, y1, blksizey, 0); |
|
} |
|
if (contflag != 0 && dir != 3) { |
|
CreateBlock(x2, y1, blksizex, 1); |
|
} |
|
if (contflag != 0 && dir != 0) { |
|
CreateBlock(x1, y2, blksizey, 2); |
|
} |
|
if (contflag != 0 && dir != 1) { |
|
CreateBlock(x1, y1, blksizex, 3); |
|
} |
|
} |
|
} |
|
|
|
void FloorArea(int x1, int y1, int x2, int y2) |
|
{ |
|
for (int j = y1; j <= y2; j++) { |
|
for (int i = x1; i <= x2; i++) { |
|
dungeon[i][j] = 1; |
|
} |
|
} |
|
} |
|
|
|
void FillDiagonals() |
|
{ |
|
for (int j = 0; j < DMAXY - 1; j++) { |
|
for (int i = 0; i < DMAXX - 1; i++) { |
|
int v = dungeon[i + 1][j + 1] + 2 * dungeon[i][j + 1] + 4 * dungeon[i + 1][j] + 8 * dungeon[i][j]; |
|
if (v == 6) { |
|
if (GenerateRnd(2) == 0) { |
|
dungeon[i][j] = 1; |
|
} else { |
|
dungeon[i + 1][j + 1] = 1; |
|
} |
|
} |
|
if (v == 9) { |
|
if (GenerateRnd(2) == 0) { |
|
dungeon[i + 1][j] = 1; |
|
} else { |
|
dungeon[i][j + 1] = 1; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void FillSingles() |
|
{ |
|
for (int j = 1; j < DMAXY - 1; j++) { |
|
for (int i = 1; i < DMAXX - 1; i++) { |
|
if (dungeon[i][j] == 0 |
|
&& dungeon[i][j - 1] + dungeon[i - 1][j - 1] + dungeon[i + 1][j - 1] == 3 |
|
&& dungeon[i + 1][j] + dungeon[i - 1][j] == 2 |
|
&& dungeon[i][j + 1] + dungeon[i - 1][j + 1] + dungeon[i + 1][j + 1] == 3) { |
|
dungeon[i][j] = 1; |
|
} |
|
} |
|
} |
|
} |
|
|
|
void FillStraights() |
|
{ |
|
int xc; |
|
int yc; |
|
|
|
for (int j = 0; j < DMAXY - 1; j++) { |
|
int xs = 0; |
|
for (int i = 0; i < 37; i++) { |
|
if (dungeon[i][j] == 0 && dungeon[i][j + 1] == 1) { |
|
if (xs == 0) { |
|
xc = i; |
|
} |
|
xs++; |
|
} else { |
|
if (xs > 3 && GenerateRnd(2) != 0) { |
|
for (int k = xc; k < i; k++) { |
|
int rv = GenerateRnd(2); |
|
dungeon[k][j] = rv; |
|
} |
|
} |
|
xs = 0; |
|
} |
|
} |
|
} |
|
for (int j = 0; j < DMAXY - 1; j++) { |
|
int xs = 0; |
|
for (int i = 0; i < 37; i++) { |
|
if (dungeon[i][j] == 1 && dungeon[i][j + 1] == 0) { |
|
if (xs == 0) { |
|
xc = i; |
|
} |
|
xs++; |
|
} else { |
|
if (xs > 3 && GenerateRnd(2) != 0) { |
|
for (int k = xc; k < i; k++) { |
|
int rv = GenerateRnd(2); |
|
dungeon[k][j + 1] = rv; |
|
} |
|
} |
|
xs = 0; |
|
} |
|
} |
|
} |
|
for (int i = 0; i < DMAXX - 1; i++) { |
|
int ys = 0; |
|
for (int j = 0; j < 37; j++) { |
|
if (dungeon[i][j] == 0 && dungeon[i + 1][j] == 1) { |
|
if (ys == 0) { |
|
yc = j; |
|
} |
|
ys++; |
|
} else { |
|
if (ys > 3 && GenerateRnd(2) != 0) { |
|
for (int k = yc; k < j; k++) { |
|
int rv = GenerateRnd(2); |
|
dungeon[i][k] = rv; |
|
} |
|
} |
|
ys = 0; |
|
} |
|
} |
|
} |
|
for (int i = 0; i < DMAXX - 1; i++) { |
|
int ys = 0; |
|
for (int j = 0; j < 37; j++) { |
|
if (dungeon[i][j] == 1 && dungeon[i + 1][j] == 0) { |
|
if (ys == 0) { |
|
yc = j; |
|
} |
|
ys++; |
|
} else { |
|
if (ys > 3 && GenerateRnd(2) != 0) { |
|
for (int k = yc; k < j; k++) { |
|
int rv = GenerateRnd(2); |
|
dungeon[i + 1][k] = rv; |
|
} |
|
} |
|
ys = 0; |
|
} |
|
} |
|
} |
|
} |
|
|
|
void Edges() |
|
{ |
|
for (int j = 0; j < DMAXY; j++) { |
|
dungeon[DMAXX - 1][j] = 0; |
|
} |
|
for (int i = 0; i < DMAXX; i++) { // NOLINT(modernize-loop-convert) |
|
dungeon[i][DMAXY - 1] = 0; |
|
} |
|
} |
|
|
|
int GetFloorArea() |
|
{ |
|
int gfa = 0; |
|
|
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { // NOLINT(modernize-loop-convert) |
|
gfa += dungeon[i][j]; |
|
} |
|
} |
|
|
|
return gfa; |
|
} |
|
|
|
void MakeMegas() |
|
{ |
|
for (int j = 0; j < DMAXY - 1; j++) { |
|
for (int i = 0; i < DMAXX - 1; i++) { |
|
int v = dungeon[i + 1][j + 1] + 2 * dungeon[i][j + 1] + 4 * dungeon[i + 1][j] + 8 * dungeon[i][j]; |
|
if (v == 6) { |
|
int rv = GenerateRnd(2); |
|
if (rv == 0) { |
|
v = 12; |
|
} else { |
|
v = 5; |
|
} |
|
} |
|
if (v == 9) { |
|
int rv = GenerateRnd(2); |
|
if (rv == 0) { |
|
v = 13; |
|
} else { |
|
v = 14; |
|
} |
|
} |
|
dungeon[i][j] = L3ConvTbl[v]; |
|
} |
|
dungeon[DMAXX - 1][j] = 8; |
|
} |
|
for (int i = 0; i < DMAXX; i++) { // NOLINT(modernize-loop-convert) |
|
dungeon[i][DMAXY - 1] = 8; |
|
} |
|
} |
|
|
|
void River() |
|
{ |
|
int dir; |
|
int nodir; |
|
int river[3][100]; |
|
int riveramt; |
|
|
|
int rivercnt = 0; |
|
int trys = 0; |
|
/// BUGFIX: pdir is uninitialized, add code `pdir = -1;`(fixed) |
|
int pdir = -1; |
|
|
|
while (trys < 200 && rivercnt < 4) { |
|
bool bail = false; |
|
while (!bail && trys < 200) { |
|
trys++; |
|
int rx = 0; |
|
int ry = 0; |
|
int i = 0; |
|
// BUGFIX: Replace with `(ry >= DMAXY || dungeon[rx][ry] < 25 || dungeon[rx][ry] > 28) && i < 100` (fixed) |
|
while ((ry >= DMAXY || dungeon[rx][ry] < 25 || dungeon[rx][ry] > 28) && i < 100) { |
|
rx = GenerateRnd(DMAXX); |
|
ry = GenerateRnd(DMAXY); |
|
i++; |
|
// BUGFIX: Move `ry < DMAXY` check before dungeon checks (fixed) |
|
while (ry < DMAXY && (dungeon[rx][ry] < 25 || dungeon[rx][ry] > 28)) { |
|
rx++; |
|
if (rx >= DMAXX) { |
|
rx = 0; |
|
ry++; |
|
} |
|
} |
|
} |
|
// BUGFIX: Continue if `ry >= DMAXY` (fixed) |
|
if (ry >= DMAXY) |
|
continue; |
|
if (i >= 100) { |
|
return; |
|
} |
|
switch (dungeon[rx][ry]) { |
|
case 25: |
|
dir = 3; |
|
nodir = 2; |
|
river[2][0] = 40; |
|
break; |
|
case 26: |
|
dir = 0; |
|
nodir = 1; |
|
river[2][0] = 38; |
|
break; |
|
case 27: |
|
dir = 1; |
|
nodir = 0; |
|
river[2][0] = 41; |
|
break; |
|
case 28: |
|
dir = 2; |
|
nodir = 3; |
|
river[2][0] = 39; |
|
break; |
|
} |
|
river[0][0] = rx; |
|
river[1][0] = ry; |
|
riveramt = 1; |
|
int nodir2 = 4; |
|
int dircheck = 0; |
|
while (dircheck < 4 && riveramt < 100) { |
|
int px = rx; |
|
int py = ry; |
|
if (dircheck == 0) { |
|
dir = GenerateRnd(4); |
|
} else { |
|
dir = (dir + 1) & 3; |
|
} |
|
dircheck++; |
|
while (dir == nodir || dir == nodir2) { |
|
dir = (dir + 1) & 3; |
|
dircheck++; |
|
} |
|
if (dir == 0 && ry > 0) { |
|
ry--; |
|
} |
|
if (dir == 1 && ry < DMAXY) { |
|
ry++; |
|
} |
|
if (dir == 2 && rx < DMAXX) { |
|
rx++; |
|
} |
|
if (dir == 3 && rx > 0) { |
|
rx--; |
|
} |
|
if (dungeon[rx][ry] == 7) { |
|
dircheck = 0; |
|
if (dir < 2) { |
|
river[2][riveramt] = (BYTE)GenerateRnd(2) + 17; |
|
} |
|
if (dir > 1) { |
|
river[2][riveramt] = (BYTE)GenerateRnd(2) + 15; |
|
} |
|
river[0][riveramt] = rx; |
|
river[1][riveramt] = ry; |
|
riveramt++; |
|
if ((dir == 0 && pdir == 2) || (dir == 3 && pdir == 1)) { |
|
if (riveramt > 2) { |
|
river[2][riveramt - 2] = 22; |
|
} |
|
if (dir == 0) { |
|
nodir2 = 1; |
|
} else { |
|
nodir2 = 2; |
|
} |
|
} |
|
if ((dir == 0 && pdir == 3) || (dir == 2 && pdir == 1)) { |
|
if (riveramt > 2) { |
|
river[2][riveramt - 2] = 21; |
|
} |
|
if (dir == 0) { |
|
nodir2 = 1; |
|
} else { |
|
nodir2 = 3; |
|
} |
|
} |
|
if ((dir == 1 && pdir == 2) || (dir == 3 && pdir == 0)) { |
|
if (riveramt > 2) { |
|
river[2][riveramt - 2] = 20; |
|
} |
|
if (dir == 1) { |
|
nodir2 = 0; |
|
} else { |
|
nodir2 = 2; |
|
} |
|
} |
|
if ((dir == 1 && pdir == 3) || (dir == 2 && pdir == 0)) { |
|
if (riveramt > 2) { |
|
river[2][riveramt - 2] = 19; |
|
} |
|
if (dir == 1) { |
|
nodir2 = 0; |
|
} else { |
|
nodir2 = 3; |
|
} |
|
} |
|
pdir = dir; |
|
} else { |
|
rx = px; |
|
ry = py; |
|
} |
|
} |
|
// BUGFIX: Check `ry >= 2` (fixed) |
|
if (dir == 0 && ry >= 2 && dungeon[rx][ry - 1] == 10 && dungeon[rx][ry - 2] == 8) { |
|
river[0][riveramt] = rx; |
|
river[1][riveramt] = ry - 1; |
|
river[2][riveramt] = 24; |
|
if (pdir == 2) { |
|
river[2][riveramt - 1] = 22; |
|
} |
|
if (pdir == 3) { |
|
river[2][riveramt - 1] = 21; |
|
} |
|
bail = true; |
|
} |
|
// BUGFIX: Check `ry + 2 < DMAXY` (fixed) |
|
if (dir == 1 && ry + 2 < DMAXY && dungeon[rx][ry + 1] == 2 && dungeon[rx][ry + 2] == 8) { |
|
river[0][riveramt] = rx; |
|
river[1][riveramt] = ry + 1; |
|
river[2][riveramt] = 42; |
|
if (pdir == 2) { |
|
river[2][riveramt - 1] = 20; |
|
} |
|
if (pdir == 3) { |
|
river[2][riveramt - 1] = 19; |
|
} |
|
bail = true; |
|
} |
|
// BUGFIX: Check `rx + 2 < DMAXX` (fixed) |
|
if (dir == 2 && rx + 2 < DMAXX && dungeon[rx + 1][ry] == 4 && dungeon[rx + 2][ry] == 8) { |
|
river[0][riveramt] = rx + 1; |
|
river[1][riveramt] = ry; |
|
river[2][riveramt] = 43; |
|
if (pdir == 0) { |
|
river[2][riveramt - 1] = 19; |
|
} |
|
if (pdir == 1) { |
|
river[2][riveramt - 1] = 21; |
|
} |
|
bail = true; |
|
} |
|
// BUGFIX: Check `rx >= 2` (fixed) |
|
if (dir == 3 && rx >= 2 && dungeon[rx - 1][ry] == 9 && dungeon[rx - 2][ry] == 8) { |
|
river[0][riveramt] = rx - 1; |
|
river[1][riveramt] = ry; |
|
river[2][riveramt] = 23; |
|
if (pdir == 0) { |
|
river[2][riveramt - 1] = 20; |
|
} |
|
if (pdir == 1) { |
|
river[2][riveramt - 1] = 22; |
|
} |
|
bail = true; |
|
} |
|
} |
|
if (bail && riveramt < 7) { |
|
bail = false; |
|
} |
|
if (bail) { |
|
int found = 0; |
|
int lpcnt = 0; |
|
int bridge; |
|
while (found == 0 && lpcnt < 30) { |
|
lpcnt++; |
|
bridge = GenerateRnd(riveramt); |
|
if ((river[2][bridge] == 15 || river[2][bridge] == 16) |
|
&& dungeon[river[0][bridge]][river[1][bridge] - 1] == 7 |
|
&& dungeon[river[0][bridge]][river[1][bridge] + 1] == 7) { |
|
found = 1; |
|
} |
|
if ((river[2][bridge] == 17 || river[2][bridge] == 18) |
|
&& dungeon[river[0][bridge] - 1][river[1][bridge]] == 7 |
|
&& dungeon[river[0][bridge] + 1][river[1][bridge]] == 7) { |
|
found = 2; |
|
} |
|
for (int i = 0; i < riveramt && found != 0; i++) { |
|
if (found == 1 |
|
&& (river[1][bridge] - 1 == river[1][i] || river[1][bridge] + 1 == river[1][i]) |
|
&& river[0][bridge] == river[0][i]) { |
|
found = 0; |
|
} |
|
if (found == 2 |
|
&& (river[0][bridge] - 1 == river[0][i] || river[0][bridge] + 1 == river[0][i]) |
|
&& river[1][bridge] == river[1][i]) { |
|
found = 0; |
|
} |
|
} |
|
} |
|
if (found != 0) { |
|
if (found == 1) { |
|
river[2][bridge] = 44; |
|
} else { |
|
river[2][bridge] = 45; |
|
} |
|
rivercnt++; |
|
for (bridge = 0; bridge <= riveramt; bridge++) { |
|
dungeon[river[0][bridge]][river[1][bridge]] = river[2][bridge]; |
|
} |
|
} else { |
|
bail = false; |
|
} |
|
} |
|
} |
|
} |
|
|
|
bool Spawn(int x, int y, int *totarea); |
|
|
|
bool SpawnEdge(int x, int y, int *totarea) |
|
{ |
|
BYTE i; |
|
static BYTE spawntable[15] = { 0x00, 0x0A, 0x43, 0x05, 0x2c, 0x06, 0x09, 0x00, 0x00, 0x1c, 0x83, 0x06, 0x09, 0x0A, 0x05 }; |
|
|
|
if (*totarea > 40) { |
|
return true; |
|
} |
|
if (x < 0 || y < 0 || x >= DMAXX || y >= DMAXY) { |
|
return true; |
|
} |
|
if ((dungeon[x][y] & 0x80) != 0) { |
|
return false; |
|
} |
|
if (dungeon[x][y] > 15) { |
|
return true; |
|
} |
|
|
|
i = dungeon[x][y]; |
|
dungeon[x][y] |= 0x80; |
|
*totarea += 1; |
|
|
|
if ((spawntable[i] & 8) != 0 && SpawnEdge(x, y - 1, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 4) != 0 && SpawnEdge(x, y + 1, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 2) != 0 && SpawnEdge(x + 1, y, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 1) != 0 && SpawnEdge(x - 1, y, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 0x80) != 0 && Spawn(x, y - 1, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 0x40) != 0 && Spawn(x, y + 1, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 0x20) != 0 && Spawn(x + 1, y, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 0x10) != 0 && Spawn(x - 1, y, totarea)) { |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool Spawn(int x, int y, int *totarea) |
|
{ |
|
BYTE i; |
|
static BYTE spawntable[15] = { 0x00, 0x0A, 0x03, 0x05, 0x0C, 0x06, 0x09, 0x00, 0x00, 0x0C, 0x03, 0x06, 0x09, 0x0A, 0x05 }; |
|
|
|
if (*totarea > 40) { |
|
return true; |
|
} |
|
if (x < 0 || y < 0 || x >= DMAXX || y >= DMAXY) { |
|
return true; |
|
} |
|
if ((dungeon[x][y] & 0x80) != 0) { |
|
return false; |
|
} |
|
if (dungeon[x][y] > 15) { |
|
return true; |
|
} |
|
|
|
i = dungeon[x][y]; |
|
dungeon[x][y] |= 0x80; |
|
*totarea += 1; |
|
|
|
if (i != 8) { |
|
if ((spawntable[i] & 8) != 0 && SpawnEdge(x, y - 1, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 4) != 0 && SpawnEdge(x, y + 1, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 2) != 0 && SpawnEdge(x + 1, y, totarea)) { |
|
return true; |
|
} |
|
if ((spawntable[i] & 1) != 0 && SpawnEdge(x - 1, y, totarea)) { |
|
return true; |
|
} |
|
} else { |
|
if (Spawn(x + 1, y, totarea)) { |
|
return true; |
|
} |
|
if (Spawn(x - 1, y, totarea)) { |
|
return true; |
|
} |
|
if (Spawn(x, y + 1, totarea)) { |
|
return true; |
|
} |
|
if (Spawn(x, y - 1, totarea)) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool HivePlaceSetRandom(const BYTE *miniset, int rndper) |
|
{ |
|
bool placed = false; |
|
int sw = miniset[0]; |
|
int sh = miniset[1]; |
|
|
|
for (int sy = 0; sy < DMAXX - sh; sy++) { |
|
for (int sx = 0; sx < DMAXY - sw; sx++) { |
|
bool found = true; |
|
int ii = 2; |
|
for (int yy = 0; yy < sh && found; yy++) { |
|
for (int xx = 0; xx < sw && found; xx++) { |
|
if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { |
|
found = false; |
|
} |
|
if (Protected[xx + sx][yy + sy]) { |
|
found = false; |
|
} |
|
ii++; |
|
} |
|
} |
|
int kk = sw * sh + 2; |
|
if (found) { |
|
if (miniset[kk] >= 84 && miniset[kk] <= 100) { |
|
// BUGFIX: accesses to dungeon can go out of bounds |
|
// BUGFIX: Comparisons vs 100 should use same tile as comparisons vs 84. |
|
if (dungeon[sx - 1][sy] >= 84 && dungeon[sx - 1][sy] <= 100) { |
|
found = false; |
|
} |
|
if (dungeon[sx + 1][sy] >= 84 && dungeon[sx - 1][sy] <= 100) { |
|
found = false; |
|
} |
|
if (dungeon[sx][sy + 1] >= 84 && dungeon[sx - 1][sy] <= 100) { |
|
found = false; |
|
} |
|
if (dungeon[sx][sy - 1] >= 84 && dungeon[sx - 1][sy] <= 100) { |
|
found = false; |
|
} |
|
} |
|
} |
|
if (found && GenerateRnd(100) < rndper) { |
|
placed = true; |
|
for (int yy = 0; yy < sh; yy++) { |
|
for (int xx = 0; xx < sw; xx++) { |
|
if (miniset[kk] != 0) { |
|
dungeon[xx + sx][yy + sy] = miniset[kk]; |
|
} |
|
kk++; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
return placed; |
|
} |
|
|
|
bool PlaceSlimePool() |
|
{ |
|
int lavapool = 0; |
|
|
|
if (HivePlaceSetRandom(HivePattern41, 30)) |
|
lavapool++; |
|
if (HivePlaceSetRandom(HivePattern42, 40)) |
|
lavapool++; |
|
if (HivePlaceSetRandom(HivePattern39, 50)) |
|
lavapool++; |
|
if (HivePlaceSetRandom(HivePattern40, 60)) |
|
lavapool++; |
|
|
|
return lavapool >= 3; |
|
} |
|
|
|
/** |
|
* Flood fills dirt and wall tiles looking for |
|
* an area of at most 40 tiles and disconnected from the map edge. |
|
* If it finds one, converts it to lava tiles and return true. |
|
*/ |
|
bool PlaceLavaPool() |
|
{ |
|
constexpr uint8_t Poolsub[15] = { 0, 35, 26, 36, 25, 29, 34, 7, 33, 28, 27, 37, 32, 31, 30 }; |
|
|
|
bool lavePoolPlaced = false; |
|
|
|
for (int duny = 0; duny < DMAXY; duny++) { |
|
for (int dunx = 0; dunx < DMAXY; dunx++) { |
|
if (dungeon[dunx][duny] != 8) { |
|
continue; |
|
} |
|
dungeon[dunx][duny] |= 0x80; |
|
int totarea = 1; |
|
bool found = true; |
|
if (dunx + 1 < DMAXX) { |
|
found = Spawn(dunx + 1, duny, &totarea); |
|
} |
|
if (dunx - 1 > 0 && !found) { |
|
found = Spawn(dunx - 1, duny, &totarea); |
|
} else { |
|
found = true; |
|
} |
|
if (duny + 1 < DMAXY && !found) { |
|
found = Spawn(dunx, duny + 1, &totarea); |
|
} else { |
|
found = true; |
|
} |
|
if (duny - 1 > 0 && !found) { |
|
found = Spawn(dunx, duny - 1, &totarea); |
|
} else { |
|
found = true; |
|
} |
|
int poolchance = GenerateRnd(100); |
|
for (int j = std::max(duny - totarea, 0); j < std::min(duny + totarea, DMAXY); j++) { |
|
for (int i = std::max(dunx - totarea, 0); i < std::min(dunx + totarea, DMAXX); i++) { |
|
// BUGFIX: In the following swap the order to first do the |
|
// index checks and only then access dungeon[i][j] (fixed) |
|
if ((dungeon[i][j] & 0x80) != 0) { |
|
dungeon[i][j] &= ~0x80; |
|
if (totarea > 4 && poolchance < 25 && !found) { |
|
uint8_t k = Poolsub[dungeon[i][j]]; |
|
if (k != 0 && k <= 37) { |
|
dungeon[i][j] = k; |
|
} |
|
lavePoolPlaced = true; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
return lavePoolPlaced; |
|
} |
|
|
|
bool PlacePool() |
|
{ |
|
if (leveltype == DTYPE_NEST) { |
|
return PlaceSlimePool(); |
|
} |
|
|
|
return PlaceLavaPool(); |
|
} |
|
|
|
void PoolFix() |
|
{ |
|
for (int duny = 1; duny < DMAXY - 1; duny++) { // BUGFIX: Change '0' to '1' and 'DMAXY' to 'DMAXY - 1' (fixed) |
|
for (int dunx = 1; dunx < DMAXX - 1; dunx++) { // BUGFIX: Change '0' to '1' and 'DMAXX' to 'DMAXX - 1' (fixed) |
|
if (dungeon[dunx][duny] == 8) { |
|
if (dungeon[dunx - 1][duny - 1] >= 25 && dungeon[dunx - 1][duny - 1] <= 41 |
|
&& dungeon[dunx - 1][duny] >= 25 && dungeon[dunx - 1][duny] <= 41 |
|
&& dungeon[dunx - 1][duny + 1] >= 25 && dungeon[dunx - 1][duny + 1] <= 41 |
|
&& dungeon[dunx][duny - 1] >= 25 && dungeon[dunx][duny - 1] <= 41 |
|
&& dungeon[dunx][duny + 1] >= 25 && dungeon[dunx][duny + 1] <= 41 |
|
&& dungeon[dunx + 1][duny - 1] >= 25 && dungeon[dunx + 1][duny - 1] <= 41 |
|
&& dungeon[dunx + 1][duny] >= 25 && dungeon[dunx + 1][duny] <= 41 |
|
&& dungeon[dunx + 1][duny + 1] >= 25 && dungeon[dunx + 1][duny + 1] <= 41) { |
|
dungeon[dunx][duny] = 33; |
|
} else if (dungeon[dunx + 1][duny] == 35 || dungeon[dunx + 1][duny] == 37) { |
|
dungeon[dunx][duny] = 33; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
bool PlaceMiniSet(const BYTE *miniset, bool setview) |
|
{ |
|
int sw = miniset[0]; |
|
int sh = miniset[1]; |
|
int sx = GenerateRnd(DMAXX - sw) - 1; |
|
int sy = GenerateRnd(DMAXY - sh); |
|
|
|
for (int bailcnt = 0;; bailcnt++) { |
|
if (bailcnt > 198) |
|
return false; |
|
|
|
sx++; |
|
if (sx == DMAXX - sw) { |
|
sx = 0; |
|
sy++; |
|
if (sy == DMAXY - sh) { |
|
sy = 0; |
|
} |
|
} |
|
|
|
if (SetPiecesRoom.Contains({ sx, sy })) { |
|
continue; |
|
} |
|
|
|
int ii = 2; |
|
|
|
bool success = true; |
|
for (int yy = 0; yy < sh && success; yy++) { |
|
for (int xx = 0; xx < sw && success; xx++) { |
|
if (miniset[ii] != 0 && dungeon[xx + sx][sy + yy] != miniset[ii]) |
|
success = false; |
|
if (Protected[xx + sx][sy + yy]) |
|
success = false; |
|
ii++; |
|
} |
|
} |
|
if (success) |
|
break; |
|
} |
|
|
|
int ii = sw * sh + 2; |
|
|
|
for (int yy = 0; yy < sh; yy++) { |
|
for (int xx = 0; xx < sw; xx++) { |
|
if (miniset[ii] != 0) { |
|
dungeon[xx + sx][sy + yy] = miniset[ii]; |
|
} |
|
ii++; |
|
} |
|
} |
|
|
|
if (setview) { |
|
ViewPosition = Point { 17, 19 } + Displacement { sx, sy } * 2; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool CanReplaceTile(uint8_t replace, Point tile) |
|
{ |
|
if (replace < 84 || replace > 100) { |
|
return true; |
|
} |
|
|
|
// BUGFIX: p2 is a workaround for a bug, only p1 should have been used (fixing this breaks compatability) |
|
constexpr auto ComparisonWithBoundsCheck = [](Point p1, Point p2) { |
|
return (p1.x >= 0 && p1.x < DMAXX && p1.y >= 0 && p1.y < DMAXY) |
|
&& (p2.x >= 0 && p2.x < DMAXX && p2.y >= 0 && p2.y < DMAXY) |
|
&& (dungeon[p1.x][p1.y] >= 84 && dungeon[p2.x][p2.y] <= 100); |
|
}; |
|
if (ComparisonWithBoundsCheck(tile + Direction::NorthWest, tile + Direction::NorthWest) |
|
|| ComparisonWithBoundsCheck(tile + Direction::SouthEast, tile + Direction::NorthWest) |
|
|| ComparisonWithBoundsCheck(tile + Direction::SouthWest, tile + Direction::NorthWest) |
|
|| ComparisonWithBoundsCheck(tile + Direction::NorthEast, tile + Direction::NorthWest)) { |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void PlaceMiniSetRandom(const BYTE *miniset, int rndper) |
|
{ |
|
int sw = miniset[0]; |
|
int sh = miniset[1]; |
|
|
|
for (int sy = 0; sy < DMAXX - sh; sy++) { |
|
for (int sx = 0; sx < DMAXY - sw; sx++) { |
|
bool found = true; |
|
int ii = 2; |
|
for (int yy = 0; yy < sh && found; yy++) { |
|
for (int xx = 0; xx < sw && found; xx++) { |
|
if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { |
|
found = false; |
|
} |
|
if (Protected[xx + sx][yy + sy]) { |
|
found = false; |
|
} |
|
ii++; |
|
} |
|
} |
|
if (!found) |
|
continue; |
|
int kk = sw * sh + 2; |
|
if (!CanReplaceTile(miniset[kk], { sx, sy })) |
|
continue; |
|
if (GenerateRnd(100) >= rndper) |
|
continue; |
|
for (int yy = 0; yy < sh; yy++) { |
|
for (int xx = 0; xx < sw; xx++) { |
|
if (miniset[kk] != 0) { |
|
dungeon[xx + sx][yy + sy] = miniset[kk]; |
|
} |
|
kk++; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void PlaceMiniSetRandom1x1(uint8_t search, uint8_t replace, int rndper) |
|
{ |
|
uint8_t miniSet[4] { 1, 1, search, replace }; |
|
PlaceMiniSetRandom(miniSet, rndper); |
|
} |
|
|
|
bool FenceVerticalUp(int i, int y) |
|
{ |
|
if ((dungeon[i + 1][y] > 152 || dungeon[i + 1][y] < 130) |
|
&& (dungeon[i - 1][y] > 152 || dungeon[i - 1][y] < 130)) { |
|
if (IsAnyOf(dungeon[i][y], 7, 10, 126, 129, 134, 136)) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool FenceVerticalDown(int i, int y) |
|
{ |
|
if ((dungeon[i + 1][y] > 152 || dungeon[i + 1][y] < 130) |
|
&& (dungeon[i - 1][y] > 152 || dungeon[i - 1][y] < 130)) { |
|
if (IsAnyOf(dungeon[i][y], 2, 7, 134, 136)) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool FenceHorizontalLeft(int x, int j) |
|
{ |
|
if ((dungeon[x][j + 1] > 152 || dungeon[x][j + 1] < 130) |
|
&& (dungeon[x][j - 1] > 152 || dungeon[x][j - 1] < 130)) { |
|
if (IsAnyOf(dungeon[x][j], 7, 9, 121, 124, 135, 137)) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool FenceHorizontalRight(int x, int j) |
|
{ |
|
if ((dungeon[x][j + 1] > 152 || dungeon[x][j + 1] < 130) |
|
&& (dungeon[x][j - 1] > 152 || dungeon[x][j - 1] < 130)) { |
|
if (IsAnyOf(dungeon[x][j], 4, 7, 135, 137)) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void AddFenceDoors() |
|
{ |
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { |
|
if (dungeon[i][j] == 7) { |
|
if (dungeon[i - 1][j] <= 152 && dungeon[i - 1][j] >= 130 |
|
&& dungeon[i + 1][j] <= 152 && dungeon[i + 1][j] >= 130) { |
|
dungeon[i][j] = 146; |
|
continue; |
|
} |
|
} |
|
if (dungeon[i][j] == 7) { |
|
if (dungeon[i][j - 1] <= 152 && dungeon[i][j - 1] >= 130 |
|
&& dungeon[i][j + 1] <= 152 && dungeon[i][j + 1] >= 130) { |
|
dungeon[i][j] = 147; |
|
continue; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void FenceDoorFix() |
|
{ |
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { |
|
if (dungeon[i][j] == 146) { |
|
if (dungeon[i + 1][j] > 152 || dungeon[i + 1][j] < 130 |
|
|| dungeon[i - 1][j] > 152 || dungeon[i - 1][j] < 130) { |
|
dungeon[i][j] = 7; |
|
continue; |
|
} |
|
} |
|
if (dungeon[i][j] == 146) { |
|
if (IsNoneOf(dungeon[i + 1][j], 130, 132, 133, 134, 136, 138, 140) && IsNoneOf(dungeon[i - 1][j], 130, 132, 133, 134, 136, 138, 140)) { |
|
dungeon[i][j] = 7; |
|
continue; |
|
} |
|
} |
|
if (dungeon[i][j] == 147) { |
|
if (dungeon[i][j + 1] > 152 || dungeon[i][j + 1] < 130 |
|
|| dungeon[i][j - 1] > 152 || dungeon[i][j - 1] < 130) { |
|
dungeon[i][j] = 7; |
|
continue; |
|
} |
|
} |
|
if (dungeon[i][j] == 147) { |
|
if (IsNoneOf(dungeon[i][j + 1], 131, 132, 133, 135, 137, 138, 139) && IsNoneOf(dungeon[i][j - 1], 131, 132, 133, 135, 137, 138, 139)) { |
|
dungeon[i][j] = 7; |
|
continue; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void Fence() |
|
{ |
|
for (int j = 1; j < DMAXY - 1; j++) { // BUGFIX: Change '0' to '1' (fixed) |
|
for (int i = 1; i < DMAXX - 1; i++) { // BUGFIX: Change '0' to '1' (fixed) |
|
if (dungeon[i][j] == 10 && GenerateRnd(2) != 0) { |
|
int x = i; |
|
while (dungeon[x][j] == 10) { |
|
x++; |
|
} |
|
x--; |
|
if (x - i > 0) { |
|
dungeon[i][j] = 127; |
|
for (int xx = i + 1; xx < x; xx++) { |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[xx][j] = 126; |
|
} else { |
|
dungeon[xx][j] = 129; |
|
} |
|
} |
|
dungeon[x][j] = 128; |
|
} |
|
} |
|
if (dungeon[i][j] == 9 && GenerateRnd(2) != 0) { |
|
int y = j; |
|
while (dungeon[i][y] == 9) { |
|
y++; |
|
} |
|
y--; |
|
if (y - j > 0) { |
|
dungeon[i][j] = 123; |
|
for (int yy = j + 1; yy < y; yy++) { |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[i][yy] = 121; |
|
} else { |
|
dungeon[i][yy] = 124; |
|
} |
|
} |
|
dungeon[i][y] = 122; |
|
} |
|
} |
|
if (dungeon[i][j] == 11 && dungeon[i + 1][j] == 10 && dungeon[i][j + 1] == 9 && GenerateRnd(2) != 0) { |
|
dungeon[i][j] = 125; |
|
int x = i + 1; |
|
while (dungeon[x][j] == 10) { |
|
x++; |
|
} |
|
x--; |
|
for (int xx = i + 1; xx < x; xx++) { |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[xx][j] = 126; |
|
} else { |
|
dungeon[xx][j] = 129; |
|
} |
|
} |
|
dungeon[x][j] = 128; |
|
int y = j + 1; |
|
while (dungeon[i][y] == 9) { |
|
y++; |
|
} |
|
y--; |
|
for (int yy = j + 1; yy < y; yy++) { |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[i][yy] = 121; |
|
} else { |
|
dungeon[i][yy] = 124; |
|
} |
|
} |
|
dungeon[i][y] = 122; |
|
} |
|
} |
|
} |
|
|
|
for (int j = 1; j < DMAXY; j++) { // BUGFIX: Change '0' to '1' (fixed) |
|
for (int i = 1; i < DMAXX; i++) { // BUGFIX: Change '0' to '1' (fixed) |
|
if (dungeon[i][j] == 7 && GenerateRnd(1) == 0 && SkipThemeRoom(i, j)) { |
|
int rt = GenerateRnd(2); |
|
if (rt == 0) { |
|
int y1 = j; |
|
// BUGFIX: Check `y1 >= 0` first (fixed) |
|
while (y1 >= 0 && FenceVerticalUp(i, y1)) { |
|
y1--; |
|
} |
|
y1++; |
|
int y2 = j; |
|
// BUGFIX: Check `y2 < DMAXY` first (fixed) |
|
while (y2 < DMAXY && FenceVerticalDown(i, y2)) { |
|
y2++; |
|
} |
|
y2--; |
|
bool skip = true; |
|
if (dungeon[i][y1] == 7) { |
|
skip = false; |
|
} |
|
if (dungeon[i][y2] == 7) { |
|
skip = false; |
|
} |
|
if (y2 - y1 > 1 && skip) { |
|
int rp = GenerateRnd(y2 - y1 - 1) + y1 + 1; |
|
for (int y = y1; y <= y2; y++) { |
|
if (y == rp) { |
|
continue; |
|
} |
|
if (dungeon[i][y] == 7) { |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[i][y] = 135; |
|
} else { |
|
dungeon[i][y] = 137; |
|
} |
|
} |
|
if (dungeon[i][y] == 10) { |
|
dungeon[i][y] = 131; |
|
} |
|
if (dungeon[i][y] == 126) { |
|
dungeon[i][y] = 133; |
|
} |
|
if (dungeon[i][y] == 129) { |
|
dungeon[i][y] = 133; |
|
} |
|
if (dungeon[i][y] == 2) { |
|
dungeon[i][y] = 139; |
|
} |
|
if (dungeon[i][y] == 134) { |
|
dungeon[i][y] = 138; |
|
} |
|
if (dungeon[i][y] == 136) { |
|
dungeon[i][y] = 138; |
|
} |
|
} |
|
} |
|
} |
|
if (rt == 1) { |
|
int x1 = i; |
|
// BUGFIX: Check `x1 >= 0` first (fixed) |
|
while (x1 >= 0 && FenceHorizontalLeft(x1, j)) { |
|
x1--; |
|
} |
|
x1++; |
|
int x2 = i; |
|
// BUGFIX: Check `x2 < DMAXX` first (fixed) |
|
while (x2 < DMAXX && FenceHorizontalRight(x2, j)) { |
|
x2++; |
|
} |
|
x2--; |
|
bool skip = true; |
|
if (dungeon[x1][j] == 7) { |
|
skip = false; |
|
} |
|
if (dungeon[x2][j] == 7) { |
|
skip = false; |
|
} |
|
if (x2 - x1 > 1 && skip) { |
|
int rp = GenerateRnd(x2 - x1 - 1) + x1 + 1; |
|
for (int x = x1; x <= x2; x++) { |
|
if (x == rp) { |
|
continue; |
|
} |
|
if (dungeon[x][j] == 7) { |
|
if (GenerateRnd(2) != 0) { |
|
dungeon[x][j] = 134; |
|
} else { |
|
dungeon[x][j] = 136; |
|
} |
|
} |
|
if (dungeon[x][j] == 9) { |
|
dungeon[x][j] = 130; |
|
} |
|
if (dungeon[x][j] == 121) { |
|
dungeon[x][j] = 132; |
|
} |
|
if (dungeon[x][j] == 124) { |
|
dungeon[x][j] = 132; |
|
} |
|
if (dungeon[x][j] == 4) { |
|
dungeon[x][j] = 140; |
|
} |
|
if (dungeon[x][j] == 135) { |
|
dungeon[x][j] = 138; |
|
} |
|
if (dungeon[x][j] == 137) { |
|
dungeon[x][j] = 138; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
AddFenceDoors(); |
|
FenceDoorFix(); |
|
} |
|
|
|
bool PlaceAnvil() |
|
{ |
|
auto dunData = LoadFileInMem<uint16_t>("Levels\\L3Data\\Anvil.DUN"); |
|
int width = SDL_SwapLE16(dunData[0]); |
|
int height = SDL_SwapLE16(dunData[1]); |
|
int sx = GenerateRnd(DMAXX - width - 2) - 1; |
|
int sy = GenerateRnd(DMAXY - height - 2); |
|
|
|
for (int trys = 0;; trys++) { |
|
if (trys > 198) |
|
return false; |
|
|
|
sx++; |
|
if (sx == DMAXX - width - 2) { |
|
sx = 0; |
|
sy++; |
|
if (sy == DMAXY - height - 2) { |
|
sy = 0; |
|
} |
|
} |
|
|
|
bool found = true; |
|
for (int yy = 0; yy < height + 2 && found; yy++) { |
|
for (int xx = 0; xx < width + 2 && found; xx++) { |
|
if (dungeon[xx + sx][yy + sy] != 7) { |
|
found = false; |
|
} |
|
if (Protected[xx + sx][yy + sy]) { |
|
found = false; |
|
} |
|
} |
|
} |
|
if (found) |
|
break; |
|
} |
|
|
|
setpc_x = sx; |
|
setpc_y = sy; |
|
setpc_w = width + 2; |
|
setpc_h = height + 2; |
|
|
|
for (int yy = 0; yy < setpc_h; yy++) { |
|
for (int xx = 0; xx < setpc_w; xx++) { |
|
Protected[xx + sx][yy + sy] = true; |
|
} |
|
} |
|
|
|
sx++; |
|
sy++; |
|
|
|
const uint16_t *tileLayer = &dunData[2]; |
|
for (int yy = 0; yy < height; yy++) { |
|
for (int xx = 0; xx < width; xx++) { |
|
int tileId = tileLayer[xx + yy * width]; |
|
if (tileId != 0) { |
|
dungeon[xx + sx][yy + sy] = tileId; |
|
} |
|
} |
|
} |
|
|
|
// Hack to avoid rivers entering the island, reversed later |
|
dungeon[setpc_x + 7][setpc_y + 5] = 2; |
|
dungeon[setpc_x + 8][setpc_y + 5] = 2; |
|
dungeon[setpc_x + 9][setpc_y + 5] = 2; |
|
|
|
return true; |
|
} |
|
|
|
void Warp() |
|
{ |
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { |
|
if (dungeon[i][j] == 125 && dungeon[i + 1][j] == 125 && dungeon[i][j + 1] == 125 && dungeon[i + 1][j + 1] == 125) { |
|
dungeon[i][j] = 156; |
|
dungeon[i + 1][j] = 155; |
|
dungeon[i][j + 1] = 153; |
|
dungeon[i + 1][j + 1] = 154; |
|
return; |
|
} |
|
if (dungeon[i][j] == 5 && dungeon[i + 1][j + 1] == 7) { |
|
dungeon[i][j] = 7; |
|
} |
|
} |
|
} |
|
} |
|
|
|
void HallOfHeroes() |
|
{ |
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { |
|
if (dungeon[i][j] == 5 && dungeon[i + 1][j + 1] == 7) { |
|
dungeon[i][j] = 7; |
|
} |
|
} |
|
} |
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { |
|
if (dungeon[i][j] == 5 && dungeon[i + 1][j + 1] == 12 && dungeon[i + 1][j] == 7) { |
|
dungeon[i][j] = 7; |
|
dungeon[i][j + 1] = 7; |
|
dungeon[i + 1][j + 1] = 7; |
|
} |
|
if (dungeon[i][j] == 5 && dungeon[i + 1][j + 1] == 12 && dungeon[i][j + 1] == 7) { |
|
dungeon[i][j] = 7; |
|
dungeon[i + 1][j] = 7; |
|
dungeon[i + 1][j + 1] = 7; |
|
} |
|
} |
|
} |
|
} |
|
|
|
void LockRectangle(int x, int y) |
|
{ |
|
if (!lockout[x][y]) { |
|
return; |
|
} |
|
|
|
lockout[x][y] = false; |
|
lockoutcnt++; |
|
LockRectangle(x, y - 1); |
|
LockRectangle(x, y + 1); |
|
LockRectangle(x - 1, y); |
|
LockRectangle(x + 1, y); |
|
} |
|
|
|
bool Lockout() |
|
{ |
|
int fx; |
|
int fy; |
|
|
|
int t = 0; |
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { |
|
if (dungeon[i][j] != 0) { |
|
lockout[i][j] = true; |
|
fx = i; |
|
fy = j; |
|
t++; |
|
} else { |
|
lockout[i][j] = false; |
|
} |
|
} |
|
} |
|
|
|
lockoutcnt = 0; |
|
LockRectangle(fx, fy); |
|
|
|
return t == lockoutcnt; |
|
} |
|
|
|
bool PlaceCaveStairs(lvl_entry entry) |
|
{ |
|
// Place stairs up |
|
if (!PlaceMiniSet(L3UP, entry == ENTRY_MAIN)) |
|
return false; |
|
|
|
// Place stairs down |
|
if (!PlaceMiniSet(L3DOWN, entry == ENTRY_PREV)) |
|
return false; |
|
if (entry == ENTRY_PREV) |
|
ViewPosition += { 2, -2 }; |
|
|
|
// Place town warp stairs |
|
if (currlevel == 9 && !PlaceMiniSet(L3HOLDWARP, entry == ENTRY_TWARPDN)) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
bool PlaceNestStairs(lvl_entry entry) |
|
{ |
|
// Place stairs up |
|
if (!PlaceMiniSet(currlevel != 17 ? L6UP : L6HOLDWARP, entry == ENTRY_MAIN || entry == ENTRY_TWARPDN)) |
|
return false; |
|
|
|
// Place stairs down |
|
if (currlevel != 20) { |
|
if (!PlaceMiniSet(L6DOWN, entry == ENTRY_PREV)) |
|
return false; |
|
if (entry == ENTRY_PREV) |
|
ViewPosition += { 2, -2 }; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool PlaceStairs(lvl_entry entry) |
|
{ |
|
if (leveltype == DTYPE_NEST) { |
|
return PlaceNestStairs(entry); |
|
} |
|
|
|
return PlaceCaveStairs(entry); |
|
} |
|
|
|
void GenerateLevel(lvl_entry entry) |
|
{ |
|
while (true) { |
|
InitDungeonFlags(); |
|
int x1 = GenerateRnd(20) + 10; |
|
int y1 = GenerateRnd(20) + 10; |
|
int x2 = x1 + 2; |
|
int y2 = y1 + 2; |
|
FillRoom(x1, y1, x2, y2); |
|
CreateBlock(x1, y1, 2, 0); |
|
CreateBlock(x2, y1, 2, 1); |
|
CreateBlock(x1, y2, 2, 2); |
|
CreateBlock(x1, y1, 2, 3); |
|
if (Quests[Q_ANVIL].IsAvailable()) { |
|
x1 = GenerateRnd(10) + 10; |
|
y1 = GenerateRnd(10) + 10; |
|
x2 = x1 + 12; |
|
y2 = y1 + 12; |
|
FloorArea(x1, y1, x2, y2); |
|
} |
|
FillDiagonals(); |
|
FillSingles(); |
|
FillStraights(); |
|
FillDiagonals(); |
|
Edges(); |
|
if (GetFloorArea() < 600 || !Lockout()) |
|
continue; |
|
MakeMegas(); |
|
if (!PlaceStairs(entry)) |
|
continue; |
|
if (Quests[Q_ANVIL].IsAvailable() && !PlaceAnvil()) |
|
continue; |
|
if (PlacePool()) |
|
break; |
|
} |
|
|
|
if (leveltype == DTYPE_NEST) { |
|
PlaceMiniSetRandom(L6ISLE1, 70); |
|
PlaceMiniSetRandom(L6ISLE2, 70); |
|
PlaceMiniSetRandom(L6ISLE3, 30); |
|
PlaceMiniSetRandom(L6ISLE4, 30); |
|
PlaceMiniSetRandom(L6ISLE1, 100); |
|
PlaceMiniSetRandom(L6ISLE2, 100); |
|
PlaceMiniSetRandom(L6ISLE5, 90); |
|
PlaceMiniSetRandom1x1(8, 25, 20); |
|
PlaceMiniSetRandom1x1(8, 26, 20); |
|
PlaceMiniSetRandom1x1(8, 27, 20); |
|
PlaceMiniSetRandom1x1(8, 28, 20); |
|
PlaceMiniSetRandom(HivePattern29, 10); |
|
PlaceMiniSetRandom(HivePattern30, 15); |
|
PlaceMiniSetRandom(HivePattern31, 20); |
|
PlaceMiniSetRandom(HivePattern32, 25); |
|
PlaceMiniSetRandom(HivePattern33, 30); |
|
PlaceMiniSetRandom(HivePattern34, 35); |
|
PlaceMiniSetRandom(HivePattern35, 40); |
|
PlaceMiniSetRandom(HivePattern36, 45); |
|
PlaceMiniSetRandom(HivePattern37, 50); |
|
PlaceMiniSetRandom(HivePattern38, 55); |
|
PlaceMiniSetRandom(HivePattern38, 10); |
|
PlaceMiniSetRandom(HivePattern37, 15); |
|
PlaceMiniSetRandom(HivePattern36, 20); |
|
PlaceMiniSetRandom(HivePattern35, 25); |
|
PlaceMiniSetRandom(HivePattern34, 30); |
|
PlaceMiniSetRandom(HivePattern33, 35); |
|
PlaceMiniSetRandom(HivePattern32, 40); |
|
PlaceMiniSetRandom(HivePattern31, 45); |
|
PlaceMiniSetRandom(HivePattern30, 50); |
|
PlaceMiniSetRandom(HivePattern29, 55); |
|
PlaceMiniSetRandom(HivePattern9, 40); |
|
PlaceMiniSetRandom(HivePattern10, 45); |
|
PlaceMiniSetRandom1x1(7, 29, 25); |
|
PlaceMiniSetRandom1x1(7, 30, 25); |
|
PlaceMiniSetRandom1x1(7, 31, 25); |
|
PlaceMiniSetRandom1x1(7, 32, 25); |
|
PlaceMiniSetRandom1x1(9, 33, 25); |
|
PlaceMiniSetRandom1x1(9, 34, 25); |
|
PlaceMiniSetRandom1x1(9, 35, 25); |
|
PlaceMiniSetRandom1x1(9, 36, 25); |
|
PlaceMiniSetRandom1x1(9, 37, 25); |
|
PlaceMiniSetRandom1x1(10, 39, 25); |
|
PlaceMiniSetRandom1x1(10, 40, 25); |
|
PlaceMiniSetRandom1x1(10, 41, 25); |
|
PlaceMiniSetRandom1x1(10, 42, 25); |
|
PlaceMiniSetRandom1x1(10, 43, 25); |
|
PlaceMiniSetRandom1x1(9, 45, 25); |
|
PlaceMiniSetRandom1x1(9, 46, 25); |
|
PlaceMiniSetRandom1x1(10, 47, 25); |
|
PlaceMiniSetRandom1x1(10, 48, 25); |
|
PlaceMiniSetRandom1x1(11, 38, 25); |
|
PlaceMiniSetRandom1x1(11, 44, 25); |
|
PlaceMiniSetRandom1x1(11, 49, 25); |
|
PlaceMiniSetRandom1x1(11, 50, 25); |
|
} else { |
|
PoolFix(); |
|
Warp(); |
|
|
|
PlaceMiniSetRandom(L3ISLE1, 70); |
|
PlaceMiniSetRandom(L3ISLE2, 70); |
|
PlaceMiniSetRandom(L3ISLE3, 30); |
|
PlaceMiniSetRandom(L3ISLE4, 30); |
|
PlaceMiniSetRandom(L3ISLE1, 100); |
|
PlaceMiniSetRandom(L3ISLE2, 100); |
|
PlaceMiniSetRandom(L3ISLE5, 90); |
|
|
|
HallOfHeroes(); |
|
River(); |
|
|
|
if (Quests[Q_ANVIL].IsAvailable()) { |
|
dungeon[setpc_x + 7][setpc_y + 5] = 7; |
|
dungeon[setpc_x + 8][setpc_y + 5] = 7; |
|
dungeon[setpc_x + 9][setpc_y + 5] = 7; |
|
if (dungeon[setpc_x + 10][setpc_y + 5] == 17 || dungeon[setpc_x + 10][setpc_y + 5] == 18) { |
|
dungeon[setpc_x + 10][setpc_y + 5] = 45; |
|
} |
|
} |
|
|
|
DRLG_PlaceThemeRooms(5, 10, 7, 0, false); |
|
Fence(); |
|
PlaceMiniSetRandom(L3TITE1, 10); |
|
PlaceMiniSetRandom(L3TITE2, 10); |
|
PlaceMiniSetRandom(L3TITE3, 10); |
|
PlaceMiniSetRandom(L3TITE6, 20); |
|
PlaceMiniSetRandom(L3TITE7, 20); |
|
PlaceMiniSetRandom(L3TITE8, 20); |
|
PlaceMiniSetRandom(L3TITE9, 20); |
|
PlaceMiniSetRandom(L3TITE10, 20); |
|
PlaceMiniSetRandom(L3TITE11, 30); |
|
PlaceMiniSetRandom(L3TITE12, 20); |
|
PlaceMiniSetRandom(L3TITE13, 20); |
|
PlaceMiniSetRandom(L3CREV1, 30); |
|
PlaceMiniSetRandom(L3CREV2, 30); |
|
PlaceMiniSetRandom(L3CREV3, 30); |
|
PlaceMiniSetRandom(L3CREV4, 30); |
|
PlaceMiniSetRandom(L3CREV5, 30); |
|
PlaceMiniSetRandom(L3CREV6, 30); |
|
PlaceMiniSetRandom(L3CREV7, 30); |
|
PlaceMiniSetRandom(L3CREV8, 30); |
|
PlaceMiniSetRandom(L3CREV9, 30); |
|
PlaceMiniSetRandom(L3CREV10, 30); |
|
PlaceMiniSetRandom(L3CREV11, 30); |
|
PlaceMiniSetRandom1x1(7, 106, 25); |
|
PlaceMiniSetRandom1x1(7, 107, 25); |
|
PlaceMiniSetRandom1x1(7, 108, 25); |
|
PlaceMiniSetRandom1x1(9, 109, 25); |
|
PlaceMiniSetRandom1x1(10, 110, 25); |
|
} |
|
|
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { |
|
pdungeon[i][j] = dungeon[i][j]; |
|
} |
|
} |
|
|
|
DRLG_Init_Globals(); |
|
} |
|
|
|
void Pass3() |
|
{ |
|
DRLG_LPass3(8 - 1); |
|
} |
|
|
|
void PlaceCaveLights() |
|
{ |
|
for (int j = 0; j < MAXDUNY; j++) { |
|
for (int i = 0; i < MAXDUNX; i++) { |
|
if (dPiece[i][j] >= 56 && dPiece[i][j] <= 147) { |
|
DoLighting({ i, j }, 7, -1); |
|
} else if (dPiece[i][j] >= 154 && dPiece[i][j] <= 161) { |
|
DoLighting({ i, j }, 7, -1); |
|
} else if (IsAnyOf(dPiece[i][j], 150, 152)) { |
|
DoLighting({ i, j }, 7, -1); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void PlaceHiveLights() |
|
{ |
|
|
|
for (int j = 0; j < MAXDUNY; j++) { |
|
for (int i = 0; i < MAXDUNX; i++) { |
|
if (dPiece[i][j] >= 382 && dPiece[i][j] <= 457) { |
|
DoLighting({ i, j }, 9, -1); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void PlaceLights() |
|
{ |
|
if (leveltype == DTYPE_NEST) { |
|
PlaceHiveLights(); |
|
return; |
|
} |
|
|
|
PlaceCaveLights(); |
|
} |
|
|
|
} // namespace |
|
|
|
void CreateL3Dungeon(uint32_t rseed, lvl_entry entry) |
|
{ |
|
SetRndSeed(rseed); |
|
|
|
dminPosition = { 16, 16 }; |
|
dmaxPosition = { 96, 96 }; |
|
|
|
DRLG_InitTrans(); |
|
DRLG_InitSetPC(); |
|
GenerateLevel(entry); |
|
Pass3(); |
|
PlaceLights(); |
|
DRLG_SetPC(); |
|
} |
|
|
|
void LoadL3Dungeon(const char *path, int vx, int vy) |
|
{ |
|
dminPosition = { 16, 16 }; |
|
dmaxPosition = { 96, 96 }; |
|
|
|
InitDungeonFlags(); |
|
DRLG_InitTrans(); |
|
|
|
auto dunData = LoadFileInMem<uint16_t>(path); |
|
|
|
int width = SDL_SwapLE16(dunData[0]); |
|
int height = SDL_SwapLE16(dunData[1]); |
|
|
|
const uint16_t *tileLayer = &dunData[2]; |
|
|
|
for (int j = 0; j < height; j++) { |
|
for (int i = 0; i < width; i++) { |
|
auto tileId = static_cast<uint8_t>(SDL_SwapLE16(tileLayer[j * width + i])); |
|
dungeon[i][j] = (tileId != 0) ? tileId : 7; |
|
} |
|
} |
|
|
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { // NOLINT(modernize-loop-convert) |
|
if (dungeon[i][j] == 0) { |
|
dungeon[i][j] = 8; |
|
} |
|
} |
|
} |
|
|
|
Pass3(); |
|
DRLG_Init_Globals(); |
|
|
|
ViewPosition = { vx, vy }; |
|
|
|
SetMapMonsters(dunData.get(), { 0, 0 }); |
|
SetMapObjects(dunData.get(), 0, 0); |
|
|
|
for (int j = 0; j < MAXDUNY; j++) { |
|
for (int i = 0; i < MAXDUNX; i++) { |
|
if (dPiece[i][j] >= 56 && dPiece[i][j] <= 147) { |
|
DoLighting({ i, j }, 7, -1); |
|
} else if (dPiece[i][j] >= 154 && dPiece[i][j] <= 161) { |
|
DoLighting({ i, j }, 7, -1); |
|
} else if (IsAnyOf(dPiece[i][j], 150, 152)) { |
|
DoLighting({ i, j }, 7, -1); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void LoadPreL3Dungeon(const char *path) |
|
{ |
|
InitDungeonFlags(); |
|
DRLG_InitTrans(); |
|
|
|
auto dunData = LoadFileInMem<uint16_t>(path); |
|
|
|
int width = SDL_SwapLE16(dunData[0]); |
|
int height = SDL_SwapLE16(dunData[1]); |
|
|
|
const uint16_t *tileLayer = &dunData[2]; |
|
|
|
for (int j = 0; j < height; j++) { |
|
for (int i = 0; i < width; i++) { |
|
auto tileId = static_cast<uint8_t>(SDL_SwapLE16(tileLayer[j * width + i])); |
|
dungeon[i][j] = (tileId != 0) ? tileId : 7; |
|
} |
|
} |
|
|
|
for (int j = 0; j < DMAXY; j++) { |
|
for (int i = 0; i < DMAXX; i++) { // NOLINT(modernize-loop-convert) |
|
if (dungeon[i][j] == 0) { |
|
dungeon[i][j] = 8; |
|
} |
|
} |
|
} |
|
|
|
memcpy(pdungeon, dungeon, sizeof(pdungeon)); |
|
} |
|
|
|
} // namespace devilution
|
|
|