Skip to content

Commit 08acd4a

Browse files
ephphathaAJenbo
authored andcommitted
Tidy up T_FitObj5
1 parent 6656c74 commit 08acd4a

File tree

2 files changed

+83
-52
lines changed

2 files changed

+83
-52
lines changed

Source/levels/themes.cpp

+33-52
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,6 @@ bool bFountainFlag;
3636

3737
/** Specifies the set of special theme IDs from which one will be selected at random. */
3838
theme_id ThemeGood[4] = { THEME_GOATSHRINE, THEME_SHRINE, THEME_SKELROOM, THEME_LIBRARY };
39-
/** Specifies a 5x5 area to fit theme objects. */
40-
int trm5x[] = {
41-
-2, -1, 0, 1, 2,
42-
-2, -1, 0, 1, 2,
43-
-2, -1, 0, 1, 2,
44-
-2, -1, 0, 1, 2,
45-
-2, -1, 0, 1, 2
46-
};
47-
/** Specifies a 5x5 area to fit theme objects. */
48-
int trm5y[] = {
49-
-2, -2, -2, -2, -2,
50-
-1, -1, -1, -1, -1,
51-
0, 0, 0, 0, 0,
52-
1, 1, 1, 1, 1,
53-
2, 2, 2, 2, 2
54-
};
5539
bool TFit_Shrine(int i)
5640
{
5741
int xp = 0;
@@ -97,49 +81,46 @@ bool TFit_Shrine(int i)
9781
return true;
9882
}
9983

100-
bool TFit_Obj5(int t)
84+
bool CheckThemeObj5(Point origin, int8_t regionId)
10185
{
102-
int xp = 0;
103-
int yp = 0;
104-
int r = GenerateRnd(5) + 1;
105-
int rs = r;
106-
107-
while (r > 0) {
108-
bool found = false;
109-
if (dTransVal[xp][yp] == themes[t].ttval && IsTileNotSolid({ xp, yp })) {
110-
found = true;
111-
for (int i = 0; found && i < 25; i++) {
112-
if (TileHasAny(dPiece[xp + trm5x[i]][yp + trm5y[i]], TileProperties::Solid)) {
113-
found = false;
114-
}
115-
if (dTransVal[xp + trm5x[i]][yp + trm5y[i]] != themes[t].ttval) {
116-
found = false;
117-
}
118-
}
86+
const PointsInRectangleRange searchArea { Rectangle { origin, 2 } };
87+
return std::all_of(searchArea.cbegin(), searchArea.cend(), [regionId](Point testPosition) {
88+
// note out-of-bounds tiles are not solid, this function relies on the guard in TFit_Obj5 and dungeon border
89+
if (IsTileSolid(testPosition)) {
90+
return false;
11991
}
92+
// If the theme object would extend into a different region then it doesn't fit.
93+
if (dTransVal[testPosition.x][testPosition.y] != regionId) {
94+
return false;
95+
}
96+
return true;
97+
});
98+
}
12099

121-
if (!found) {
122-
xp++;
123-
if (xp == MAXDUNX) {
124-
xp = 0;
125-
yp++;
126-
if (yp == MAXDUNY) {
127-
if (r == rs) {
128-
return false;
129-
}
130-
yp = 0;
100+
bool TFit_Obj5(int t)
101+
{
102+
int skipCandidates = GenerateRnd(5);
103+
if (skipCandidates < 0) {
104+
// vanilla rng can return -3 for GenerateRnd(5), default behaviour is to set the output to 0,0 and return true in this case...
105+
themex = 0;
106+
themey = 0;
107+
return true;
108+
}
109+
110+
for (int yp = 0; yp < MAXDUNY; yp++) {
111+
for (int xp = 0; xp < MAXDUNX; xp++) {
112+
if (dTransVal[xp][yp] == themes[t].ttval && IsTileNotSolid({ xp, yp }) && CheckThemeObj5({ xp, yp }, themes[t].ttval)) {
113+
if (skipCandidates > 0) {
114+
skipCandidates--;
115+
continue;
131116
}
117+
themex = xp;
118+
themey = yp;
119+
return true;
132120
}
133-
continue;
134121
}
135-
136-
r--;
137122
}
138-
139-
themex = xp;
140-
themey = yp;
141-
142-
return true;
123+
return false;
143124
}
144125

145126
bool TFit_SkelRoom(int t)

test/random_test.cpp

+50
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,54 @@ TEST(RandomTest, ModDistributionSignPreserving)
237237
<< "Distribution must map negative numbers using sign preserving modulo";
238238
}
239239

240+
TEST(RandomTest, NegativeReturnValues)
241+
{
242+
// The bug in vanilla RNG stemming from mod instead of bitmasking means that negative values are possible for
243+
// non-power of 2 arguments to GenerateRnd
244+
SetRndSeed(1457187811);
245+
EXPECT_EQ(GenerateRnd(3), -2) << "Unexpected return value for a limit of 3";
246+
247+
SetRndSeed(1457187811);
248+
EXPECT_EQ(GenerateRnd(5), -3) << "Unexpected return value for a limit of 5";
249+
SetRndSeed(1457187811);
250+
EXPECT_EQ(GenerateRnd(6), -2) << "Unexpected return value for a limit of 6";
251+
SetRndSeed(1457187811);
252+
EXPECT_EQ(GenerateRnd(7), -1) << "Unexpected return value for a limit of 7";
253+
254+
SetRndSeed(1457187811);
255+
EXPECT_EQ(GenerateRnd(11), -10) << "Unexpected return value for a limit of 11";
256+
257+
SetRndSeed(1457187811);
258+
EXPECT_EQ(GenerateRnd(17), -9) << "Unexpected return value for a limit of 17";
259+
260+
SetRndSeed(1457187811);
261+
EXPECT_EQ(GenerateRnd(19), -12) << "Unexpected return value for a limit of 19";
262+
263+
SetRndSeed(1457187811);
264+
EXPECT_EQ(GenerateRnd(22), -10) << "Unexpected return value for a limit of 22";
265+
SetRndSeed(1457187811);
266+
EXPECT_EQ(GenerateRnd(23), -16) << "Unexpected return value for a limit of 23";
267+
268+
SetRndSeed(1457187811);
269+
EXPECT_EQ(GenerateRnd(25), -18) << "Unexpected return value for a limit of 25";
270+
271+
SetRndSeed(1457187811);
272+
EXPECT_EQ(GenerateRnd(27), -17) << "Unexpected return value for a limit of 27";
273+
274+
SetRndSeed(1457187811);
275+
EXPECT_EQ(GenerateRnd(29), -27) << "Unexpected return value for a limit of 29";
276+
277+
SetRndSeed(1457187811);
278+
EXPECT_EQ(GenerateRnd(31), -1) << "Unexpected return value for a limit of 31";
279+
280+
for (int i : { 9, 10, 12, 13, 14, 15, 18, 20, 21, 24, 26, 28, 30 }) {
281+
SetRndSeed(1457187811);
282+
EXPECT_EQ(GenerateRnd(i), -8) << "Unexpected return value for a limit of " << i;
283+
}
284+
285+
for (int i = 1; i < 32768; i *= 2) {
286+
SetRndSeed(1457187811);
287+
EXPECT_EQ(GenerateRnd(i), 0) << "Expect powers of 2 such as " << i << " to cleanly divide the int_min RNG value ";
288+
}
289+
}
240290
} // namespace devilution

0 commit comments

Comments
 (0)