void G_FinishTravel () { TThinkerIterator<APlayerPawn> it (STAT_TRAVELLING); APlayerPawn *pawn, *pawndup, *oldpawn, *next; AInventory *inv; FPlayerStart *start; int pnum; next = it.Next (); while ( (pawn = next) != NULL) { next = it.Next (); pnum = int(pawn->player - players); pawn->ChangeStatNum (STAT_PLAYER); pawndup = pawn->player->mo; start = NULL; assert (pawn != pawndup); if (pawndup == NULL) { // Oh no! there was no start for this player! start = G_PickPlayerStart(pnum, PPS_FORCERANDOM); if (start != NULL) pawndup = P_SpawnPlayer(start, pnum, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); if (pawndup == NULL) { pawn->flags |= MF_NOSECTOR | MF_NOBLOCKMAP; pawn->Destroy(); continue; } } 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->Pos()); } } 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 (pawndup != NULL) { if (!(changeflags & CHANGELEVEL_KEEPFACING)) { pawn->Angles = pawndup->Angles; } pawn->SetXYZ(pawndup->Pos()); pawn->Vel = pawndup->Vel; 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->target = NULL; pawn->lastenemy = NULL; pawn->player->mo = pawn; pawn->player->camera = pawn; pawn->player->viewheight = pawn->ViewHeight; pawn->flags2 &= ~MF2_BLASTED; DObject::StaticPointerSubstitution (oldpawn, pawn); oldpawn->Destroy(); if (pawndup != NULL) { pawndup->Destroy(); } pawn->LinkToWorld (); pawn->ClearInterpolation(); pawn->AddToHash (); pawn->SetState(pawn->SpawnState); pawn->player->SendPitchLimits(); for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory) { inv->ChangeStatNum (STAT_INVENTORY); inv->LinkToWorld (); inv->Travelled (); } if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED) { pawn->Speed = pawn->GetDefault()->Speed; } if (level.FromSnapshot) { FBehavior::StaticStartTypedScripts (SCRIPT_Return, pawn, true); } } bglobal.FinishTravel (); }
void G_FinishTravel () { TThinkerIterator<APlayerPawn> it (STAT_TRAVELLING); APlayerPawn *pawn, *pawndup, *oldpawn, *next; AInventory *inv; next = it.Next (); while ( (pawn = next) != NULL) { next = it.Next (); pawn->ChangeStatNum (STAT_PLAYER); pawndup = pawn->player->mo; assert (pawn != pawndup); if (pawndup == NULL) { // Oh no! there was no start for this player! pawn->flags |= MF_NOSECTOR|MF_NOBLOCKMAP; pawn->Destroy (); } else { 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 (&playerstarts[pawn->player - players], int(pawn->player - players), SPF_TEMPPLAYER); if (!(changeflags & CHANGELEVEL_KEEPFACING)) { pawn->angle = pawndup->angle; pawn->pitch = pawndup->pitch; } pawn->x = pawndup->x; pawn->y = pawndup->y; pawn->z = 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->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; pawn->player->camera = pawn; DObject::StaticPointerSubstitution (oldpawn, pawn); oldpawn->Destroy(); pawndup->Destroy (); pawn->LinkToWorld (); pawn->AddToHash (); pawn->SetState(pawn->SpawnState); pawn->player->SendPitchLimits(); for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory) { inv->ChangeStatNum (STAT_INVENTORY); inv->LinkToWorld (); inv->Travelled (); } if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED) { pawn->Speed = pawn->GetDefault()->Speed; } if (level.FromSnapshot) { FBehavior::StaticStartTypedScripts (SCRIPT_Return, pawn, true); } } } }
void G_FinishTravel () { TThinkerIterator<APlayerPawn> it (STAT_TRAVELLING); APlayerPawn *pawn, *pawndup, *oldpawn, *next; AInventory *inv; FPlayerStart *start; int pnum; next = it.Next (); while ( (pawn = next) != NULL) { next = it.Next (); pnum = int(pawn->player - players); pawn->ChangeStatNum (STAT_PLAYER); pawndup = pawn->player->mo; assert (pawn != pawndup); start = G_PickPlayerStart(pnum, 0); if (start == NULL) { if (pawndup != nullptr) { 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->Pos()); } else { // Could not find a start for this player at all. This really should never happen but if it does, let's better abort. DThinker::DestroyThinkersInList(STAT_TRAVELLING); I_Error ("No player %d start to travel to!\n", pnum + 1); } } 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 (pawndup != NULL) { if (!(changeflags & CHANGELEVEL_KEEPFACING)) { pawn->Angles = pawndup->Angles; } pawn->SetXYZ(pawndup->Pos()); pawn->Vel = pawndup->Vel; 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->target = NULL; pawn->lastenemy = NULL; pawn->player->mo = pawn; pawn->player->camera = pawn; pawn->player->viewheight = pawn->ViewHeight; pawn->flags2 &= ~MF2_BLASTED; if (oldpawn != nullptr) { DObject::StaticPointerSubstitution (oldpawn, pawn); oldpawn->Destroy(); } if (pawndup != NULL) { pawndup->Destroy(); } pawn->LinkToWorld (nullptr); pawn->ClearInterpolation(); pawn->AddToHash (); pawn->SetState(pawn->SpawnState); pawn->player->SendPitchLimits(); for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory) { inv->ChangeStatNum (STAT_INVENTORY); inv->LinkToWorld (nullptr); inv->Travelled (); } if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED) { pawn->Speed = pawn->GetDefault()->Speed; } if (level.FromSnapshot) { FBehavior::StaticStartTypedScripts (SCRIPT_Return, pawn, true); // [Nash] run REOPEN scripts upon map re-entry FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false); } } bglobal.FinishTravel (); // make sure that, after travelling has completed, no travelling thinkers are left. // Since this list is excluded from regular thinker cleaning, anything that may survive through here // will endlessly multiply and severely break the following savegames or just simply crash on broken pointers. DThinker::DestroyThinkersInList(STAT_TRAVELLING); }