diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 8dccbae79..71f4acb07 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -3156,30 +3156,18 @@ void MI_HorkSpawn(Missile &missile) CheckMissileCol(missile, 0, 0, false, missile.position.tile, false); if (missile._mirange <= 0) { missile._miDelFlag = true; - for (int i = 0; i < 2; i++) { - int k = CrawlNum[i]; - int ck = k + 2; - for (auto j = static_cast(CrawlTable[k]); j > 0; j--, ck += 2) { - Point target = missile.position.tile + Displacement { CrawlTable[ck - 1], CrawlTable[ck] }; - if (!InDungeonBounds(target)) - continue; - - if (nSolidTable[dPiece[target.x][target.y]]) - continue; - if (dMonster[target.x][target.y] != 0) - continue; - if (dPlayer[target.x][target.y] != 0) - continue; - if (dObject[target.x][target.y] != 0) - continue; - - auto md = static_cast(missile.var1); - int monsterId = AddMonster(target, md, 1, true); - if (monsterId != -1) - M_StartStand(Monsters[monsterId], md); - i = 6; - break; + std::optional spawnPosition = FindClosestValidPosition( + [](Point target) { + return !IsTileOccupied(target); + }, + missile.position.tile, 0, 1); + + if (spawnPosition) { + auto facing = static_cast(missile.var1); + int monsterId = AddMonster(*spawnPosition, facing, 1, true); + if (monsterId != -1) { + M_StartStand(Monsters[monsterId], facing); } } } else { diff --git a/Source/path.cpp b/Source/path.cpp index a0eff10cb..37abffe09 100644 --- a/Source/path.cpp +++ b/Source/path.cpp @@ -316,6 +316,28 @@ bool IsTileWalkable(Point position, bool ignoreDoors) return !IsTileSolid(position); } +bool IsTileOccupied(Point position) +{ + if (!InDungeonBounds(position)) { + return true; // OOB positions are considered occupied. + } + + if (IsTileSolid(position)) { + return true; + } + if (dMonster[position.x][position.y] != 0) { + return true; + } + if (dPlayer[position.x][position.y] != 0) { + return true; + } + if (dObject[position.x][position.y] != 0) { + return true; + } + + return false; +} + int FindPath(const std::function &posOk, Point startPosition, Point destinationPosition, int8_t path[MAX_PATH_LENGTH]) { /** diff --git a/Source/path.h b/Source/path.h index 9ccd806e5..e0838fd1b 100644 --- a/Source/path.h +++ b/Source/path.h @@ -35,6 +35,11 @@ bool IsTileSolid(Point position); */ bool IsTileWalkable(Point position, bool ignoreDoors = false); +/** + * @brief Checks if the position contains an object, player, monster, or solid dungeon piece +*/ +bool IsTileOccupied(Point position); + /** * @brief Find the shortest path from startPosition to destinationPosition, using PosOk(Point) to check that each step is a valid position. * Store the step directions (corresponds to an index in PathDirs) in path, which must have room for 24 steps