diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 5f777df34..1fe569c3f 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -91,7 +91,7 @@ int GetDistance(Point destination, int maxDistance) } int8_t walkpath[MAX_PATH_LENGTH]; - int steps = FindPath(std::bind(PosOkPlayer, MyPlayerId, std::placeholders::_1), Players[MyPlayerId].position.future.x, Players[MyPlayerId].position.future.y, destination.x, destination.y, walkpath); + int steps = FindPath([](Point position){ return PosOkPlayer(MyPlayerId, position); }, Players[MyPlayerId].position.future.x, Players[MyPlayerId].position.future.y, destination.x, destination.y, walkpath); if (steps > maxDistance) return 0; diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 1e0f7ebd6..c161bd649 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -198,7 +198,7 @@ void MoveMissilePos(int i) } int x = Missiles[i].position.tile.x + dx; int y = Missiles[i].position.tile.y + dy; - if (MonsterIsTileAvailable(Missiles[i]._misource, { x, y })) { + if (IsTileAvailable(Monsters[Missiles[i]._misource], { x, y })) { Missiles[i].position.tile.x += dx; Missiles[i].position.tile.y += dy; Missiles[i].position.offset.deltaX += (dy * 32) - (dx * 32); @@ -4288,7 +4288,7 @@ void MI_Rhino(int i) } UpdateMissilePos(i); Point newPos = Missiles[i].position.tile; - if (!MonsterIsTileAvailable(monst, newPos) || (monster._mAi == AI_SNAKE && !MonsterIsTileAvailable(monst, newPosSnake))) { + if (!IsTileAvailable(monster, newPos) || (monster._mAi == AI_SNAKE && !IsTileAvailable(monster, newPosSnake))) { MissToMonst(i, prevPos); Missiles[i]._miDelFlag = true; return; @@ -4315,7 +4315,7 @@ void MI_Fireman(int i) Point c = (monster._mFlags & MFLAG_TARGETS_MONSTER) == 0 ? Players[enemy].position.tile : Monsters[enemy].position.tile; int j = 0; - if (b != a && (((Missiles[i]._miVar1 & 1) != 0 && a.WalkingDistance(c) >= 4) || Missiles[i]._miVar2 > 1) && MonsterIsTileAvailable(Missiles[i]._misource, a)) { + if (b != a && (((Missiles[i]._miVar1 & 1) != 0 && a.WalkingDistance(c) >= 4) || Missiles[i]._miVar2 > 1) && IsTileAvailable(monster, a)) { MissToMonst(i, a); Missiles[i]._miDelFlag = true; } else if ((monster._mFlags & MFLAG_TARGETS_MONSTER) == 0) { diff --git a/Source/monster.cpp b/Source/monster.cpp index f9be5e23a..52f0759df 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -288,7 +288,7 @@ bool MonstPlace(int xp, int yp) return false; } - return !SolidLoc({ xp, yp }); + return !IsTileSolid({ xp, yp }); } void PlaceMonster(int i, int mtype, int x, int y) @@ -1157,7 +1157,7 @@ void Teleport(int i) x = mx + rx * j; y = my + ry * k; if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX && x != monster.position.tile.x && y != monster.position.tile.y) { - if (MonsterIsTileAvailable(i, { x, y })) + if (IsTileAvailable(monster, { x, y })) done = true; } } @@ -1942,14 +1942,9 @@ int SpawnSkeleton(Point position, Direction dir) return skel; } -bool IsNotSolid(Point position) -{ - return !nSolidTable[dPiece[position.x][position.y]]; -} - bool IsLineNotSolid(Point startPoint, Point endPoint) { - return LineClear(IsNotSolid, startPoint, endPoint); + return LineClear(IsTileNotSolid, startPoint, endPoint); } void GroupUnity(int i) @@ -2046,7 +2041,7 @@ bool RandomWalk2(int i, Direction md) /** * @brief Check if a tile is affected by a spell we are vunerable to */ -bool MonsterIsTileSafe(const MonsterStruct &monster, Point position) +bool IsTileSafe(const MonsterStruct &monster, Point position) { int8_t mi = dMissile[position.x][position.y]; if (mi == 0) { @@ -2085,49 +2080,31 @@ bool MonsterIsTileSafe(const MonsterStruct &monster, Point position) } /** - * @brief Check that the monster can stand on the tile + * @brief Check that the given tile is not currently blocked */ -bool MonsterIsTileClear(int i, Point position) +bool IsTileAvailable(Point position) { - if (SolidLoc(position)) + if (dPlayer[position.x][position.y] != 0 || dMonster[position.x][position.y] != 0) return false; - if (dObject[position.x][position.y] != 0) { - int oi = dObject[position.x][position.y] > 0 ? dObject[position.x][position.y] - 1 : -(dObject[position.x][position.y] + 1); - if (Objects[oi]._oSolidFlag) - return false; - } + if (!IsTileWalkable(position)) + return false; - return MonsterIsTileSafe(Monsters[i], position); + return true; } /** * @brief If a monster can access the given tile (possibly by opening a door) */ -bool MonsterIsTileAccessible(int i, Point position) +bool IsTileAccessible(const MonsterStruct &monster, Point position) { - MonsterStruct *monster; - if (i >= 0) - monster = &Monsters[i]; - - bool canOpen = false; - if (dObject[position.x][position.y] != 0) { - int oi = dObject[position.x][position.y] > 0 ? dObject[position.x][position.y] - 1 : -(dObject[position.x][position.y] + 1); - - if (monster != nullptr && (monster->_mFlags & MFLAG_CAN_OPEN_DOOR) != 0) - canOpen = IsAnyOf(Objects[oi]._otype, OBJ_L1LDOOR, OBJ_L1RDOOR, OBJ_L2LDOOR, OBJ_L2RDOOR, OBJ_L3LDOOR, OBJ_L3RDOOR); - - if (Objects[oi]._oSolidFlag && !canOpen) - return false; - } - - if ((SolidLoc(position) && !canOpen) || dPlayer[position.x][position.y] != 0 || dMonster[position.x][position.y] != 0) + if (dPlayer[position.x][position.y] != 0 || dMonster[position.x][position.y] != 0) return false; - if (monster == nullptr) - return true; + if (!IsTileWalkable(position, (monster._mFlags & MFLAG_CAN_OPEN_DOOR) != 0)) + return false; - return MonsterIsTileSafe(*monster, position); + return IsTileSafe(monster, position); } bool AiPlanWalk(int i) @@ -2140,7 +2117,7 @@ bool AiPlanWalk(int i) assert((DWORD)i < MAXMONSTERS); auto &monster = Monsters[i]; - if (FindPath(std::bind(MonsterIsTileAccessible, i, std::placeholders::_1), monster.position.tile.x, monster.position.tile.y, monster.enemyPosition.x, monster.enemyPosition.y, path) == 0) { + if (FindPath([&monster](Point position) { return IsTileAccessible(monster, position); }, monster.position.tile.x, monster.position.tile.y, monster.enemyPosition.x, monster.enemyPosition.y, path) == 0) { return false; } @@ -2207,7 +2184,7 @@ bool AiPlanPath(int i) } bool clear = LineClear( - std::bind(MonsterIsTileAvailable, i, std::placeholders::_1), + [&monster](Point position) { return IsTileAvailable(monster, position); }, monster.position.tile, monster.enemyPosition); if (!clear || (monster._pathcount >= 5 && monster._pathcount < 8)) { @@ -2643,7 +2620,7 @@ void RhinoAi(int i) if (monster._mgoal == MGOAL_NORMAL) { if (dist >= 5 && v < 2 * monster._mint + 43 - && LineClear(std::bind(MonsterIsTileAvailable, i, std::placeholders::_1), monster.position.tile, { fx, fy })) { + && LineClear([&monster](Point position) { return IsTileAvailable(monster, position); }, monster.position.tile, { fx, fy })) { if (AddMissile(monster.position.tile, { fx, fy }, md, MIS_RHINO, monster._menemy, i, 0, 0) != -1) { if (monster.MData->snd_special) PlayEffect(monster, 3); @@ -2789,7 +2766,7 @@ void LeoricAi(int i) && ((dist >= 3 && v < 4 * monster._mint + 35) || v < 6) && LineClearMissile(monster.position.tile, { fx, fy })) { Point newPosition = monster.position.tile + md; - if (MonsterIsTileAvailable(i, newPosition) && ActiveMonsterCount < MAXMONSTERS) { + if (IsTileAvailable(monster, newPosition) && ActiveMonsterCount < MAXMONSTERS) { SpawnSkeleton(newPosition, md); StartSpecialStand(monster, md); } @@ -2846,7 +2823,7 @@ void BatAi(int i) if (monster.MType->mtype == MT_GLOOM && (abs(xd) >= 5 || abs(yd) >= 5) && v < 4 * monster._mint + 33 - && LineClear(std::bind(MonsterIsTileAvailable, i, std::placeholders::_1), monster.position.tile, { fx, fy })) { + && LineClear([&monster](Point position) { return IsTileAvailable(monster, position); }, monster.position.tile, { fx, fy })) { if (AddMissile(monster.position.tile, { fx, fy }, md, MIS_RHINO, pnum, i, 0, 0) != -1) { dMonster[monster.position.tile.x][monster.position.tile.y] = -(i + 1); monster._mmode = MM_CHARGE; @@ -3175,7 +3152,7 @@ void SnakeAi(int i) Direction md = GetDirection(monster.position.tile, monster.position.last); monster._mdir = md; if (abs(mx) >= 2 || abs(my) >= 2) { - if (abs(mx) < 3 && abs(my) < 3 && LineClear(std::bind(MonsterIsTileAvailable, i, std::placeholders::_1), monster.position.tile, { fx, fy }) && monster._mVar1 != MM_CHARGE) { + if (abs(mx) < 3 && abs(my) < 3 && LineClear([&monster](Point position) { return IsTileAvailable(monster, position); }, monster.position.tile, { fx, fy }) && monster._mVar1 != MM_CHARGE) { if (AddMissile(monster.position.tile, { fx, fy }, md, MIS_RHINO, pnum, i, 0, 0) != -1) { PlayEffect(monster, 0); dMonster[monster.position.tile.x][monster.position.tile.y] = -(i + 1); @@ -3577,7 +3554,7 @@ void HorkDemonAi(int i) if (monster._mgoal == 1) { if ((abs(mx) >= 3 || abs(my) >= 3) && v < 2 * monster._mint + 43) { Point position = monster.position.tile + monster._mdir; - if (MonsterIsTileAvailable(i, position) && ActiveMonsterCount < MAXMONSTERS) { + if (IsTileAvailable(monster, position) && ActiveMonsterCount < MAXMONSTERS) { StartRangedSpecialAttack(monster, MIS_HORKDMN, 0); } } else if (abs(mx) < 2 && abs(my) < 2) { @@ -4002,7 +3979,7 @@ void InitMonsters() int na = 0; for (int s = 16; s < 96; s++) { for (int t = 16; t < 96; t++) { - if (!SolidLoc({ s, t })) + if (!IsTileSolid({ s, t })) na++; } } @@ -4099,19 +4076,9 @@ void AddDoppelganger(MonsterStruct &monster) Point target = { 0, 0 }; for (int d = 0; d < 8; d++) { const Point position = monster.position.tile + static_cast(d); - if (!SolidLoc(position)) { - if (dPlayer[position.x][position.y] == 0 && dMonster[position.x][position.y] == 0) { - if (dObject[position.x][position.y] == 0) { - target = position; - break; - } - int oi = dObject[position.x][position.y] > 0 ? dObject[position.x][position.y] - 1 : -(dObject[position.x][position.y] + 1); - if (!Objects[oi]._oSolidFlag) { - target = position; - break; - } - } - } + if (!IsTileAvailable(position)) + continue; + target = position; } if (target != Point { 0, 0 }) { for (int j = 0; j < MAX_LVLMTYPES; j++) { @@ -4606,19 +4573,19 @@ bool DirOK(int i, Direction mdir) auto &monster = Monsters[i]; Point position = monster.position.tile; Point futurePosition = position + mdir; - if (futurePosition.y < 0 || futurePosition.y >= MAXDUNY || futurePosition.x < 0 || futurePosition.x >= MAXDUNX || !MonsterIsTileAvailable(i, futurePosition)) + if (futurePosition.y < 0 || futurePosition.y >= MAXDUNY || futurePosition.x < 0 || futurePosition.x >= MAXDUNX || !IsTileAvailable(monster, futurePosition)) return false; if (mdir == DIR_E) { - if (SolidLoc(position + DIR_SE) || (dFlags[position.x + 1][position.y] & BFLAG_MONSTLR) != 0) + if (IsTileSolid(position + DIR_SE) || (dFlags[position.x + 1][position.y] & BFLAG_MONSTLR) != 0) return false; } else if (mdir == DIR_W) { - if (SolidLoc(position + DIR_SW) || (dFlags[position.x][position.y + 1] & BFLAG_MONSTLR) != 0) + if (IsTileSolid(position + DIR_SW) || (dFlags[position.x][position.y + 1] & BFLAG_MONSTLR) != 0) return false; } else if (mdir == DIR_N) { - if (SolidLoc(position + DIR_NE) || SolidLoc(position + DIR_NW)) + if (IsTileSolid(position + DIR_NE) || IsTileSolid(position + DIR_NW)) return false; } else if (mdir == DIR_S) - if (SolidLoc(position + DIR_SW) || SolidLoc(position + DIR_SE)) + if (IsTileSolid(position + DIR_SW) || IsTileSolid(position + DIR_SE)) return false; if (monster.leaderflag == MonsterRelation::Minion) { return futurePosition.WalkingDistance(Monsters[monster.leader].position.future) < 4; @@ -5001,7 +4968,7 @@ void MissToMonst(int i, Point position) MonsterAttackMonster(m, dMonster[oldPosition.x][oldPosition.y] - 1, 500, monster.mMinDamage2, monster.mMaxDamage2); if (monster.MType->mtype < MT_NSNAKE || monster.MType->mtype > MT_GSNAKE) { Point newPosition = oldPosition + monster._mdir; - if (MonsterIsTileAvailable(dMonster[oldPosition.x][oldPosition.y] - 1, newPosition)) { + if (IsTileAvailable(Monsters[dMonster[oldPosition.x][oldPosition.y] - 1], newPosition)) { m = dMonster[oldPosition.x][oldPosition.y]; dMonster[newPosition.x][newPosition.y] = m; dMonster[oldPosition.x][oldPosition.y] = 0; @@ -5017,12 +4984,12 @@ void MissToMonst(int i, Point position) /** * @brief Check that the given tile is available to the monster */ -bool MonsterIsTileAvailable(int i, Point position) +bool IsTileAvailable(const MonsterStruct &monster, Point position) { - if (dPlayer[position.x][position.y] != 0 || dMonster[position.x][position.y] != 0) + if (!IsTileAvailable(position)) return false; - return MonsterIsTileClear(i, position); + return IsTileSafe(monster, position); } bool IsSkel(int mt) @@ -5043,7 +5010,7 @@ bool SpawnSkeleton(int ii, Point position) if (ii == -1) return false; - if (MonsterIsTileAvailable(-1, position)) { + if (IsTileAvailable(position)) { Direction dir = GetDirection(position, position); // TODO useless calculation ActivateSpawn(ii, position.x, position.y, dir); return true; @@ -5056,7 +5023,7 @@ bool SpawnSkeleton(int ii, Point position) for (int j = position.y - 1; j <= position.y + 1; j++) { int xx = 0; for (int k = position.x - 1; k <= position.x + 1; k++) { - monstok[xx][yy] = MonsterIsTileAvailable(-1, { k, j }); + monstok[xx][yy] = IsTileAvailable({ k, j }); savail = savail || monstok[xx][yy]; xx++; } diff --git a/Source/monster.h b/Source/monster.h index c80100405..0febbacaa 100644 --- a/Source/monster.h +++ b/Source/monster.h @@ -264,7 +264,7 @@ void PrintMonstHistory(int mt); void PrintUniqueHistory(); void PlayEffect(MonsterStruct &monster, int mode); void MissToMonst(int i, Point position); -bool MonsterIsTileAvailable(int i, Point position); +bool IsTileAvailable(const MonsterStruct &monster, Point position); bool IsSkel(int mt); bool IsGoat(int mt); bool SpawnSkeleton(int ii, Point position); diff --git a/Source/path.cpp b/Source/path.cpp index 5ccce03c1..541cab03a 100644 --- a/Source/path.cpp +++ b/Source/path.cpp @@ -6,6 +6,7 @@ #include "path.h" #include "gendung.h" +#include "objects.h" namespace devilution { @@ -56,6 +57,36 @@ const Displacement PathDirs[8] = { */ int8_t path_directions[9] = { 5, 1, 6, 2, 0, 3, 8, 4, 7 }; +bool IsTileNotSolid(Point position) +{ + return !nSolidTable[dPiece[position.x][position.y]]; +} + +bool IsTileSolid(Point position) +{ + if (position.x < 0 || position.y < 0 || position.x >= MAXDUNX || position.y >= MAXDUNY) { + return false; + } + + return nSolidTable[dPiece[position.x][position.y]]; +} + +/** + * @brief Checks the position is solid or blocked by an object + */ +bool IsTileWalkable(Point position, bool ignoreDoors) +{ + if (dObject[position.x][position.y] != 0) { + int oi = abs(dObject[position.x][position.y]) - 1; + if (ignoreDoors && IsAnyOf(Objects[oi]._otype, OBJ_L1LDOOR, OBJ_L1RDOOR, OBJ_L2LDOOR, OBJ_L2RDOOR, OBJ_L3LDOOR, OBJ_L3RDOOR)) + return true; + if (Objects[oi]._oSolidFlag) + return false; + } + + return !IsTileSolid(position); +} + /** * find the shortest path from (sx,sy) to (dx,dy), using PosOk(PosOkArg,x,y) to * check that each step is a valid position. Store the step directions (see diff --git a/Source/path.h b/Source/path.h index 201bf116b..fb385dec5 100644 --- a/Source/path.h +++ b/Source/path.h @@ -26,6 +26,9 @@ struct PATHNODE { struct PATHNODE *NextNode; }; +bool IsTileNotSolid(Point position); +bool IsTileSolid(Point position); +bool IsTileWalkable(Point position, bool ignoreDoors = false); int FindPath(const std::function &posOk, int sx, int sy, int dx, int dy, int8_t path[MAX_PATH_LENGTH]); int path_get_h_cost(int sx, int sy, int dx, int dy); PATHNODE *GetNextPath(); diff --git a/Source/player.cpp b/Source/player.cpp index 9422e2f47..9f3f27692 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -147,11 +147,11 @@ bool PlrDirOK(int pnum, Direction dir) } if (dir == DIR_E) { - return !SolidLoc(position + DIR_SE) && (dFlags[position.x + 1][position.y] & BFLAG_PLAYERLR) == 0; + return !IsTileSolid(position + DIR_SE) && (dFlags[position.x + 1][position.y] & BFLAG_PLAYERLR) == 0; } if (dir == DIR_W) { - return !SolidLoc(position + DIR_SW) && (dFlags[position.x][position.y + 1] & BFLAG_PLAYERLR) == 0; + return !IsTileSolid(position + DIR_SW) && (dFlags[position.x][position.y + 1] & BFLAG_PLAYERLR) == 0; } return true; @@ -1292,15 +1292,6 @@ void InitMultiView() ViewY = myPlayer.position.tile.y; } -bool SolidLoc(Point position) -{ - if (position.x < 0 || position.y < 0 || position.x >= MAXDUNX || position.y >= MAXDUNY) { - return false; - } - - return nSolidTable[dPiece[position.x][position.y]]; -} - void PlrClrTrans(Point position) { for (int i = position.y - 1; i <= position.y + 1; i++) { @@ -3504,7 +3495,7 @@ bool PosOkPlayer(int pnum, Point position) return false; if (dPiece[position.x][position.y] == 0) return false; - if (SolidLoc(position)) + if (!IsTileWalkable(position)) return false; if (dPlayer[position.x][position.y] != 0) { int8_t p = -1; @@ -3533,18 +3524,6 @@ bool PosOkPlayer(int pnum, Point position) } } - if (dObject[position.x][position.y] != 0) { - int8_t bv = -1; - if (dObject[position.x][position.y] > 0) { - bv = dObject[position.x][position.y] - 1; - } else { - bv = -(dObject[position.x][position.y] + 1); - } - if (Objects[bv]._oSolidFlag) { - return false; - } - } - return true; } @@ -3559,7 +3538,7 @@ void MakePlrPath(int pnum, Point targetPosition, bool endspace) return; } - int path = FindPath(std::bind(PosOkPlayer, pnum, std::placeholders::_1), player.position.future.x, player.position.future.y, targetPosition.x, targetPosition.y, player.walkpath); + int path = FindPath([pnum](Point position) { return PosOkPlayer(pnum, position); }, player.position.future.x, player.position.future.y, targetPosition.x, targetPosition.y, player.walkpath); if (path == 0) { return; } diff --git a/Source/player.h b/Source/player.h index 7021053ca..5ceccffea 100644 --- a/Source/player.h +++ b/Source/player.h @@ -466,7 +466,6 @@ void AddPlrMonstExper(int lvl, int exp, char pmask); void ApplyPlrDamage(int pnum, int dam, int minHP = 0, int frac = 0, int earflag = 0); void InitPlayer(int pnum, bool FirstTime); void InitMultiView(); -bool SolidLoc(Point position); void PlrClrTrans(Point position); void PlrDoTrans(Point position); void SetPlayerOld(PlayerStruct &player);