Botpack
Class GuidedWarShell

source: e:\games\UnrealTournament\Botpack\Classes\GuidedWarshell.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Projectile
         |
         +--Botpack.WarShell
            |
            +--Botpack.GuidedWarShell
Direct Known Subclasses:None

class GuidedWarShell
extends Botpack.WarShell

//============================================================================= // GuidedWarShell. //=============================================================================
Variables
 SavedMove FreeMoves
 OldGuiderRotation, GuidedRotation
 Pawn Guider
 CurrentTimeStamp, LastUpdateTime,ClientBuffer,ServerUpdate
 RealLocation, RealVelocity
 SavedMove SavedMoves
 bool bDestroyed
 bool bUpdatePosition

States
Flying

Function Summary
 
simulated
ClientAdjustPosition(float TimeStamp, float NewLocX, float NewLocY, float NewLocZ, float NewVelX, float NewVelY, float NewVelZ)
     
// Server sends ClientAdjustPosition to the client to adjust the warhead position on the client side when the error
// is excessive
 
simulated
ClientUpdatePosition()
     
// Client calls this to replay moves after getting its position updated by the server
 
simulated
Destroyed()
 SavedMove GetFreeMove()
 
simulated
MoveRocket(float DeltaTime, vector CurrentVelocity, rotator GuideRotation)
 
simulated
PostRender(Canvas Canvas)
 void ServerMove(float TimeStamp, vector ClientLoc, int Pitch, int Yaw)
     
// server moves the rocket based on clients input, and compares the resultant location to the client's view of the location
 
simulated
Tick(float DeltaTime)
 
simulated
Timer()


State Flying Function Summary
 void BeginState()



Source Code


