//=============================================================================
// WarpZoneInfo. For making disjoint spaces appear as if they were connected;
// supports both in-level warp zones and cross-level warp zones.
//=============================================================================
class WarpZoneInfo extends ZoneInfo
	native;

//-----------------------------------------------------------------------------
// Information set by the level designer.

var() string     OtherSideURL;
var() name       ThisTag;
var() bool		 bNoTeleFrag;

//-----------------------------------------------------------------------------
// Internal.

var const int              iWarpZone;
var const coords           WarpCoords;
var transient WarpZoneInfo OtherSideActor;
var transient object       OtherSideLevel;
var() string		       Destinations[8];
var int					   numDestinations;

//-----------------------------------------------------------------------------
// Network replication.

replication
{
	reliable if( Role==ROLE_Authority )
		OtherSideURL, ThisTag, OtherSideActor;
}

//-----------------------------------------------------------------------------
// Functions.

// Warp coordinate system transformations.
native(314) final function Warp  ( out vector Loc, out vector Vel, out rotator R );
native(315) final function UnWarp( out vector Loc, out vector Vel, out rotator R );

function PreBeginPlay()
{
	Super.PreBeginPlay();

	// Generate the local connection.
	Generate();

	// Setup destination list.
	numDestinations = 0;
	While( numDestinations < 8 )
		if (Destinations[numDestinations] != "")
			numDestinations++;
		else
			numDestinations = 8;

	// Generate URL if necessary.
	if( numDestinations>0 && (OtherSideURL == "") )
		OtherSideURL = Destinations[0];
}

function Trigger( actor Other, pawn EventInstigator )
{
	local int nextPick;
	if (numDestinations == 0)
		return;
	
	nextPick = 0;
	While( (nextPick < 8) && (Destinations[nextPick] != OtherSideURL )  )
		nextPick++;

	nextPick++;
	if ( (nextPick > 7) || (Destinations[nextPick] == "") )
		nextPick = 0;
	
	OtherSideURL = Destinations[nextPick];
	ForceGenerate();
}

// Set up this warp zone's destination.
simulated event Generate()
{
	if( OtherSideLevel != None )
		return;
	ForceGenerate();
}

// Set up this warp zone's destination.
simulated event ForceGenerate()
{
	if( InStr(OtherSideURL,"/") >= 0 )
	{
		// Remote level.
		//log( "Warpzone " $ Self $ " remote" );
		OtherSideLevel = None;
		OtherSideActor = None;
	}
	else
	{
		// Local level.
		OtherSideLevel = XLevel;
		foreach AllActors( class 'WarpZoneInfo', OtherSideActor )
			if( string(OtherSideActor.ThisTag)~=OtherSideURL && OtherSideActor!=Self )
				break;
		//log( "Warpzone " $ Self $ " local, connected to " $ OtherSideActor );
	}
}

// When an actor enters this warp zone.
simulated function ActorEntered( actor Other )
{
	local vector L;
	local rotator R;
	local Controller P;

	//if ( Other.Role == ROLE_AutonomousProxy )
	//	return; // don't simulate for client players
	if( !Other.bJustTeleported )
	{
		Generate();
		if( OtherSideActor != None )
		{
			// This needs to also perform a coordinate system transformation,
			// in case the portals aren't directionally aligned. This is easy to
			// do but UnrealScript doesn't provide coordinate system operators yet.
			Other.Disable('Touch');
			Other.Disable('UnTouch');

			L = Other.Location;
			if( Pawn(Other) != None )
				R = Pawn(Other).GetViewRotation();

			UnWarp( L, Other.Velocity, R );
			OtherSideActor.Warp( L, Other.Velocity, R );

			if( Other.IsA('Pawn') )
			{
				Pawn(Other).bWarping = bNoTelefrag;
				if ( Other.SetLocation(L) )
				{
					//tell enemies about teleport
					if ( Role == ROLE_Authority )
						For ( P=Level.ControllerList; P!=None; P=P.NextController )
							if (P.Enemy == Other)
								P.LineOfSightTo(Other); 
					R.Roll = 0;
					Pawn(Other).SetViewRotation(R);
					Pawn(Other).ClientSetLocation(L, R );
					if ( Pawn(Other).Controller != None )
						Pawn(Other).Controller.MoveTimer = -1.0;
				}
				else
				{
					// set up to keep trying to teleport
					GotoState('DelayedWarp');
				}
			}
			else
			{
				Other.SetLocation(L);
				Other.SetRotation( R );
			}
			Other.Enable('Touch');
			Other.Enable('UnTouch');
			// Change rotation according to portal's rotational change.
		}
	}
}

event ActorLeaving( actor Other )
{
	If ( Other.IsA('Pawn') )
		Pawn(Other).bWarping = false;
}

State DelayedWarp
{
	function Tick(float DeltaTime)
	{
		local Controller P;
		local bool bFound;

		For ( P=Level.ControllerList; P!=None; P=P.NextController )
			if ( P.Pawn.bWarping && (P.Pawn.Region.Zone == Self) )
			{
				bFound = true;
				ActorEntered(P);
			}

		If ( !bFound )
			GotoState('');
	}
}

defaultproperties
{
}
