diff --git a/src/p_mapthing.cpp b/src/p_mapthing.cpp index 034ed29ca..4163307fe 100644 --- a/src/p_mapthing.cpp +++ b/src/p_mapthing.cpp @@ -1,3 +1,9 @@ +#include +#include +#include + +#include "core/static_vec.hpp" + #include "doomstat.h" // mapobjectscale #include "info.h" #include "m_fixed.h" @@ -13,20 +19,60 @@ fixed_t P_GetMobjSpawnHeight( const fixed_t y, const fixed_t dz, const fixed_t offset, + const size_t layer, const boolean flip, const fixed_t scale ) { const fixed_t finalScale = FixedMul(scale, mapobjectscale); + + const fixed_t finalZOffset = flip + ? -(dz) - FixedMul(finalScale, offset + mobjinfo[mobjtype].height) + : +(dz) + FixedMul(finalScale, offset); + const sector_t* sector = R_PointInSubsector(x, y)->sector; // Axis objects snap to the floor. if (mobjtype == MT_AXIS || mobjtype == MT_AXISTRANSFER || mobjtype == MT_AXISTRANSFERLINE) return ONFLOORZ; + if (layer != 0) + { + // multiset is a container that automatically sorts + // each insertion. It only contains unique values, so + // two FOFs at the exact same height only count as one + // layer. + std::multiset heights; + + auto get_height = flip ? P_GetFFloorBottomZAt : P_GetFFloorTopZAt; + + for (ffloor_t* rover = sector->ffloors; rover; rover = rover->next) + { + heights.insert(get_height(rover, x, y)); + } + + if (!heights.empty()) + { + auto get_layer = [layer, &heights](auto it) + { + std::advance(it, std::min(layer, heights.size()) - 1); + return *it; + }; + + if (flip) + { + return get_layer(heights.rbegin()) + finalZOffset; + } + else + { + return get_layer(heights.begin()) + finalZOffset; + } + } + } + // Establish height. if (flip) - return P_GetSectorCeilingZAt(sector, x, y) - dz - FixedMul(finalScale, offset + mobjinfo[mobjtype].height); + return P_GetSectorCeilingZAt(sector, x, y) + finalZOffset; else - return P_GetSectorFloorZAt(sector, x, y) + dz + FixedMul(finalScale, offset); + return P_GetSectorFloorZAt(sector, x, y) + finalZOffset; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 7abbfd8bd..4d8451648 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12120,7 +12120,7 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt break; } - if (!(dz + offset)) // Snap to the surfaces when there's no offset set. + if (!(dz + offset) && mthing->layer == 0) // Snap to the surfaces when there's no offset set. { if (flip) return ONCEILINGZ; @@ -12128,7 +12128,7 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt return ONFLOORZ; } - return P_GetMobjSpawnHeight(mobjtype, x, y, dz, offset, flip, mthing->scale); + return P_GetMobjSpawnHeight(mobjtype, x, y, dz, offset, mthing->layer, flip, mthing->scale); } static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing) @@ -13487,7 +13487,7 @@ void P_SpawnHoop(mapthing_t *mthing) TVector v, *res; fixed_t x = mthing->x << FRACBITS; fixed_t y = mthing->y << FRACBITS; - fixed_t z = P_GetMobjSpawnHeight(MT_HOOP, x, y, mthing->z << FRACBITS, 0, false, mthing->scale); + fixed_t z = P_GetMobjSpawnHeight(MT_HOOP, x, y, mthing->z << FRACBITS, 0, mthing->layer, false, mthing->scale); hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); hoopcenter->spawnpoint = mthing; @@ -13609,7 +13609,7 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi itemtypes[r] = P_GetMobjtypeSubstitute(&dummything, itemtypes[r]); } } - z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, 0, mthing->options & MTF_OBJECTFLIP, mthing->scale); + z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, 0, mthing->layer, mthing->options & MTF_OBJECTFLIP, mthing->scale); if (isloopend) { @@ -13689,7 +13689,7 @@ static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 n itemtypes[i] = P_GetMobjtypeSubstitute(&dummything, itemtypes[i]); } } - z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, 0, false, mthing->scale); + z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, 0, mthing->layer, false, mthing->scale); for (i = 0; i < numitems; i++) { diff --git a/src/p_mobj.h b/src/p_mobj.h index 3ee45aedd..56c95a7c3 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -524,7 +524,7 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing); void P_MovePlayerToStarpost(INT32 playernum); void P_AfterPlayerSpawn(INT32 playernum); -fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale); +fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const size_t layer, const boolean flip, const fixed_t scale); fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y); mobj_t *P_SpawnMapThing(mapthing_t *mthing);