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); 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/g_level.cpp b/src/g_level.cpp index ffbda6e99..a8d302db5 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 (); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 36b6b9a0c..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)) { @@ -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 diff --git a/src/p_map.cpp b/src/p_map.cpp index a277c7b77..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; @@ -2405,11 +2406,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)) { @@ -5251,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_mobj.cpp b/src/p_mobj.cpp index 87fe34837..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); } @@ -4603,6 +4615,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; 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 { diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 76c5036a0..85887878c 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -2277,7 +2277,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/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; 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)))