Use Point/range iterator in CheckThemeObj3

This does introduce a slight behaviour difference for some callers. It was possible to read out of bounds due to the bounds check only guarding against negative indexes (e.g. Theme_Library uses 1, MAXDUN - 1 as the bounds, but Theme_ArmorStand includes boundary tiles so could read off the right/bottom edge). Given the way vanilla levels are generated with a border this has no impact in practice.
This commit is contained in:
ephphatha 2021-10-29 00:37:02 +11:00 committed by Anders Jenbo
commit 3e991fc9a8

View file

@ -5,6 +5,7 @@
*/
#include "themes.h"
#include "engine/points_in_rectangle_range.hpp"
#include "engine/random.hpp"
#include "items.h"
#include "monster.h"
@ -48,19 +49,6 @@ int trm5y[] = {
1, 1, 1, 1, 1,
2, 2, 2, 2, 2
};
/** Specifies a 3x3 area to fit theme objects. */
int trm3x[] = {
-1, 0, 1,
-1, 0, 1,
-1, 0, 1
};
/** Specifies a 3x3 area to fit theme objects. */
int trm3y[] = {
-1, -1, -1,
0, 0, 0,
1, 1, 1
};
bool TFit_Shrine(int i)
{
int xp = 0;
@ -179,28 +167,28 @@ bool TFit_GoatShrine(int t)
return false;
}
bool CheckThemeObj3(int xp, int yp, int t, int f)
bool CheckThemeObj3(Point origin, int8_t regionId, int frequency)
{
for (int i = 0; i < 9; i++) {
Point testPosition = Point { xp, yp } + Displacement { trm3x[i], trm3y[i] };
if (testPosition.x < 0 || testPosition.y < 0) {
const PointsInRectangleRange searchArea { Rectangle { origin, 1 } };
return std::all_of(searchArea.cbegin(), searchArea.cend(), [regionId, frequency](Point testPosition) {
if (!InDungeonBounds(testPosition)) {
return false;
}
if (IsTileSolid(testPosition)) {
return false;
}
if (dTransVal[testPosition.x][testPosition.y] != themes[t].ttval) {
// If the theme object would extend into a different region then it doesn't fit.
if (dTransVal[testPosition.x][testPosition.y] != regionId) {
return false;
}
if (IsObjectAtPosition(testPosition)) {
return false;
}
if (f != -1 && GenerateRnd(f) == 0) {
if (frequency != -1 && GenerateRnd(frequency) == 0) {
return false;
}
}
return true;
return true;
});
}
bool TFit_Obj3(int t)
@ -209,7 +197,7 @@ bool TFit_Obj3(int t)
for (int yp = 1; yp < MAXDUNY - 1; yp++) {
for (int xp = 1; xp < MAXDUNX - 1; xp++) {
if (CheckThemeObj3(xp, yp, t, objrnd[leveltype - 1])) {
if (CheckThemeObj3({ xp, yp }, themes[t].ttval, objrnd[leveltype - 1])) {
themex = xp;
themey = yp;
return true;
@ -717,7 +705,7 @@ void Theme_Library(int t)
for (int yp = 1; yp < MAXDUNY - 1; yp++) {
for (int xp = 1; xp < MAXDUNX - 1; xp++) {
if (CheckThemeObj3(xp, yp, t, -1) && dMonster[xp][yp] == 0 && GenerateRnd(librnd[leveltype - 1]) == 0) {
if (CheckThemeObj3({ xp, yp }, themes[t].ttval, -1) && dMonster[xp][yp] == 0 && GenerateRnd(librnd[leveltype - 1]) == 0) {
AddObject(OBJ_BOOKSTAND, { xp, yp });
if (GenerateRnd(2 * librnd[leveltype - 1]) != 0) {
Object *bookstand = ObjectAtPosition({ xp, yp });
@ -753,7 +741,7 @@ void Theme_Torture(int t)
for (int yp = 1; yp < MAXDUNY - 1; yp++) {
for (int xp = 1; xp < MAXDUNX - 1; xp++) {
if (dTransVal[xp][yp] == themes[t].ttval && IsTileNotSolid({ xp, yp })) {
if (CheckThemeObj3(xp, yp, t, -1)) {
if (CheckThemeObj3({ xp, yp }, themes[t].ttval, -1)) {
if (GenerateRnd(tortrnd[leveltype - 1]) == 0) {
AddObject(OBJ_TNUDEM2, { xp, yp });
}
@ -790,7 +778,7 @@ void Theme_Decap(int t)
for (int yp = 1; yp < MAXDUNY - 1; yp++) {
for (int xp = 1; xp < MAXDUNX - 1; xp++) {
if (dTransVal[xp][yp] == themes[t].ttval && IsTileNotSolid({ xp, yp })) {
if (CheckThemeObj3(xp, yp, t, -1)) {
if (CheckThemeObj3({ xp, yp }, themes[t].ttval, -1)) {
if (GenerateRnd(decaprnd[leveltype - 1]) == 0) {
AddObject(OBJ_DECAP, { xp, yp });
}
@ -832,7 +820,7 @@ void Theme_ArmorStand(int t)
for (int yp = 0; yp < MAXDUNY; yp++) {
for (int xp = 0; xp < MAXDUNX; xp++) {
if (dTransVal[xp][yp] == themes[t].ttval && IsTileNotSolid({ xp, yp })) {
if (CheckThemeObj3(xp, yp, t, -1)) {
if (CheckThemeObj3({ xp, yp }, themes[t].ttval, -1)) {
if (GenerateRnd(armorrnd[leveltype - 1]) == 0) {
AddObject(OBJ_ARMORSTANDN, { xp, yp });
}
@ -917,7 +905,7 @@ void Theme_BrnCross(int t)
for (int yp = 0; yp < MAXDUNY; yp++) {
for (int xp = 0; xp < MAXDUNX; xp++) {
if (dTransVal[xp][yp] == themes[t].ttval && IsTileNotSolid({ xp, yp })) {
if (CheckThemeObj3(xp, yp, t, -1)) {
if (CheckThemeObj3({ xp, yp }, themes[t].ttval, -1)) {
if (GenerateRnd(bcrossrnd[leveltype - 1]) == 0) {
AddObject(OBJ_TBCROSS, { xp, yp });
}
@ -945,7 +933,7 @@ void Theme_WeaponRack(int t)
for (int yp = 0; yp < MAXDUNY; yp++) {
for (int xp = 0; xp < MAXDUNX; xp++) {
if (dTransVal[xp][yp] == themes[t].ttval && IsTileNotSolid({ xp, yp })) {
if (CheckThemeObj3(xp, yp, t, -1)) {
if (CheckThemeObj3({ xp, yp }, themes[t].ttval, -1)) {
if (GenerateRnd(weaponrnd[leveltype - 1]) == 0) {
AddObject(OBJ_WEAPONRACKN, { xp, yp });
}