Ejemplo n.º 1
0
static void GetPortalTransition(DVector3 &pos, sector_t *&sec)
{
	bool moved = false;
	double testz = pos.Z;

	while (!sec->PortalBlocksMovement(sector_t::ceiling))
	{
		if (pos.Z > sec->GetPortalPlaneZ(sector_t::ceiling))
		{
			pos += sec->GetPortalDisplacement(sector_t::ceiling);
			sec = P_PointInSector(pos);
			moved = true;
		}
		else break;
	}
	if (!moved)
	{
		while (!sec->PortalBlocksMovement(sector_t::floor))
		{
			if (pos.Z <= sec->GetPortalPlaneZ(sector_t::floor))
			{
				pos += sec->GetPortalDisplacement(sector_t::floor);
				sec = P_PointInSector(pos);
			}
			else break;
		}
	}
}
Ejemplo n.º 2
0
void AActor::UpdateRenderSectorList()
{
	static const double SPRITE_SPACE = 64.;
	if (Pos() != OldRenderPos && !(flags & MF_NOSECTOR))
	{
		// Only check if the map contains line portals
		ClearRenderLineList();
		if (level.PortalBlockmap.containsLines && Pos().XY() != OldRenderPos.XY())
		{
			int bx = level.blockmap.GetBlockX(X());
			int by = level.blockmap.GetBlockY(Y());
			FBoundingBox bb(X(), Y(), MIN(radius*1.5, 128.));	// Don't go further than 128 map units, even for large actors
			// Are there any portals near the actor's position?
			if (level.blockmap.isValidBlock(bx, by) && level.PortalBlockmap(bx, by).neighborContainsLines)
			{
				// Go through the entire list. In most cases this is faster than setting up a blockmap iterator
				for (auto &p : level.linePortals)
				{
					if (p.mType == PORTT_VISUAL) continue;
					if (bb.inRange(p.mOrigin) && bb.BoxOnLineSide(p.mOrigin))
					{
						touching_lineportallist = P_AddPortalnode(&p, this, touching_lineportallist);
					}
				}
			}
		}
		sector_t *sec = Sector;
		double lasth = -FLT_MAX;
		ClearRenderSectorList();
		while (!sec->PortalBlocksMovement(sector_t::ceiling))
		{
			double planeh = sec->GetPortalPlaneZ(sector_t::ceiling);
			if (planeh <= lasth) break;	// broken setup.
			if (Top() + SPRITE_SPACE < planeh) break;
			lasth = planeh;
			DVector2 newpos = Pos() + sec->GetPortalDisplacement(sector_t::ceiling);
			sec = P_PointInSector(newpos);
			touching_sectorportallist = P_AddSecnode(sec, this, touching_sectorportallist, sec->sectorportal_thinglist);
		}
		sec = Sector;
		lasth = FLT_MAX;
		while (!sec->PortalBlocksMovement(sector_t::floor))
		{
			double planeh = sec->GetPortalPlaneZ(sector_t::floor);
			if (planeh >= lasth) break;	// broken setup.
			if (Z() - SPRITE_SPACE > planeh) break;
			lasth = planeh;
			DVector2 newpos = Pos() + sec->GetPortalDisplacement(sector_t::floor);
			sec = P_PointInSector(newpos);
			touching_sectorportallist = P_AddSecnode(sec, this, touching_sectorportallist, sec->sectorportal_thinglist);
		}
	}
}
Ejemplo n.º 3
0
void FTraceInfo::EnterLinePortal(FPathTraverse &pt, intercept_t *in)
{
	line_t *li = in->d.line;
	FLinePortal *port = li->getPortal();

	double frac = in->frac + EQUAL_EPSILON;
	double enterdist = MaxDist * frac;
	DVector3 exit = Start + MaxDist * in->frac * Vec;

	P_TranslatePortalXY(li, Start.X, Start.Y);
	P_TranslatePortalZ(li, Start.Z);
	P_TranslatePortalVXVY(li, Vec.X, Vec.Y);
	P_TranslatePortalZ(li, limitz);

	CurSector = P_PointInSector(Start + enterdist * Vec);
	EnterDist = enterdist;
	inshootthrough = true;
	startfrac = frac;
	Results->unlinked |= (port->mType != PORTT_LINKED);
	pt.PortalRelocate(in, ptflags);

	if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL)
	{
		enterdist = MaxDist * in->frac;
		Results->HitType = TRACE_CrossingPortal;
		Results->HitPos = exit;
		P_TranslatePortalXY(li, exit.X, exit.Y);
		P_TranslatePortalZ(li, exit.Z);
		Results->SrcFromTarget = exit;
		Results->HitVector = Vec;
		TraceCallback(*Results, TraceCallbackData);
	}
}
Ejemplo n.º 4
0
void FTraceInfo::EnterSectorPortal(FPathTraverse &pt, int position, double frac, sector_t *entersec)
{
	DVector2 displacement = entersec->GetPortalDisplacement(position);;
	double enterdist = MaxDist * frac;
	DVector3 exit = Start + enterdist * Vec;
	DVector3 enter = exit + displacement;

	Start += displacement;
	CurSector = P_PointInSector(enter);
	inshootthrough = true;
	startfrac = frac;
	EnterDist = enterdist;
	pt.PortalRelocate(entersec->GetPortal(position)->mDisplacement, ptflags, frac);

	if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL)
	{
		enterdist = MaxDist * frac;
		Results->HitType = TRACE_CrossingPortal;
		Results->HitPos = exit;
		Results->SrcFromTarget = enter;
		Results->HitVector = Vec;
		TraceCallback(*Results, TraceCallbackData);
	}

	Setup3DFloors();
}
Ejemplo n.º 5
0
static void DrawCoordinates(player_t * CPlayer)
{
	DVector3 pos;
	char coordstr[18];
	int h = SmallFont->GetHeight()+1;

	
	if (!map_point_coordinates || !automapactive) 
	{
		pos = CPlayer->mo->Pos();
	}
	else 
	{
		DVector2 apos = AM_GetPosition();
		double z = P_PointInSector(apos)->floorplane.ZatPoint(apos);
		pos = DVector3(apos, z);
	}

	int vwidth, vheight;
	if (active_con_scaletext() == 0)
	{
		vwidth = SCREENWIDTH / 2;
		vheight = SCREENHEIGHT / 2;
	}
	else
	{
		vwidth = SCREENWIDTH / active_con_scaletext();
		vheight = SCREENHEIGHT / active_con_scaletext();
	}

	int xpos = vwidth - SmallFont->StringWidth("X: -00000")-6;
	int ypos = 18;

	screen->DrawText(SmallFont, hudcolor_titl, vwidth - 6 - SmallFont->StringWidth(level.MapName), ypos, level.MapName,
		DTA_KeepRatio, true,
		DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);

	screen->DrawText(SmallFont, hudcolor_titl, vwidth - 6 - SmallFont->StringWidth(level.LevelName), ypos + h, level.LevelName,
		DTA_KeepRatio, true,
		DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);

	mysnprintf(coordstr, countof(coordstr), "X: %d", int(pos.X));
	screen->DrawText(SmallFont, hudcolor_xyco, xpos, ypos+2*h, coordstr,
		DTA_KeepRatio, true,
		DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);

	mysnprintf(coordstr, countof(coordstr), "Y: %d", int(pos.Y));
	screen->DrawText(SmallFont, hudcolor_xyco, xpos, ypos+3*h, coordstr,
		DTA_KeepRatio, true,
		DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);

	mysnprintf(coordstr, countof(coordstr), "Z: %d", int(pos.Z));
	screen->DrawText(SmallFont, hudcolor_xyco, xpos, ypos+4*h, coordstr,
		DTA_KeepRatio, true,
		DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);
}
Ejemplo n.º 6
0
void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt, const int *oldvertextable)
{
	FMapThing *mt;

	for (mt = firstmt; mt < lastmt; ++mt)
	{
		if (mt->info != NULL && mt->info->Type == NULL &&
		   (mt->info->Special >= SMT_SlopeFloorPointLine && mt->info->Special <= SMT_VavoomCeiling))
		{
			DVector3 pos = mt->pos;
			secplane_t *refplane;
			sector_t *sec;
			bool ceiling;

			sec = P_PointInSector (mt->pos);
			if (mt->info->Special == SMT_SlopeCeilingPointLine || mt->info->Special == SMT_VavoomCeiling || mt->info->Special == SMT_SetCeilingSlope)
			{
				refplane = &sec->ceilingplane;
				ceiling = true;
			}
			else
			{
				refplane = &sec->floorplane;
				ceiling = false;
			}
			pos.Z = refplane->ZatPoint (mt->pos) + mt->pos.Z;

			if (mt->info->Special <= SMT_SlopeCeilingPointLine)
			{ // SlopeFloorPointLine and SlopCeilingPointLine
				P_SlopeLineToPoint (mt->args[0], pos, ceiling);
			}
			else if (mt->info->Special <= SMT_SetCeilingSlope)
			{ // SetFloorSlope and SetCeilingSlope
				P_SetSlope (refplane, ceiling, mt->angle, mt->args[0], pos);
			}
			else 
			{ // VavoomFloor and VavoomCeiling (these do not perform any sector height adjustment - z is absolute)
				P_VavoomSlope(sec, mt->thingid, mt->pos, ceiling); 
			}
			mt->EdNum = 0;
		}
	}

	for (mt = firstmt; mt < lastmt; ++mt)
	{
		if (mt->info != NULL && mt->info->Type == NULL &&
			(mt->info->Special == SMT_CopyFloorPlane || mt->info->Special == SMT_CopyCeilingPlane))
		{
			P_CopyPlane (mt->args[0], mt->pos, mt->info->Special == SMT_CopyCeilingPlane);
			mt->EdNum = 0;
		}
	}

	P_SetSlopesFromVertexHeights(firstmt, lastmt, oldvertextable);
}
Ejemplo n.º 7
0
DEFINE_ACTION_FUNCTION(AActor, A_Burnination)
{
	PARAM_ACTION_PROLOGUE;

	self->Vel.Z -= 8;
	self->Vel.X += (pr_phburn.Random2 (3));
	self->Vel.Y += (pr_phburn.Random2 (3));
	S_Sound (self, CHAN_VOICE, "world/largefire", 1, ATTN_NORM);

	// Only the main fire spawns more.
	if (!(self->flags & MF_DROPPED))
	{
		// Original x and y offsets seemed to be like this:
		//		x + (((pr_phburn() + 12) & 31) << F.RACBITS);
		//
		// But that creates a lop-sided burn because it won't use negative offsets.
		int xofs, xrand = pr_phburn();
		int yofs, yrand = pr_phburn();

		// Adding 12 is pointless if you're going to mask it afterward.
		xofs = xrand & 31;
		if (xrand & 128)
		{
			xofs = -xofs;
		}

		yofs = yrand & 31;
		if (yrand & 128)
		{
			yofs = -yofs;
		}

		DVector2 pos = self->Vec2Offset((double)xofs, (double)yofs);
		sector_t * sector = P_PointInSector(pos);

		// The sector's floor is too high so spawn the flame elsewhere.
		if (sector->floorplane.ZatPoint(pos) > self->Z() + self->MaxStepHeight)
		{
			pos = self->Pos();
		}

		AActor *drop = Spawn<APhosphorousFire> (DVector3(pos, self->Z() + 4.), ALLOW_REPLACE);
		if (drop != NULL)
		{
			drop->Vel.X = self->Vel.X + pr_phburn.Random2 (7);
			drop->Vel.Y = self->Vel.Y + pr_phburn.Random2 (7);
			drop->Vel.Z = self->Vel.Z - 1;
			drop->reactiontime = (pr_phburn() & 3) + 2;
			drop->flags |= MF_DROPPED;
		}
	}
	return 0;
}
Ejemplo n.º 8
0
int	P_Find3DFloor(sector_t * sec, const DVector3 &pos, bool above, bool floor, double &cmpz)
{
	// If no sector given, find the one appropriate
	if (sec == NULL)
		sec = P_PointInSector(pos);

	// Above normal ceiling
	cmpz = sec->ceilingplane.ZatPoint(pos);
	if (pos.Z >= cmpz)
		return -1;

	// Below normal floor
	cmpz = sec->floorplane.ZatPoint(pos);
	if (pos.Z <= cmpz)
		return -1;

	// Looking through planes from top to bottom
	for (int i = 0; i < (signed)sec->e->XFloor.ffloors.Size(); ++i)
	{
		F3DFloor *rover = sec->e->XFloor.ffloors[i];

		// We are only interested in solid 3D floors here
		if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;

		if (above)
		{
			// z is above that floor
			if (floor && (pos.Z >= (cmpz = rover->top.plane->ZatPoint(pos))))
				return i - 1;
			// z is above that ceiling
			if (pos.Z >= (cmpz = rover->bottom.plane->ZatPoint(pos)))
				return i - 1;
		}
		else // below
		{
			// z is below that ceiling
			if (!floor && (pos.Z <= (cmpz = rover->bottom.plane->ZatPoint(pos))))
				return i;
			// z is below that floor
			if (pos.Z <= (cmpz = rover->top.plane->ZatPoint(pos)))
				return i;
		}
	}

	// Failsafe
	return -1;
}
Ejemplo n.º 9
0
void ASkyCamCompat::BeginPlay ()
{
	if (Sector == NULL)
	{
		Printf("Sector not initialized for SkyCamCompat\n");
		Sector = P_PointInSector(x, y);
	}
	if (Sector)
	{
		line_t * refline = NULL;
		for (short i = 0; i < Sector->linecount; i++)
		{
			refline = Sector->lines[i];
			if (refline->special == Sector_SetPortal && refline->args[1] == 2)
			{
				// We found the setup linedef for this skybox, so let's use it for our init.
				int skybox_id = refline->args[0];

				// Then, change the alpha
				alpha = refline->args[4];

				// Finally, skyboxify all tagged sectors
				// This involves changing their texture to the sky flat, because while
				// EE works with any texture for its skybox portals, ZDoom doesn't.
				for (int secnum =-1; (secnum = P_FindSectorFromTag (skybox_id, secnum)) != -1; )
				{
					// plane: 0=floor, 1=ceiling, 2=both
					if (refline->args[2] == 1 || refline->args[2] == 2)
					{
						sectors[secnum].CeilingSkyBox = this;
						sectors[secnum].SetTexture(sector_t::ceiling, skyflatnum, false);
					}
					if (refline->args[2] == 0 || refline->args[2] == 2)
					{
						sectors[secnum].FloorSkyBox = this;
						sectors[secnum].SetTexture(sector_t::floor, skyflatnum, false);
					}
				}
			}
		}
	}
	// Do not call the SkyViewpoint's super method because it would trash our setup
	AActor::BeginPlay();
}
Ejemplo n.º 10
0
static void DrawCoordinates(player_t * CPlayer)
{
	fixed_t x;
	fixed_t y;
	fixed_t z;
	char coordstr[18];
	int h = SmallFont->GetHeight()+1;

	
	if (!map_point_coordinates || !automapactive) 
	{
		x=CPlayer->mo->X();
		y=CPlayer->mo->Y();                     
		z=CPlayer->mo->Z();
	}
	else 
	{
		AM_GetPosition(x,y);
		z = P_PointInSector(x, y)->floorplane.ZatPoint(x, y);
	}

	int vwidth = con_scaletext==0? SCREENWIDTH : SCREENWIDTH/2;
	int vheight = con_scaletext==0? SCREENHEIGHT : SCREENHEIGHT/2;
	int xpos = vwidth - SmallFont->StringWidth("X: -00000")-6;
	int ypos = 18;

	mysnprintf(coordstr, countof(coordstr), "X: %d", x>>FRACBITS);
	screen->DrawText(SmallFont, hudcolor_xyco, xpos, ypos, coordstr,
		DTA_KeepRatio, true,
		DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);

	mysnprintf(coordstr, countof(coordstr), "Y: %d", y>>FRACBITS);
	screen->DrawText(SmallFont, hudcolor_xyco, xpos, ypos+h, coordstr,
		DTA_KeepRatio, true,
		DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);

	mysnprintf(coordstr, countof(coordstr), "Z: %d", z>>FRACBITS);
	screen->DrawText(SmallFont, hudcolor_xyco, xpos, ypos+2*h, coordstr,
		DTA_KeepRatio, true,
		DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE);
}
Ejemplo n.º 11
0
bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
				 bool useFog, bool sourceFog, bool keepOrientation, bool bHaltVelocity, bool keepHeight)
{
	bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING));

	fixed_t oldx;
	fixed_t oldy;
	fixed_t oldz;
	fixed_t aboveFloor;
	player_t *player;
	angle_t an;
	sector_t *destsect;
	bool resetpitch = false;
	fixed_t floorheight, ceilingheight;
	fixed_t missilespeed;

	oldx = thing->x;
	oldy = thing->y;
	oldz = thing->z;
	aboveFloor = thing->z - thing->floorz;
	destsect = P_PointInSector (x, y);
	// killough 5/12/98: exclude voodoo dolls:
	player = thing->player;
	if (player && player->mo != thing)
		player = NULL;
	floorheight = destsect->floorplane.ZatPoint (x, y);
	ceilingheight = destsect->ceilingplane.ZatPoint (x, y);
	if (thing->flags & MF_MISSILE)
	{ // We don't measure z velocity, because it doesn't change.
		missilespeed = xs_CRoundToInt(TVector2<double>(thing->velx, thing->vely).Length());
	}
	if (keepHeight)
	{
		z = floorheight + aboveFloor;
	}
	else if (z == ONFLOORZ)
	{
		if (player)
		{
			if (thing->flags & MF_NOGRAVITY && aboveFloor)
			{
				z = floorheight + aboveFloor;
				if (z + thing->height > ceilingheight)
				{
					z = ceilingheight - thing->height;
				}
			}
			else
			{
				z = floorheight;
				if (!keepOrientation)
				{
					resetpitch = false;
				}
			}
		}
		else if (thing->flags & MF_MISSILE)
		{
			z = floorheight + aboveFloor;
			if (z + thing->height > ceilingheight)
			{
				z = ceilingheight - thing->height;
			}
		}
		else
		{
			z = floorheight;
		}
	}
	if (!P_TeleportMove (thing, x, y, z, false))
	{
		return false;
	}
	if (player)
	{
		player->viewz = thing->z + player->viewheight;
		if (resetpitch)
		{
			player->mo->pitch = 0;
		}
	}
	if (!keepOrientation)
	{
		thing->angle = angle;
	}
	else
	{
		angle = thing->angle;
	}
	// Spawn teleport fog at source and destination
	if (sourceFog && !predicting)
	{
		fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
		P_SpawnTeleportFog(thing, oldx, oldy, oldz, true, true); //Passes the actor through which then pulls the TeleFog metadate types based on properties.
	}
	if (useFog)
	{
		if (!predicting)
		{
			fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
			an = angle >> ANGLETOFINESHIFT;
			P_SpawnTeleportFog(thing, x + 20 * finecosine[an], y + 20 * finesine[an], thing->z + fogDelta, false, true);

		}
		if (thing->player)
		{
			// [RH] Zoom player's field of vision
			// [BC] && bHaltVelocity.
			if (telezoom && thing->player->mo == thing && bHaltVelocity)
				thing->player->FOV = MIN (175.f, thing->player->DesiredFOV + 45.f);
		}
	}