00001	//=============================================================================
00002	// GuidedWarShell.
00003	//=============================================================================
00004	class GuidedWarShell extends WarShell;
00005	
00006	var Pawn Guider;
00007	var rotator OldGuiderRotation, GuidedRotation;
00008	var float CurrentTimeStamp, LastUpdateTime,ClientBuffer,ServerUpdate;
00009	var bool bUpdatePosition;
00010	var bool bDestroyed;
00011	
00012	var SavedMove SavedMoves;
00013	var SavedMove FreeMoves;
00014	
00015	var vector RealLocation, RealVelocity;
00016	
00017	replication
00018	{
00019		// Things the server should send to the client.
00020		unreliable if( Role==ROLE_Authority )
00021			ClientAdjustPosition, bDestroyed;
00022		unreliable if ( Role==ROLE_Authority && bNetOwner && bNetInitial )
00023			GuidedRotation, OldGuiderRotation;
00024		unreliable if( Role==ROLE_Authority && !bNetOwner )
00025			RealLocation, RealVelocity;
00026		unreliable if( Role==ROLE_AutonomousProxy )
00027			ServerMove;
00028	}
00029	
00030	simulated function Timer()
00031	{
00032		local ut_SpriteSmokePuff b;
00033		local float SmokeRate;
00034	
00035		if ( (Role == ROLE_Authority) && (Level.TimeSeconds - ServerUpdate > 4) )
00036		{
00037			Explode(Location,Vect(0,0,1));
00038			return;
00039		}
00040	
00041		if ( Trail == None )
00042			Trail = Spawn(class'RedeemerTrail',self);
00043	
00044		CannonTimer += SmokeRate;
00045		if ( CannonTimer > 0.6 )
00046		{
00047			WarnCannons();
00048			CannonTimer -= 0.6;
00049		}
00050	
00051		if ( Region.Zone.bWaterZone || (Level.NetMode == NM_DedicatedServer) )
00052		{
00053			SetTimer(SmokeRate, false);
00054			Return;
00055		}
00056	
00057		if ( Level.bHighDetailMode )
00058		{
00059			if ( Level.bDropDetail )
00060				SmokeRate = 0.07;
00061			else
00062				SmokeRate = 0.02; 
00063		}
00064		else 
00065		{
00066			SmokeRate = 0.15;
00067		}
00068		b = Spawn(class'ut_SpriteSmokePuff');
00069		b.RemoteRole = ROLE_None;
00070		SetTimer(SmokeRate, false);
00071	}
00072	
00073	
00074	simulated function Destroyed()
00075	{
00076		local WarheadLauncher W;
00077	
00078		bDestroyed = true;
00079		if ( (PlayerPawn(Guider) != None) )
00080			PlayerPawn(Guider).ViewTarget = None;
00081	
00082		While ( FreeMoves != None )
00083		{
00084			FreeMoves.Destroy();
00085			FreeMoves = FreeMoves.NextMove;
00086		}
00087	
00088		While ( SavedMoves != None )
00089		{
00090			SavedMoves.Destroy();
00091			SavedMoves = SavedMoves.NextMove;
00092		}
00093	
00094		if ( (Guider != None) && (Level.NetMode != NM_Client) )
00095		{
00096			W = WarheadLauncher(Guider.FindInventoryType(class'WarheadLauncher'));
00097			if ( W != None )
00098			{
00099				W.GuidedShell = None;
00100				W.GotoState('Finishing');
00101			}
00102		}
00103		Super.Destroyed();
00104	}
00105	
00106	simulated function Tick(float DeltaTime)
00107	{
00108		local int DeltaYaw, DeltaPitch;
00109		local int YawDiff, PitchDiff;
00110		local SavedMove NewMove;
00111	
00112		if ( Level.NetMode == NM_Client )
00113		{
00114			if ( (PlayerPawn(Instigator) != None) && (ViewPort(PlayerPawn(Instigator).Player) != None) )
00115			{
00116				Guider = Instigator;
00117				if ( bDestroyed || (Instigator.health < 0) )
00118				{
00119					PlayerPawn(Instigator).ViewTarget = None;
00120					Destroy();
00121					if ( Instigator.Weapon.IsA('WarheadLauncher') )
00122						WarheadLauncher(Instigator.Weapon).bGuiding = false;
00123					return;
00124				}
00125				PlayerPawn(Instigator).ViewTarget = self;
00126				if ( Instigator.Weapon.IsA('WarheadLauncher') )
00127				{
00128					WarheadLauncher(Instigator.Weapon).GuidedShell = self;
00129					WarheadLauncher(Instigator.Weapon).bGuiding = true;
00130				}
00131			}
00132			else
00133			{
00134				if ( RealLocation != vect(0,0,0) )
00135				{
00136					SetLocation(RealLocation);
00137					RealLocation = vect(0,0,0);
00138				}
00139				if ( RealVelocity != vect(0,0,0) )
00140				{
00141					Velocity = RealVelocity;
00142					SetRotation(rotator(Velocity));
00143					RealVelocity = vect(0,0,0);
00144				}
00145				return;
00146			}
00147		}
00148		else if ( (Level.NetMode != NM_Standalone) && (RemoteRole == ROLE_AutonomousProxy) ) 
00149				return;
00150	
00151		// if server updated client position, client needs to replay moves after the update
00152		if ( bUpdatePosition )
00153			ClientUpdatePosition();
00154	
00155		DeltaYaw = (Guider.ViewRotation.Yaw & 65535) - (OldGuiderRotation.Yaw & 65535);
00156		DeltaPitch = (Guider.ViewRotation.Pitch & 65535) - (OldGuiderRotation.Pitch & 65535);
00157		if ( DeltaPitch < -32768 )
00158			DeltaPitch += 65536;
00159		else if ( DeltaPitch > 32768 )
00160			DeltaPitch -= 65536;
00161		if ( DeltaYaw < -32768 )
00162			DeltaYaw += 65536;
00163		else if ( DeltaYaw > 32768 )
00164			DeltaYaw -= 65536;
00165	
00166		YawDiff = (Rotation.Yaw & 65535) - (GuidedRotation.Yaw & 65535) - DeltaYaw;
00167		if ( DeltaYaw < 0 )
00168		{
00169			if ( ((YawDiff > 0) && (YawDiff < 16384)) || (YawDiff < -49152) )
00170				GuidedRotation.Yaw += DeltaYaw;
00171		}	
00172		else if ( ((YawDiff < 0) && (YawDiff > -16384)) || (YawDiff > 49152) )
00173			GuidedRotation.Yaw += DeltaYaw;
00174	
00175		GuidedRotation.Pitch += DeltaPitch;
00176		OldGuiderRotation = Guider.ViewRotation;
00177		if ( Role == ROLE_AutonomousProxy )
00178		{
00179			// Send the move to the server
00180			// skip move if too soon
00181			if ( ClientBuffer < 0 )
00182			{
00183				ClientBuffer += DeltaTime;
00184				MoveRocket(DeltaTime, Velocity, GuidedRotation);
00185				return;
00186			}
00187			else
00188				ClientBuffer = ClientBuffer + DeltaTime - 80.0/PlayerPawn(Instigator).Player.CurrentNetSpeed;
00189	
00190			// I'm  a client, so I'll save my moves in case I need to replay them
00191			// Get a SavedMove actor to store the movement in.
00192			if ( SavedMoves == None )
00193			{
00194				SavedMoves = GetFreeMove();
00195				NewMove = SavedMoves;
00196			}
00197			else
00198			{
00199				NewMove = SavedMoves;
00200				while ( NewMove.NextMove != None )
00201					NewMove = NewMove.NextMove;
00202				NewMove.NextMove = GetFreeMove();
00203				NewMove = NewMove.NextMove;
00204			}
00205	
00206			NewMove.TimeStamp = Level.TimeSeconds;
00207			NewMove.Delta = DeltaTime;
00208			NewMove.Velocity = Velocity;
00209			NewMove.SetRotation(GuidedRotation);
00210	
00211			MoveRocket(DeltaTime, Velocity, GuidedRotation);
00212			ServerMove(Level.TimeSeconds, Location, NewMove.Rotation.Pitch, NewMove.Rotation.Yaw);
00213			return;
00214		}
00215		MoveRocket(DeltaTime, Velocity, GuidedRotation);
00216	}
00217	
00218	// Server sends ClientAdjustPosition to the client to adjust the warhead position on the client side when the error
00219	// is excessive
00220	simulated function ClientAdjustPosition
00221	(
00222		float TimeStamp, 
00223		float NewLocX, 
00224		float NewLocY, 
00225		float NewLocZ, 
00226		float NewVelX, 
00227		float NewVelY, 
00228		float NewVelZ
00229	)
00230	{
00231		local vector NewLocation;
00232	
00233		if ( CurrentTimeStamp > TimeStamp )
00234			return;
00235		CurrentTimeStamp = TimeStamp;
00236	
00237		NewLocation.X = NewLocX;
00238		NewLocation.Y = NewLocY;
00239		NewLocation.Z = NewLocZ;
00240		Velocity.X = NewVelX;
00241		Velocity.Y = NewVelY;
00242		Velocity.Z = NewVelZ;
00243	
00244		SetLocation(NewLocation);
00245	
00246		bUpdatePosition = true;
00247	}
00248	
00249	// Client calls this to replay moves after getting its position updated by the server
00250	simulated function ClientUpdatePosition()
00251	{
00252		local SavedMove CurrentMove;
00253		local int realbRun, realbDuck;
00254		local bool bRealJump;
00255	
00256		bUpdatePosition = false;
00257		CurrentMove = SavedMoves;
00258		while ( CurrentMove != None )
00259		{
00260			if ( CurrentMove.TimeStamp <= CurrentTimeStamp )
00261			{
00262				SavedMoves = CurrentMove.NextMove;
00263				CurrentMove.NextMove = FreeMoves;
00264				FreeMoves = CurrentMove;
00265				FreeMoves.Clear();
00266				CurrentMove = SavedMoves;
00267			}
00268			else
00269			{
00270				MoveRocket(CurrentMove.Delta, CurrentMove.Velocity, CurrentMove.Rotation);
00271				CurrentMove = CurrentMove.NextMove;
00272			}
00273		}
00274	}
00275		
00276	// server moves the rocket based on clients input, and compares the resultant location to the client's view of the location
00277	function ServerMove(float TimeStamp, vector ClientLoc, int Pitch, int Yaw)
00278	{
00279		local float ClientErr, DeltaTime;
00280		local vector LocDiff;
00281	
00282		if ( CurrentTimeStamp >= TimeStamp )
00283			return;
00284	
00285		if ( CurrentTimeStamp > 0 )
00286			DeltaTime = TimeStamp - CurrentTimeStamp;
00287		CurrentTimeStamp = TimeStamp;
00288		GuidedRotation.Pitch = Pitch;
00289		GuidedRotation.Yaw = Yaw;
00290		if ( DeltaTime > 0 )	
00291			MoveRocket(DeltaTime, Velocity, GuidedRotation);
00292		if ( Level.TimeSeconds - LastUpdateTime > 0.3 )
00293		{
00294			ClientErr = 10000;
00295		}
00296		else if ( Level.TimeSeconds - LastUpdateTime > 0.07 )
00297		{
00298			LocDiff = Location - ClientLoc;
00299			ClientErr = LocDiff Dot LocDiff;
00300		}
00301	
00302		// If client has accumulated a noticeable positional error, correct him.
00303		if ( ClientErr > 3 )
00304		{
00305			LastUpdateTime = Level.TimeSeconds;
00306			ClientAdjustPosition(TimeStamp, Location.X, Location.Y, Location.Z, Velocity.X, Velocity.Y, Velocity.Z);
00307		}
00308	}
00309	
00310	simulated function MoveRocket(float DeltaTime, vector CurrentVelocity, rotator GuideRotation )
00311	{
00312		local int OldRoll, RollMag;
00313		local rotator NewRot;
00314		local float SmoothRoll;
00315		local vector OldVelocity, X,Y,Z;
00316	
00317		if ( (Role == ROLE_Authority) && ( (Guider == None) || (Guider.Health <= 0)
00318					|| (Guider.IsA('PlayerPawn') && (PlayerPawn(Guider).ViewTarget != self)) || Guider.IsInState('FeigningDeath')) )
00319		{
00320			Explode(Location,Vect(0,0,1));
00321			return;
00322		}
00323	
00324		ServerUpdate = Level.TimeSeconds;
00325		OldRoll = Rotation.Roll & 65535;
00326		OldVelocity = CurrentVelocity;
00327		Velocity = CurrentVelocity + Vector(GuideRotation) * 1500 * DeltaTime;
00328		Velocity = Normal(Velocity) * 550;
00329		NewRot = Rotator(Velocity);
00330	
00331		// Roll Warhead based on acceleration
00332		GetAxes(NewRot, X,Y,Z);
00333		RollMag = int(10 * (Y Dot (Velocity - OldVelocity))/DeltaTime);
00334		if ( RollMag > 0 ) 
00335			NewRot.Roll = Min(12000, RollMag); 
00336		else
00337			NewRot.Roll = Max(53535, 65536 + RollMag);
00338	
00339		//smoothly change rotation
00340		if (NewRot.Roll > 32768)
00341		{
00342			if (OldRoll < 32768)
00343				OldRoll += 65536;
00344		}
00345		else if (OldRoll > 32768)
00346			OldRoll -= 65536;
00347	
00348		SmoothRoll = FMin(1.0, 5.0 * deltaTime);
00349		NewRot.Roll = NewRot.Roll * SmoothRoll + OldRoll * (1 - SmoothRoll);
00350		SetRotation(NewRot);
00351	
00352		if ( (Level.NetMode != NM_Standalone)
00353			&& ((Level.NetMode != NM_ListenServer) || (Instigator == None) 
00354				|| (Instigator.IsA('PlayerPawn') && (PlayerPawn(Instigator).Player != None)
00355					&& (ViewPort(PlayerPawn(Instigator).Player) == None))) )
00356			AutonomousPhysics(DeltaTime);
00357	
00358		if ( Role == ROLE_Authority )
00359		{
00360			RealLocation = Location;
00361			RealVelocity = Velocity;
00362		}
00363	}
00364	
00365	simulated function PostRender( canvas Canvas )
00366	{
00367		local float Dist;
00368		local Pawn P;
00369		local int XPos, YPos;
00370		local Vector X,Y,Z, Dir;
00371	
00372		GetAxes(Rotation, X,Y,Z);
00373		Canvas.Font = Font'TinyRedFont';
00374		if ( Level.bHighDetailMode )
00375			Canvas.Style = ERenderStyle.STY_Translucent;
00376		else
00377			Canvas.Style = ERenderStyle.STY_Normal;
00378		foreach visiblecollidingactors(class'Pawn', P, 2000,, true)
00379		{
00380			Dir = P.Location - Location;
00381			Dist = VSize(Dir);
00382			Dir = Dir/Dist;
00383			if ( (Dir Dot X) > 0.7 )
00384			{
00385				XPos = 0.5 * Canvas.ClipX * (1 + 1.4 * (Dir Dot Y));
00386				YPos = 0.5 * Canvas.ClipY * (1 - 1.4 * (Dir Dot Z));
00387				Canvas.SetPos(XPos - 8, YPos - 8);
00388				Canvas.DrawIcon(texture'CrossHair6', 1.0);
00389				Canvas.SetPos(Xpos - 12, YPos + 8);
00390				Canvas.DrawText(Dist, true);
00391			}
00392		}	
00393	}		
00394	
00395	simulated function SavedMove GetFreeMove()
00396	{
00397		local SavedMove s;
00398	
00399		if ( FreeMoves == None )
00400			return Spawn(class'SavedMove');
00401		else
00402		{
00403			s = FreeMoves;
00404			FreeMoves = FreeMoves.NextMove;
00405			s.NextMove = None;
00406			return s;
00407		}	
00408	}
00409	
00410	auto state Flying
00411	{
00412		function BeginState()
00413		{
00414			ServerUpdate = Level.TimeSeconds;
00415			GuidedRotation = Rotation;
00416			OldGuiderRotation = Rotation;
00417			Velocity = speed*vector(Rotation);
00418			Acceleration = vect(0,0,0);
00419			if ( (Level.NetMode != NM_Standalone) && (Role == ROLE_Authority) )
00420			{
00421				if ( (PlayerPawn(Instigator) != None) 
00422					&& (ViewPort(PlayerPawn(Instigator).Player) != None) )
00423					RemoteRole = ROLE_SimulatedProxy;
00424				else
00425					RemoteRole = ROLE_AutonomousProxy;
00426			}
00427		}
00428	}
00429	
00430	defaultproperties
00431	{
00432	     RemoteRole=ROLE_DumbProxy
00433	     NetPriority=3.000000
00434	}

End Source Code