From f836f9e145f20186e95290f442f72979ab0c78ee Mon Sep 17 00:00:00 2001 From: MIDIMan Date: Wed, 11 Dec 2024 14:34:52 -0500 Subject: [PATCH] Add thing argument to P_BlockThingsIterator and P_DoBlockThingsIterate --- src/p_enemy.c | 6 +-- src/p_map.c | 6 +-- src/p_maputl.c | 139 +++++++++++++++++++++++++++++++++++++------------ src/p_maputl.h | 4 +- src/p_mobj.c | 2 +- src/p_user.c | 2 +- 6 files changed, 116 insertions(+), 43 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 59ca95409..46c1cf50d 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5582,7 +5582,7 @@ void A_MinusDigging(mobj_t *actor) minus = actor; - P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_MinusCarry); + P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_MinusCarry, minus); } else { @@ -13726,7 +13726,7 @@ void A_DustDevilThink(mobj_t *actor) dustdevil = actor; - P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_DustDevilLaunch); + P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_DustDevilLaunch, dustdevil); //Whirlwind sound effect. if (leveltime % 70 == 0) @@ -13842,7 +13842,7 @@ void A_TNTExplode(mobj_t *actor) barrel = actor; - P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_TNTExplode); + P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_TNTExplode, barrel); // cause a quake -- P_StartQuake does not exist yet epicenter.x = actor->x; diff --git a/src/p_map.c b/src/p_map.c index 1116ae06a..126dd5b5f 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2264,7 +2264,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) { - if (!P_BlockThingsIterator(bx, by, PIT_CheckThing)) + if (!P_BlockThingsIterator(bx, by, PIT_CheckThing, tmthing)) blockval = false; else tmhitthing = tmfloorthing; @@ -2883,7 +2883,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) standx = x; standy = y; - P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_PushableMoved); + P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_PushableMoved, stand); } // Link the thing into its new position @@ -4229,7 +4229,7 @@ void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 dama bombdamagetype = damagetype; bombsightcheck = sightcheck; - P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_RadiusAttack); + P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_RadiusAttack, bombspot); } // diff --git a/src/p_maputl.c b/src/p_maputl.c index f10a396a3..e23872276 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -1050,10 +1050,14 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *)) // // P_BlockThingsIterator // -boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *)) +boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *), mobj_t *thing) { mobj_t *bnext = NULL; blocknode_t *block, *next = NULL; + + boolean checkthing = false; + if (thing) + checkthing = true; if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) return true; @@ -1071,7 +1075,7 @@ boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *)) return false; } - if (P_MobjWasRemoved(tmthing) // func just popped our tmthing, cannot continue. + if ((checkthing && P_MobjWasRemoved(thing)) // func just popped our tmthing, cannot continue. || (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue. { P_SetTarget(&bnext, NULL); @@ -1084,13 +1088,13 @@ boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *)) return true; } -boolean P_DoBlockThingsIterate(int x1, int y1, int x2, int y2, boolean (*func)(mobj_t *)) +boolean P_DoBlockThingsIterate(int x1, int y1, int x2, int y2, boolean (*func)(mobj_t *), mobj_t *thing) { boolean status = true; for (INT32 bx = x1; bx <= x2; bx++) for (INT32 by = y1; by <= y2; by++) - if (!P_BlockThingsIterator(bx, by, func)) + if (!P_BlockThingsIterator(bx, by, func, thing)) status = false; return status; @@ -1463,7 +1467,7 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2, INT32 flags, traverser_t trav) { fixed_t xt1, yt1, xt2, yt2; - fixed_t xstep, ystep, partial, xintercept, yintercept; + fixed_t xstep, ystep, partialx, partialy, xintercept, yintercept; INT32 mapx, mapy, mapxstep, mapystep, count; earlyout = flags & PT_EARLYOUT; @@ -1481,57 +1485,83 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2, trace.y = py1; trace.dx = px2 - px1; trace.dy = py2 - py1; - - px1 -= bmaporgx; - py1 -= bmaporgy; - xt1 = (unsigned)px1>>MAPBLOCKSHIFT; - yt1 = (unsigned)py1>>MAPBLOCKSHIFT; - - px2 -= bmaporgx; - py2 -= bmaporgy; - xt2 = (unsigned)px2>>MAPBLOCKSHIFT; - yt2 = (unsigned)py2>>MAPBLOCKSHIFT; + + xt1 = px1>>MAPBLOCKSHIFT; + yt1 = py2>>MAPBLOCKSHIFT; + px1 = (unsigned)(px1 - bmaporgx); + py1 = (unsigned)(py1 - bmaporgy); + + xt2 = px2>>MAPBLOCKSHIFT; + yt2 = py2>>MAPBLOCKSHIFT; + px2 = (unsigned)(px2 - bmaporgx); + py2 = (unsigned)(py2 - bmaporgy); if (xt2 > xt1) { mapxstep = 1; - partial = FRACUNIT - ((px1>>MAPBTOFRAC) & FRACMASK); + partialx = FRACUNIT - (((unsigned)px1>>MAPBTOFRAC) & FRACMASK); ystep = FixedDiv(py2 - py1, abs(px2 - px1)); } else if (xt2 < xt1) { mapxstep = -1; - partial = (px1>>MAPBTOFRAC) & FRACMASK; + partialx = ((unsigned)px1>>MAPBTOFRAC) & FRACMASK; ystep = FixedDiv(py2 - py1, abs(px2 - px1)); } else { mapxstep = 0; - partial = FRACUNIT; + partialx = FRACUNIT; ystep = 256*FRACUNIT; } - yintercept = (py1>>MAPBTOFRAC) + FixedMul(partial, ystep); + yintercept = ((unsigned)py1>>MAPBTOFRAC) + FixedMul(partialx, ystep); if (yt2 > yt1) { mapystep = 1; - partial = FRACUNIT - ((py1>>MAPBTOFRAC) & FRACMASK); + partialy = FRACUNIT - (((unsigned)py1>>MAPBTOFRAC) & FRACMASK); xstep = FixedDiv(px2 - px1, abs(py2 - py1)); } else if (yt2 < yt1) { mapystep = -1; - partial = (py1>>MAPBTOFRAC) & FRACMASK; + partialy = ((unsigned)py1>>MAPBTOFRAC) & FRACMASK; xstep = FixedDiv(px2 - px1, abs(py2 - py1)); } else { mapystep = 0; - partial = FRACUNIT; + partialy = FRACUNIT; xstep = 256*FRACUNIT; } - xintercept = (px1>>MAPBTOFRAC) + FixedMul(partial, xstep); + xintercept = ((unsigned)px1>>MAPBTOFRAC) + FixedMul(partialy, xstep); + + // [RH] Fix for traces that pass only through blockmap corners. In that case, + // xintercept and yintercept can both be set ahead of mapx and mapy, so the + // for loop would never advance anywhere. + + if (abs(xstep) == 1 && abs(ystep) == 1) + { + if (ystep < 0) + { + partialx = FRACUNIT - partialx; + } + if (xstep < 0) + { + partialy = FRACUNIT - partialy; + } + if (partialx == partialy) + { + xintercept = xt1; + yintercept = yt1; + } + } + + xt1 = (unsigned)px1>>MAPBLOCKSHIFT; + yt1 = (unsigned)py1>>MAPBLOCKSHIFT; + xt2 = (unsigned)px2>>MAPBLOCKSHIFT; + yt2 = (unsigned)py2>>MAPBLOCKSHIFT; // Step through map blocks. // Count is present to prevent a round off error @@ -1546,21 +1576,64 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2, return false; // early out if (flags & PT_ADDTHINGS) - if (!P_BlockThingsIterator(mapx, mapy, PIT_AddThingIntercepts)) + if (!P_BlockThingsIterator(mapx, mapy, PIT_AddThingIntercepts, NULL)) return false; // early out - if (mapx == xt2 && mapy == yt2) + // both coordinates reached the end, so end the traversing. + if ((mapxstep | mapystep) == 0) break; - if ((yintercept >> FRACBITS) == mapy) + // [RH] Handle corner cases properly instead of pretending they don't exist. + switch ((((yintercept >> FRACBITS) == mapy) << 1) | ((xintercept >> FRACBITS) == mapx)) { - yintercept += ystep; - mapx += mapxstep; - } - else if ((xintercept >> FRACBITS) == mapx) - { - xintercept += xstep; - mapy += mapystep; + case 0: // neither xintercept nor yintercept match! + count = 64; // Stop traversing, because somebody screwed up. + break; + + case 1: // xintercept matches + xintercept += xstep; + mapy += mapystep; + if (mapy == yt2) + mapystep = 0; + break; + + case 2: // yintercept matches + yintercept += ystep; + mapx += mapxstep; + if (mapx == xt2) + mapxstep = 0; + break; + + case 3: // xintercept and yintercept both match + // The trace is exiting a block through its corner. Not only does the block + // being entered need to be checked (which will happen when this loop + // continues), but the other two blocks adjacent to the corner also need to + // be checked. + if (flags & PT_ADDLINES) + { + if (!P_BlockLinesIterator(mapx + mapxstep, mapy, PIT_AddLineIntercepts)) + return false; // early out + if (!P_BlockLinesIterator(mapx, mapy + mapystep, PIT_AddLineIntercepts)) + return false; // early out + } + + if (flags & PT_ADDTHINGS) + { + if (!P_BlockThingsIterator(mapx + mapxstep, mapy, PIT_AddThingIntercepts, NULL)) + return false; // early out + if (!P_BlockThingsIterator(mapx, mapy + mapystep, PIT_AddThingIntercepts, NULL)) + return false; // early out + } + + xintercept += xstep; + yintercept += ystep; + mapx += mapxstep; + mapy += mapystep; + if (mapx == xt2) + mapxstep = 0; + if (mapy == yt2) + mapystep = 0; + break; } } // Go through the sorted list diff --git a/src/p_maputl.h b/src/p_maputl.h index 67f7fd086..11cc90c59 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -61,7 +61,7 @@ extern ffloor_t *openfloorrover, *openceilingrover; void P_LineOpening(line_t *plinedef, mobj_t *mobj); boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean(*func)(line_t *)); -boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean(*func)(mobj_t *)); +boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean(*func)(mobj_t *), mobj_t *thing); void P_ClearBlockNodes(void); @@ -94,7 +94,7 @@ typedef struct bthingit_s bthingit_t *P_NewBlockThingsIterator(int x1, int y1, int x2, int y2); mobj_t *P_BlockThingsIteratorNext(bthingit_t *it, boolean centeronly); void P_FreeBlockThingsIterator(bthingit_t *it); -boolean P_DoBlockThingsIterate(int x1, int y1, int x2, int y2, boolean (*func)(mobj_t *)); +boolean P_DoBlockThingsIterate(int x1, int y1, int x2, int y2, boolean (*func)(mobj_t *), mobj_t *thing); #define PT_ADDLINES 1 #define PT_ADDTHINGS 2 diff --git a/src/p_mobj.c b/src/p_mobj.c index fb9e7d78e..014ae4fab 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9342,7 +9342,7 @@ static void P_PointPushThink(mobj_t *mobj) yl = (unsigned)(mobj->y - radius - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; yh = (unsigned)(mobj->y + radius - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; - P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_PushThing); + P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_PushThing, pushmobj); } static boolean P_MobjRegularThink(mobj_t *mobj) diff --git a/src/p_user.c b/src/p_user.c index a2bae228b..080ff6dbf 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4126,7 +4126,7 @@ static void P_DoTeeter(player_t *player) teeteryl = teeteryh = player->mo->y; couldteeter = false; solidteeter = teeter; - if (!P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_CheckSolidsTeeter)) + if (!P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_CheckSolidsTeeter, tmthing)) goto teeterdone; // we've found something that stops us teetering at all teeterdone: teeter = solidteeter;