Ejemplo n.º 12
0
static void P_CopyPlane (int tag, const DVector2 &pos, bool copyCeil)
{
	sector_t *dest = P_PointInSector (pos);
	P_CopyPlane(tag, dest, copyCeil);
}
Ejemplo n.º 13
0
bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags)
{
	bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING));

	DVector3 old;
	double aboveFloor;
	player_t *player;
	sector_t *destsect;
	bool resetpitch = false;
	double floorheight, ceilingheight;
	double missilespeed = 0;

	old = thing->Pos();
	aboveFloor = thing->Z() - thing->floorz;
	destsect = P_PointInSector (pos);
	// killough 5/12/98: exclude voodoo dolls:
	player = thing->player;
	if (player && player->mo != thing)
		player = NULL;
	floorheight = destsect->floorplane.ZatPoint (pos);
	ceilingheight = destsect->ceilingplane.ZatPoint (pos);
	if (thing->flags & MF_MISSILE)
	{ // We don't measure z velocity, because it doesn't change.
		missilespeed = thing->VelXYToSpeed();
	}
	if (flags & TELF_KEEPHEIGHT)
	{
		pos.Z = floorheight + aboveFloor;
	}
	else if (pos.Z == ONFLOORZ)
	{
		if (player)
		{
			if (thing->flags & MF_NOGRAVITY && aboveFloor)
			{
				pos.Z = floorheight + aboveFloor;
				if (pos.Z + thing->Height > ceilingheight)
				{
					pos.Z = ceilingheight - thing->Height;
				}
			}
			else
			{
				pos.Z = floorheight;
				if (!(flags & TELF_KEEPORIENTATION))
				{
					resetpitch = false;
				}
			}
		}
		else if (thing->flags & MF_MISSILE)
		{
			pos.Z = floorheight + aboveFloor;
			if (pos.Z + thing->Height > ceilingheight)
			{
				pos.Z = ceilingheight - thing->Height;
			}
		}
		else
		{
			pos.Z = floorheight;
		}
	}
	if (!P_TeleportMove (thing, pos, false))
	{
		return false;
	}
	if (player)
	{
		player->viewz = thing->Z() + player->viewheight;
		if (resetpitch)
		{
			player->mo->Angles.Pitch = 0.;
		}
	}
	if (!(flags & TELF_KEEPORIENTATION))
	{
		thing->Angles.Yaw = angle;
	}
	else
	{
		angle = thing->Angles.Yaw;
	}
	// Spawn teleport fog at source and destination
	if ((flags & TELF_SOURCEFOG) && !predicting)
	{
		P_SpawnTeleportFog(thing, old, true, true); //Passes the actor through which then pulls the TeleFog metadata types based on properties.
	}
	if (flags & TELF_DESTFOG)
	{
		if (!predicting)
		{
			DVector2 vector = angle.ToVector(20);
			DVector2 fogpos = P_GetOffsetPosition(pos.X, pos.Y, vector.X, vector.Y);
			P_SpawnTeleportFog(thing, DVector3(fogpos, thing->Z()), false, true);

		}
		if (thing->player)
		{
			// [RH] Zoom player's field of vision
			// [BC] && bHaltVelocity.
			if (telezoom && thing->player->mo == thing && !(flags & TELF_KEEPVELOCITY))
				thing->player->FOV = MIN (175.f, thing->player->DesiredFOV + 45.f);
		}
	}
	// [BC] && bHaltVelocity.
	if (thing->player && ((flags & TELF_DESTFOG) || !(flags & TELF_KEEPORIENTATION)) && !(flags & TELF_KEEPVELOCITY))
	{
		// Freeze player for about .5 sec
		if (thing->Inventory == NULL || !thing->Inventory->GetNoTeleportFreeze())
			thing->reactiontime = 18;
	}
	if (thing->flags & MF_MISSILE)
	{
		thing->VelFromAngle(missilespeed);
	}
	// [BC] && bHaltVelocity.
	else if (!(flags & TELF_KEEPORIENTATION) && !(flags & TELF_KEEPVELOCITY))
	{ // no fog doesn't alter the player's momentum
		thing->Vel.Zero();
		// killough 10/98: kill all bobbing velocity too
		if (player)	player->Vel.Zero();
	}
	return true;
}
Ejemplo n.º 14
0
bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
				 bool useFog, bool sourceFog, bool keepOrientation, bool bHaltVelocity, bool keepHeight)
{
	fixed_t oldx;
	fixed_t oldy;
	fixed_t oldz;
	fixed_t aboveFloor;
	player_t *player;
	angle_t an;
	sector_t *destsect;
	bool resetpitch = false;
	fixed_t floorheight, ceilingheight;
	fixed_t missilespeed;

	oldx = thing->x;
	oldy = thing->y;
	oldz = thing->z;
	aboveFloor = thing->z - thing->floorz;
	destsect = P_PointInSector (x, y);
	// killough 5/12/98: exclude voodoo dolls:
	player = thing->player;
	if (player && player->mo != thing)
		player = NULL;
	floorheight = destsect->floorplane.ZatPoint (x, y);
	ceilingheight = destsect->ceilingplane.ZatPoint (x, y);
	if (thing->flags & MF_MISSILE)
	{ // We don't measure z velocity, because it doesn't change.
		missilespeed = xs_CRoundToInt(TVector2<double>(thing->velx, thing->vely).Length());
	}
	if (keepHeight)
	{
		z = floorheight + aboveFloor;
	}
	else if (z == ONFLOORZ)
	{
		if (player)
		{
			if (thing->flags & MF_NOGRAVITY && aboveFloor)
			{
				z = floorheight + aboveFloor;
				if (z + thing->height > ceilingheight)
				{
					z = ceilingheight - thing->height;
				}
			}
			else
			{
				z = floorheight;
				if (!keepOrientation)
				{
					resetpitch = false;
				}
			}
		}
		else if (thing->flags & MF_MISSILE)
		{
			z = floorheight + aboveFloor;
			if (z + thing->height > ceilingheight)
			{
				z = ceilingheight - thing->height;
			}
		}
		else
		{
			z = floorheight;
		}
	}
	if (!P_TeleportMove (thing, x, y, z, false))
	{
		return false;
	}
	if (player)
	{
		player->viewz = thing->z + player->viewheight;
		if (resetpitch)
		{
			player->mo->pitch = 0;
		}
	}
	if (!keepOrientation)
	{
		thing->angle = angle;
	}
	else
	{
		angle = thing->angle;
	}
	// Spawn teleport fog at source and destination
	if (sourceFog)
	{
		fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
		AActor *fog = Spawn<ATeleportFog> (oldx, oldy, oldz + fogDelta, ALLOW_REPLACE);
		fog->target = thing;
	}
	if (useFog)
	{
		fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
		an = angle >> ANGLETOFINESHIFT;
		AActor *fog = Spawn<ATeleportFog> (x + 20*finecosine[an],
			y + 20*finesine[an], thing->z + fogDelta, ALLOW_REPLACE);
		fog->target = thing;
		if (thing->player)
		{
			// [RH] Zoom player's field of vision
			// [BC] && bHaltVelocity.
			if (telezoom && thing->player->mo == thing && bHaltVelocity)
				thing->player->FOV = MIN (175.f, thing->player->DesiredFOV + 45.f);
		}
	}
	// [BC] && bHaltVelocity.
	if (thing->player && (useFog || !keepOrientation) && bHaltVelocity)
	{
		// Freeze player for about .5 sec
		if (thing->Inventory == NULL || thing->Inventory->GetSpeedFactor() <= FRACUNIT)
			thing->reactiontime = 18;
	}
	if (thing->flags & MF_MISSILE)
	{
		angle >>= ANGLETOFINESHIFT;
		thing->velx = FixedMul (missilespeed, finecosine[angle]);
		thing->vely = FixedMul (missilespeed, finesine[angle]);
	}