Пример #1
0
DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition)
{
	PARAM_ACTION_PROLOGUE;

	// Move item back to its original location
	DVector2 sp = self->SpawnPoint;

	self->UnlinkFromWorld();
	self->SetXY(sp);
	self->LinkToWorld(true);
	self->SetZ(self->Sector->floorplane.ZatPoint(sp));
	P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS | FFCF_NOPORTALS);	// no portal checks here so that things get spawned in this sector.

	if (self->flags & MF_SPAWNCEILING)
	{
		self->SetZ(self->ceilingz - self->Height - self->SpawnPoint.Z);
	}
	else if (self->flags2 & MF2_SPAWNFLOAT)
	{
		double space = self->ceilingz - self->Height - self->floorz;
		if (space > 48)
		{
			space -= 40;
			self->SetZ((space * pr_restore()) / 256. + self->floorz + 40);
		}
		else
		{
			self->SetZ(self->floorz);
		}
	}
	else
	{
		self->SetZ(self->SpawnPoint.Z + self->floorz);
	}
	// Redo floor/ceiling check, in case of 3D floors and portals
	P_FindFloorCeiling(self, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT);
	if (self->Z() < self->floorz)
	{ // Do not reappear under the floor, even if that's where we were for the
	  // initial spawn.
		self->SetZ(self->floorz);
	}
	if ((self->flags & MF_SOLID) && (self->Top() > self->ceilingz))
	{ // Do the same for the ceiling.
		self->SetZ(self->ceilingz - self->Height);
	}
	// Do not interpolate from the position the actor was at when it was
	// picked up, in case that is different from where it is now.
	self->ClearInterpolation();
	return 0;
}
Пример #2
0
DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition)
{
	// Move item back to its original location
	fixed_t _x, _y;
	sector_t *sec;

	_x = self->SpawnPoint[0];
	_y = self->SpawnPoint[1];

	self->UnlinkFromWorld();
	self->x = _x;
	self->y = _y;
	self->LinkToWorld(true);
	sec = self->Sector;
	self->z =
	self->dropoffz =
	self->floorz = sec->floorplane.ZatPoint(_x, _y);
	self->ceilingz = sec->ceilingplane.ZatPoint(_x, _y);
	P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS);

	if (self->flags & MF_SPAWNCEILING)
	{
		self->z = self->ceilingz - self->height - self->SpawnPoint[2];
	}
	else if (self->flags2 & MF2_SPAWNFLOAT)
	{
		fixed_t space = self->ceilingz - self->height - self->floorz;
		if (space > 48*FRACUNIT)
		{
			space -= 40*FRACUNIT;
			self->z = ((space * pr_restore())>>8) + self->floorz + 40*FRACUNIT;
		}
Пример #3
0
void AInventory::BecomePickup ()
{
	if (Owner != NULL)
	{
		Owner->RemoveInventory (this);
	}
	if (flags & (MF_NOBLOCKMAP|MF_NOSECTOR))
	{
		UnlinkFromWorld ();
		flags &= ~(MF_NOBLOCKMAP|MF_NOSECTOR);
		LinkToWorld ();
		P_FindFloorCeiling (this);
	}
	flags = (GetDefault()->flags | MF_DROPPED) & ~MF_COUNTITEM;
	renderflags &= ~RF_INVISIBLE;
	SetState (SpawnState);
}
Пример #4
0
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 ();
}
Пример #5
0
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);
}
Пример #6
0
// Shift stuff back in time before doing hitscan calculations
// Call UNLAGGED_Restore afterwards to restore everything
void UNLAGGED_Reconcile( AActor *actor )
{
	//Only do anything if the actor to be reconciled is a player,
	//it's on a server with unlagged on, and reconciliation is not being blocked
	if ( !actor->player || (NETWORK_GetState() != NETSTATE_SERVER) || ( dmflags3 & DF3_NOUNLAGGED ) ||
		 ( actor->player->userinfo.bUnlagged == false ) || ( reconciliationBlockers > 0 ) )
		return;

	//Something went wrong, reconciliation was attempted when the gamestate
	//was already reconciled!
	if (reconciledGame)
	{
		// [BB] I_Error terminates the current game, so we need to reset the value of reconciledGame,
		// otherwise UNLAGGED_Reconcile will always trigger this error from now on.
		reconciledGame = false;
		I_Error("UNLAGGED_Reconcile called while reconciledGame is true");
	}

	const int unlaggedGametic = UNLAGGED_Gametic( actor->player );

	//Don't reconcile if the unlagged gametic is the same as the current
	//because unlagged data for this tic may not be completely recorded yet
	if (unlaggedGametic == gametic)
		return;

	reconciledGame = true;

	//find the index
	const int unlaggedIndex = unlaggedGametic % UNLAGGEDTICS;

	//reconcile the sectors
	for (int i = 0; i < numsectors; ++i)
	{
		sectors[i].floorplane.restoreD = sectors[i].floorplane.d;
		sectors[i].ceilingplane.restoreD = sectors[i].ceilingplane.d;

		sectors[i].floorplane.d = sectors[i].floorplane.unlaggedD[unlaggedIndex];
		sectors[i].ceilingplane.d = sectors[i].ceilingplane.unlaggedD[unlaggedIndex];
	}

	//reconcile the players
	for (int i = 0; i < MAXPLAYERS; ++i)
	{
		if (playeringame[i] && players[i].mo && !players[i].bSpectating)
		{
			players[i].restoreX = players[i].mo->x;
			players[i].restoreY = players[i].mo->y;
			players[i].restoreZ = players[i].mo->z;

			//Work around limitations of SetOrigin to prevent players
			//from getting stuck in ledges
			players[i].restoreFloorZ = players[i].mo->floorz;

			//Also, don't reconcile the shooter because the client is supposed
			//to predict him
			if (players+i != actor->player)
			{
				players[i].mo->SetOrigin(
					players[i].unlaggedX[unlaggedIndex],
					players[i].unlaggedY[unlaggedIndex],
					players[i].unlaggedZ[unlaggedIndex]
				);
			}
			else
				//However, the client sometimes mispredicts itself if it's on a moving sector.
				//We need to correct for that.
			{
				//current server floorz/ceilingz before reconciliation
				fixed_t serverFloorZ = actor->floorz;
				fixed_t serverCeilingZ = actor->ceilingz;

				// [BB] Try to reset floorz/ceilingz to account for the fact that the sector the actor is in was possibly reconciled.
				actor->floorz = actor->Sector->floorplane.ZatPoint (actor->x, actor->y);
				actor->ceilingz = actor->Sector->ceilingplane.ZatPoint (actor->x, actor->y);
				P_FindFloorCeiling(actor, false);

				//force the shooter out of the floor/ceiling - a client has to mispredict in this case,
				//because not mispredicting would mean the client would think he's inside the floor/ceiling
				if (actor->z + actor->height > actor->ceilingz)
					actor->z = actor->ceilingz - actor->height;

				if (actor->z < actor->floorz)
					actor->z = actor->floorz;

				//floor moved up - a client might have mispredicted himself too low due to gravity
				//and the client thinking the floor is lower than it actually is
				// [BB] But only do this if the sector actually moved. Note: This adjustment seems to break on some kind of non-moving 3D floors.
				if ( (serverFloorZ > actor->floorz) && (( actor->Sector->floorplane.restoreD != actor->Sector->floorplane.d ) || ( actor->Sector->ceilingplane.restoreD != actor->Sector->ceilingplane.d )) )
				{
					//shooter was standing on the floor, let's pull him down to his floor if
					//he wasn't falling
					if ( (actor->z == serverFloorZ) && (actor->momz >= 0) )
						actor->z = actor->floorz;

					//todo: more correction for floor moving up
				}

				//todo: more correction for client misprediction
			}
		}
	}	
}