From 48b6b6e0576fd7b21bfc415079cfffcee0da090f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 8 Mar 2016 19:53:37 -0600 Subject: [PATCH 1/9] Clip portals to viewheight, not screen height - Aside, but is this even neccessary? The arrays being copied from should already be clipped properly. --- src/r_segs.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 06c5034c6..eca7adc88 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2643,12 +2643,12 @@ void R_StoreWallRange (int start, int stop) { if (pds.ceilingclip[i] < 0) pds.ceilingclip[i] = 0; - if (pds.ceilingclip[i] >= RenderTarget->GetHeight()) - pds.ceilingclip[i] = RenderTarget->GetHeight()-1; + if (pds.ceilingclip[i] >= viewheight) + pds.ceilingclip[i] = viewheight-1; if (pds.floorclip[i] < 0) pds.floorclip[i] = 0; - if (pds.floorclip[i] >= RenderTarget->GetHeight()) - pds.floorclip[i] = RenderTarget->GetHeight()-1; + if (pds.floorclip[i] >= viewheight) + pds.floorclip[i] = viewheight-1; } pds.mirror = curline->linedef->special == Line_Mirror; From 174e00afe7c408ba8c32a964fe15eac64a49397a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 8 Mar 2016 21:42:24 -0600 Subject: [PATCH 2/9] Add NULL mthing check to P_SpawnPlayer --- src/p_mobj.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 87fe34837..04e90273f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4603,6 +4603,10 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) fixed_t spawn_x, spawn_y, spawn_z; angle_t spawn_angle; + if (mthing == NULL) + { + return NULL; + } // not playing? if ((unsigned)playernum >= (unsigned)MAXPLAYERS || !playeringame[playernum]) return NULL; From 76489e76386426dd86841b67994c3ec766e71cdc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 8 Mar 2016 21:51:12 -0600 Subject: [PATCH 3/9] More gracefully handle travelling to a map without matching player starts - First, don't crash when travelling to a map in a hub that doesn't have any player starts that match the position given to Teleport_NewMap (or equivalent). - Seconed, move the player to the location they were at when the left the level. At least that way, they shouldn't be in random geometry or off the map entirely. --- src/g_level.cpp | 59 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index ab0746617..7827121d7 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1221,32 +1221,48 @@ void G_FinishTravel () } } - if (start == NULL) start = G_PickPlayerStart(pnum, 0); + if (start == NULL) + { + start = G_PickPlayerStart(pnum, 0); + if (start == NULL) + { + Printf(TEXTCOLOR_RED "No player %d start to travel to!\n", pnum + 1); + // Move to the coordinates this player had when they left the level. + pawn->SetXYZ(pawndup->X(), pawndup->Y(), pawndup->Z()); + } + } oldpawn = pawndup; // The player being spawned here is a short lived dummy and // must not start any ENTER script or big problems will happen. pawndup = P_SpawnPlayer(start, pnum, SPF_TEMPPLAYER); - if (!(changeflags & CHANGELEVEL_KEEPFACING)) + if (pawndup != NULL) { - pawn->angle = pawndup->angle; - pawn->pitch = pawndup->pitch; + if (!(changeflags & CHANGELEVEL_KEEPFACING)) + { + pawn->angle = pawndup->angle; + pawn->pitch = pawndup->pitch; + } + pawn->SetXYZ(pawndup->X(), pawndup->Y(), pawndup->Z()); + pawn->velx = pawndup->velx; + pawn->vely = pawndup->vely; + pawn->velz = pawndup->velz; + pawn->Sector = pawndup->Sector; + pawn->floorz = pawndup->floorz; + pawn->ceilingz = pawndup->ceilingz; + pawn->dropoffz = pawndup->dropoffz; + pawn->floorsector = pawndup->floorsector; + pawn->floorpic = pawndup->floorpic; + pawn->floorterrain = pawndup->floorterrain; + pawn->ceilingsector = pawndup->ceilingsector; + pawn->ceilingpic = pawndup->ceilingpic; + pawn->floorclip = pawndup->floorclip; + pawn->waterlevel = pawndup->waterlevel; + } + else + { + P_FindFloorCeiling(pawn); } - pawn->SetXYZ(pawndup->X(), pawndup->Y(), pawndup->Z()); - pawn->velx = pawndup->velx; - pawn->vely = pawndup->vely; - pawn->velz = pawndup->velz; - pawn->Sector = pawndup->Sector; - pawn->floorz = pawndup->floorz; - pawn->ceilingz = pawndup->ceilingz; - pawn->dropoffz = pawndup->dropoffz; - pawn->floorsector = pawndup->floorsector; - pawn->floorpic = pawndup->floorpic; - pawn->floorterrain = pawndup->floorterrain; - pawn->ceilingsector = pawndup->ceilingsector; - pawn->ceilingpic = pawndup->ceilingpic; - pawn->floorclip = pawndup->floorclip; - pawn->waterlevel = pawndup->waterlevel; pawn->target = NULL; pawn->lastenemy = NULL; pawn->player->mo = pawn; @@ -1255,7 +1271,10 @@ void G_FinishTravel () pawn->flags2 &= ~MF2_BLASTED; DObject::StaticPointerSubstitution (oldpawn, pawn); oldpawn->Destroy(); - pawndup->Destroy (); + if (pawndup != NULL) + { + pawndup->Destroy(); + } pawn->LinkToWorld (); pawn->ClearInterpolation(); pawn->AddToHash (); From 03118d441f03fdaffe90240abe988c9222f438f7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 8 Mar 2016 22:00:16 -0600 Subject: [PATCH 4/9] Don't use _FPU_GETCW if it won't do what we want - _FPU_GETCW is defined for more than just x87. Don't use it if the control word for the target architecture doesn't support _FPU_EXTENDED or _FPU_DOUBLE defined, e.g. pretty much anything but x87. If I had been using glibc on PowerPC instead of Apple's libc, I probably would have noticed this sooner, since _FPU_GETCW is part of glibc. --- src/d_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index accb6c247..84e03cdaa 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1973,7 +1973,7 @@ static void D_DoomInit() // Set the FPU precision to 53 significant bits. This is the default // for Visual C++, but not for GCC, so some slight math variances // might crop up if we leave it alone. -#if defined(_FPU_GETCW) +#if defined(_FPU_GETCW) && defined(_FPU_EXTENDED) && defined(_FPU_DOUBLE) { int cw; _FPU_GETCW(cw); From b3f7a57518f7b698d48de17c1066cf2c86082d40 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 9 Mar 2016 11:44:01 +0100 Subject: [PATCH 5/9] - yet another case of adding a workaround to preserve a side effect in Doom's original movement code that's bound to be inadvertently exploited: When a spechit results in teleportation, P_TryMove never accounted for that, so that subsequent spechits either failed or succeeded, depending on where the teleport ends up. With portal-aware positions stored within the spechit this no longer worked, so some handling is needed to revert to the original behavior in case there's no portals to consider. The ideal solution would have been to stop checking spechits (or to block further teleports) once this happens but the likelihood of some old maps depending on this is high. --- src/p_map.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index a277c7b77..181e730b7 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2405,11 +2405,18 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP))) { spechit_t spec; + fixedvec3 lastpos = thing->Pos(); while (spechit.Pop(spec)) { line_t *ld = spec.line; // see if the line was crossed - side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, ld); + + // One more case of trying to preserve some side effects from the original: + // If the reference position is the same as the actor's position before checking the spechits, + // we use the thing's actual position, including all the side effects of the original. + // If some portal transition has to be considered here, we cannot do that and use the reference position stored with the spechit. + bool posisoriginal = (spec.refpos.x == lastpos.x && spec.refpos.y == lastpos.y); + side = posisoriginal? P_PointOnLineSide(thing->X(), thing->Y(), ld) : P_PointOnLineSide(spec.refpos.x, spec.refpos.y, ld); oldside = P_PointOnLineSide(spec.oldrefpos.x, spec.oldrefpos.y, ld); if (side != oldside && ld->special && !(thing->flags6 & MF6_NOTRIGGER)) { From 40ceb0fef6477bcac8a838a4a239d9cd5dfa2d15 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 9 Mar 2016 12:00:07 +0100 Subject: [PATCH 6/9] - fixed: NextHighestCeilingAt and NextLowestFloorAt need to check if a 3D floor is outside the sector's boundaries before reporting it as the best match. --- src/p_sectors.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index c0b19cef9..d9cd733cb 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -940,12 +940,13 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flag while (true) { // Looking through planes from bottom to top + fixed_t realceil = sec->ceilingplane.ZatPoint(x, y); for (int i = sec->e->XFloor.ffloors.Size() - 1; i >= 0; --i) { F3DFloor *ff = sec->e->XFloor.ffloors[i]; fixed_t ffz = ff->bottom.plane->ZatPoint(x, y); - if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && z <= ffz) + if (ffz < realceil && ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && z <= ffz)) { // This floor is above our eyes. if (resultsec) *resultsec = sec; if (resultffloor) *resultffloor = ff; @@ -956,7 +957,7 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flag { // Use sector's floor if (resultffloor) *resultffloor = NULL; if (resultsec) *resultsec = sec; - return sec->ceilingplane.ZatPoint(x, y); + return realceil; } else { @@ -977,17 +978,19 @@ fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags, { // Looking through planes from top to bottom unsigned numff = sec->e->XFloor.ffloors.Size(); + fixed_t realfloor = sec->floorplane.ZatPoint(x, y); for (unsigned i = 0; i < numff; ++i) { F3DFloor *ff = sec->e->XFloor.ffloors[i]; - fixed_t ffz = ff->top.plane->ZatPoint(x, y); - fixed_t ffb = ff->bottom.plane->ZatPoint(x, y); // either with feet above the 3D floor or feet with less than 'stepheight' map units inside if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID)) { - if (z >= ffz || (!(flags & FFCF_3DRESTRICT) && (ffb < z && ffz < z + steph))) + fixed_t ffz = ff->top.plane->ZatPoint(x, y); + fixed_t ffb = ff->bottom.plane->ZatPoint(x, y); + + if (ffz > realfloor && (z >= ffz || (!(flags & FFCF_3DRESTRICT) && (ffb < z && ffz < z + steph)))) { // This floor is beneath our feet. if (resultsec) *resultsec = sec; if (resultffloor) *resultffloor = ff; @@ -999,7 +1002,7 @@ fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags, { // Use sector's floor if (resultffloor) *resultffloor = NULL; if (resultsec) *resultsec = sec; - return sec->floorplane.ZatPoint(x, y); + return realfloor; } else { From a605913f425ebe6790b859648f1c65a8c4773001 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 9 Mar 2016 12:49:49 +0100 Subject: [PATCH 7/9] - fixed: When passing through a teleporter or portal that alters the angle, it is not sufficient that P_XYMovement adjusts the position in case a second P_TryMove call is needed, it must also change the precalculated movement vector. --- src/p_mobj.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 04e90273f..cf084c433 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1983,7 +1983,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) FCheckPosition tm(!!(mo->flags2 & MF2_RIP)); - + angle_t oldangle = mo->angle; do { if (i_compatflags & COMPATF_WALLRUN) pushtime++; @@ -2213,13 +2213,25 @@ explode: // If the new position does not match the desired position, the player // must have gone through a teleporter, so stop moving right now if it // was a regular teleporter. If it was a line-to-line or fogless teleporter, - // the move should continue, but startx and starty need to change. + // the move should continue, but startx, starty and xmove, ymove need to change. if (mo->velx == 0 && mo->vely == 0) { step = steps; } else { + angle_t anglediff = (mo->angle - oldangle) >> ANGLETOFINESHIFT; + + if (anglediff != 0) + { + fixed_t xnew = FixedMul(xmove, finecosine[anglediff]) - FixedMul(ymove, finesine[anglediff]); + fixed_t ynew = FixedMul(xmove, finesine[anglediff]) + FixedMul(ymove, finecosine[anglediff]); + + xmove = xnew; + ymove = ynew; + oldangle = mo->angle; // in case more moves are needed this needs to be updated. + } + startx = mo->X() - Scale (xmove, step, steps); starty = mo->Y() - Scale (ymove, step, steps); } From 3063312f7f01529b7cef8f9a23fed18fca3bd923 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 10 Mar 2016 10:25:44 +0200 Subject: [PATCH 8/9] Fixed resurrection distance check See http://forum.zdoom.org/viewtopic.php?t=51177 --- src/p_enemy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 36b6b9a0c..9a7851277 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2618,8 +2618,8 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) // use the current actor's radius instead of the Arch Vile's default. fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; - if (abs(cres.position.x - viletry.x) > maxdist || - abs(cres.position.y - viletry.y) > maxdist) + if (abs(corpsehit->Pos().x - cres.position.x) > maxdist || + abs(corpsehit->Pos().y - cres.position.y) > maxdist) continue; // not actually touching // Let's check if there are floors in between the archvile and its target From 3d367d585df63e810606d9cb4ffa8ebdbe0f77cf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 10 Mar 2016 14:22:18 +0100 Subject: [PATCH 9/9] - did some profiling which revealed that P_PointInSector was called needlessly often. Did some optimization to the MultiBlock iterators to avoid this problem. --- src/dthinker.cpp | 2 +- src/p_enemy.cpp | 2 +- src/p_map.cpp | 11 ++++++----- src/p_maputl.cpp | 23 +++++++++++++---------- src/p_maputl.h | 6 ++++-- src/p_spec.cpp | 2 +- src/thingdef/thingdef_codeptr.cpp | 2 +- 7 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 93096b5c3..230d0dd41 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -576,6 +576,6 @@ DThinker *FThinkerIterator::Next () ADD_STAT (think) { FString out; - out.Format ("Think time = %04.1f ms, Action = %04.1f ms", ThinkCycles.TimeMS(), ActionCycles.TimeMS()); + out.Format ("Think time = %04.2f ms, Action = %04.2f ms", ThinkCycles.TimeMS(), ActionCycles.TimeMS()); return out; } diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 9a7851277..2d8d4980c 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2607,7 +2607,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) FPortalGroupArray check(FPortalGroupArray::PGA_Full3d); - FMultiBlockThingsIterator it(check, viletry.x, viletry.y, self->Z() - 64* FRACUNIT, self->Top() + 64 * FRACUNIT, 32 * FRACUNIT); + FMultiBlockThingsIterator it(check, viletry.x, viletry.y, self->Z() - 64* FRACUNIT, self->Top() + 64 * FRACUNIT, 32 * FRACUNIT, false, NULL); FMultiBlockThingsIterator::CheckResult cres; while (it.Next(&cres)) { diff --git a/src/p_map.cpp b/src/p_map.cpp index 181e730b7..0b7d6fc05 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -431,9 +431,10 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra // P_LineOpening requires the thing's z to be the destination z in order to work. fixed_t savedz = thing->Z(); thing->SetZ(z); + sector_t *sector = P_PointInSector(x, y); FPortalGroupArray grouplist; - FMultiBlockLinesIterator mit(grouplist, x, y, z, thing->height, thing->radius); + FMultiBlockLinesIterator mit(grouplist, x, y, z, thing->height, thing->radius, sector); FMultiBlockLinesIterator::CheckResult cres; while (mit.Next(&cres)) @@ -444,7 +445,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz; - FMultiBlockThingsIterator mit2(grouplist, x, y, z, thing->height, thing->radius); + FMultiBlockThingsIterator mit2(grouplist, x, y, z, thing->height, thing->radius, false, sector); FMultiBlockThingsIterator::CheckResult cres2; while (mit2.Next(&cres2)) @@ -1670,7 +1671,7 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo FBoundingBox box(x, y, thing->radius); FPortalGroupArray pcheck; - FMultiBlockThingsIterator it2(pcheck, x, y, thing->Z(), thing->height, thing->radius); + FMultiBlockThingsIterator it2(pcheck, x, y, thing->Z(), thing->height, thing->radius, false, newsec); FMultiBlockThingsIterator::CheckResult tcres; while ((it2.Next(&tcres))) @@ -1740,7 +1741,7 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo spechit.Clear(); portalhit.Clear(); - FMultiBlockLinesIterator it(pcheck, x, y, thing->Z(), thing->height, thing->radius); + FMultiBlockLinesIterator it(pcheck, x, y, thing->Z(), thing->height, thing->radius, newsec); FMultiBlockLinesIterator::CheckResult lcres; fixed_t thingdropoffz = tm.floorz; @@ -5258,7 +5259,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo double bombdamagefloat = (double)bombdamage; FPortalGroupArray grouplist(FPortalGroupArray::PGA_Full3d); - FMultiBlockThingsIterator it(grouplist, bombspot->X(), bombspot->Y(), bombspot->Z() - bombdistfix, bombspot->height + bombdistfix*2, bombdistfix); + FMultiBlockThingsIterator it(grouplist, bombspot->X(), bombspot->Y(), bombspot->Z() - bombdistfix, bombspot->height + bombdistfix*2, bombdistfix, false, bombspot->Sector); FMultiBlockThingsIterator::CheckResult cres; if (flags & RADF_SOURCEISSPOT) diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 55ce03470..526626b22 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -741,16 +741,19 @@ FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AAc if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist); checkpoint.z = checkradius == -1? origin->radius : checkradius; basegroup = origin->Sector->PortalGroup; + startsector = origin->Sector; Reset(); } -FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius) +FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, sector_t *newsec) : checklist(check) { checkpoint.x = checkx; checkpoint.y = checky; checkpoint.z = checkz; - basegroup = P_PointInSector(checkx, checky)->PortalGroup; + if (newsec == NULL) newsec = P_PointInSector(checkx, checky); + startsector = newsec; + basegroup = newsec->PortalGroup; if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist); checkpoint.z = checkradius; Reset(); @@ -766,10 +769,9 @@ bool FMultiBlockLinesIterator::GoUp(fixed_t x, fixed_t y) { if (continueup) { - sector_t *sector = P_PointInSector(x, y); - if (!sector->PortalBlocksMovement(sector_t::ceiling)) + if (!cursector->PortalBlocksMovement(sector_t::ceiling)) { - startIteratorForGroup(sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); + startIteratorForGroup(cursector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); portalflags = FFCF_NOFLOOR; return true; } @@ -788,10 +790,9 @@ bool FMultiBlockLinesIterator::GoDown(fixed_t x, fixed_t y) { if (continuedown) { - sector_t *sector = P_PointInSector(x, y); - if (!sector->PortalBlocksMovement(sector_t::floor)) + if (!cursector->PortalBlocksMovement(sector_t::floor)) { - startIteratorForGroup(sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup); + startIteratorForGroup(cursector->SkyBoxes[sector_t::floor]->Sector->PortalGroup); portalflags = FFCF_NOCEILING; return true; } @@ -871,6 +872,7 @@ void FMultiBlockLinesIterator::startIteratorForGroup(int group) offset = Displacements.getOffset(basegroup, group); offset.x += checkpoint.x; offset.y += checkpoint.y; + cursector = group == startsector->PortalGroup ? startsector : P_PointInSector(offset.x, offset.y); bbox.setBox(offset.x, offset.y, checkpoint.z); blockIterator.init(bbox); } @@ -1076,13 +1078,14 @@ FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, A Reset(); } -FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, bool ignorerestricted) +FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, bool ignorerestricted, sector_t *newsec) : checklist(check) { checkpoint.x = checkx; checkpoint.y = checky; checkpoint.z = checkz; - basegroup = P_PointInSector(checkx, checky)->PortalGroup; + if (newsec == NULL) newsec = P_PointInSector(checkx, checky); + basegroup = newsec->PortalGroup; if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist); checkpoint.z = checkradius; Reset(); diff --git a/src/p_maputl.h b/src/p_maputl.h index 7f045c24f..6ef5aa6c8 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -218,6 +218,8 @@ class FMultiBlockLinesIterator FPortalGroupArray &checklist; fixedvec3 checkpoint; fixedvec2 offset; + sector_t *startsector; + sector_t *cursector; short basegroup; short portalflags; short index; @@ -240,7 +242,7 @@ public: }; FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1); - FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius); + FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, sector_t *newsec); bool Next(CheckResult *item); void Reset(); // for stopping group traversal through portals. Only the calling code can decide whether this is needed so this needs to be set from the outside. @@ -325,7 +327,7 @@ public: }; FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1, bool ignorerestricted = false); - FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, bool ignorerestricted = false); + FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, bool ignorerestricted, sector_t *newsec); bool Next(CheckResult *item); void Reset(); const FBoundingBox &Box() const diff --git a/src/p_spec.cpp b/src/p_spec.cpp index c60529a60..ece79c2fb 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -2250,7 +2250,7 @@ void DPusher::Tick () // point pusher. Crosses sectors, so use blockmap. FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals); // no sector portals because this thing is utterly z-unaware. - FMultiBlockThingsIterator it(check, m_X, m_Y, 0, 0, m_Radius); + FMultiBlockThingsIterator it(check, m_X, m_Y, 0, 0, m_Radius, false, m_Source->Sector); FMultiBlockThingsIterator::CheckResult cres; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 072059901..a807fb7fd 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5583,7 +5583,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) { FPortalGroupArray check(FPortalGroupArray::PGA_Full3d); fixed_t mid = self->Z() + self->height / 2; - FMultiBlockThingsIterator it(check, self->X(), self->Y(), mid-distance, mid+distance, distance); + FMultiBlockThingsIterator it(check, self->X(), self->Y(), mid-distance, mid+distance, distance, false, self->Sector); FMultiBlockThingsIterator::CheckResult cres; while ((it.Next(&cres)))