Chimeric Home

  Reference
Material to look stuff up in.

  UnrealScript
That lovely java cum C++ language

  A Look at Mods
You wanted work in progress - and here it is

  Bots
Custom bots & configurations

  Misc
Stuff we can't place easily :-)

  Contributors
The guys and gals of Chimeric


Turret Pt. 2
Mod Code : ca
Mod Text : ca

12 November 1998

Download the Mod


//=============================================================================
// Turret - How to make a simple player-controlled Turret
//
// Part 2:
//
// In Part 2 we add the ability to make our Turret Fire, either
// a chosen projectile, or just regular bullets.  Also modify
// the way the Turret is controlled a little bit so that it can
// be rotated using the mouse.  The majority of the code is the
// same as in Part 1, except for a few new functions/states.
//
// -ca
// ca@planetunreal.com
//
//=============================================================================



//=============================================================================
// Turret
//
// In this class we need to basically add a new state and 2 new functions.
// The Fire() function just sends the Turret into the Firing state, where
// the function FireShot() either spawns a projectile or does a bullet trace.
// Most of this code is based on the same setup as normal Unreal weapons,
// albeit there are a few differences.
//=============================================================================

class Turret expands Actor;

var() float MaxYaw, MaxPitch, YawRate, PitchRate, FireRate;


// TurretDamage determines the amount of damage done when bInstantHit is set to true.
// TurretHeight has been implemented to automatically place the Turret a certain distance
// above the ground.  This allows for mappers to create different "bases" for the Turret
// to sit upon.

var() int TurretDamage, TurretHeight;		


// FireOffset is used to determine the spawning location of fired projectiles.

var() vector FireOffset;


// bInstantHit tells the Turret whether to simulate a bullet-firing sequence similiar to
// the way the automag/rifle works.  If bInstantHit is false, then the Turret will fire
// whatever projectile determined by ProjClass.

var() bool bInstantHit;
var() class ProjClass;

var rotator CurRot, InitialRot;
var Pawn User;

function PreBeginPlay()
{
	local vector HitLocation, HitNormal, newLoc;
	local actor other;
		
	InitialRot = Rotation;
	CurRot.Yaw = 0;
	CurRot.Pitch = 0;
	

	// This is the code to set the Turret above the ground.
	// It performs a trace down (relative to the Turret) and then
	// sets the gun TurretHeight above whatever it hits.

	Trace(HitLocation, HitNormal, vect(0,0,-1) * 1000, Location);
	if (HitLocation.Z != 0)
	{
		newLoc = Location;
		newLoc.Z = HitLocation.Z + TurretHeight;
		setLocation(newLoc);
	}
}


// Fire() is used to send the Turret into a firing sequence.  This is also a good
// place to call any animations/sound functions for Turrets more detailed than this
// one..:)

function Fire()
{
	GotoState('Firing');
}


// Nothing has changed in either YawTurret or PitchTurret.

function YawTurret(int Sign)
{
	local rotator newRot;
	
	CurRot.Yaw += YawRate * 1024 * Sign;

	if (CurRot.Yaw > MaxYaw)
		CurRot.Yaw = MaxYaw;
	else if (CurRot.Yaw <-maxyaw) CurRot.Yaw="-MaxYaw;" newRot="InitialRot;" newRot +="CurRot;" SetRotation(newRot); } function PitchTurret(int Sign) { local rotator newRot; CurRot.Pitch +="PitchRate" * 1024 * Sign; if (CurRot.Pitch> MaxPitch)
		CurRot.Pitch = MaxPitch;
	else if (CurRot.Pitch <-maxpitch) CurRot.Pitch="-MaxPitch;" newRot="InitialRot;" newRot +="CurRot;" SetRotation(newRot); } auto state Idle { Begin: } 
// The Firing state is the where the good stuff happens.  When we are first put into this state
// the Turret fires a shot, then sleeps for FireRate (in seconds).  After that if the Turret
// still has a User and the User is no longer pressing the fire button (bFire == 0), then go
// back to the Idle state, else loop the whole sequence again.

state Firing
{

	// FireShot functions two different ways depending on whether bInstantHit == true.
	// If bInstantHit == true, then the Turret traces a line in the direction it is
	// facing (EndTrace), and if it finds a Pawn then it damages the pawn, else it
	// makes a little smokepuff.
	//
	// if bInstantHit == false, then the Turret spawns a projectile starting from the
	// Turret's Location, plus FireOffset.  By setting ProjClass in the default
	// properties to any projectile, the Turret can be used for any type of flying
	// death that you can imagine (er code). 

	function FireShot()
	{
		local vector HitLocation, HitNormal, StartTrace, EndTrace, X,Y,Z;
		local actor Other;

		if (bInstantHit)
		{
			GetAxes(Rotation,X,Y,Z);
			StartTrace = Location + FireOffset;
			EndTrace = StartTrace + vector(Rotation) * FRand() * 5000;
			Other = Trace(HitLocation,HitNormal,EndTrace,StartTrace);
		
			if (Other.IsA('Pawn'))
				Other.TakeDamage(TurretDamage, User, HitLocation, 3000.0*X, 'shot');
			else if (Other != none)
				spawn(class'SpriteSmokePuff',,,HitLocation+HitNormal*9);
		}
		else if (ProjClass != none)
		{
			GetAxes(Rotation, X, Y, Z);
			spawn(ProjClass,,,Location + FireOffset, rotator( Location + FireOffset + X * 5000 + vector(Rotation) * 10000));
		}
	}
	
Begin:

// Firing is just an easy way to keep looping inside the Firing state.

Firing:
	FireShot();
	Sleep(FireRate);
	if (PlayerPawn(user) != none)
		if (User.bFire == 0)
			GotoState('Idle');
	Goto('Firing');
}

defaultproperties
{
     MaxYaw=12192.000000
     maxPitch=12192.000000
     YawRate=0.400000
     PitchRate=0.400000
     FireRate=0.600000
     TurretDamage=15
     ProjClass=Class'UnrealI.Rocket'
     DrawType=DT_Mesh
     Mesh=Mesh'UnrealI.QuadShotHeld'
     DrawScale=1.500000
     bCollideActors=True
     bCollideWorld=True
     bBlockActors=True
     bBlockPlayers=True
}

//=============================================================================
// End Turret
//=============================================================================



//=============================================================================
// TurretMaleOne
//
// The major changes we need to make in our Player class is to override the
// Fire function so that the Turret fires instead of the current weapon, also
// we need to make a few minor changes in ActivateItem() to let the Turret
// know who is using it, so that it can know when to stop firing.
//=============================================================================

class TurretMaleOne expands MaleOne;

var bool bUsingTurret;
var Turret TGun;


// Only need to check if we're using a Turret, if so then Fire the Turret and
// not the weapon.

exec function Fire( optional float F )
{
	if( bShowMenu || Level.Pauser!="" )
		return;
	if (bUsingTurret && TGun != none)
	{
		TGun.Fire();
	} 
	else if( Weapon!=None )
	{
		Weapon.bPointing = true;
		Weapon.Fire(F);
		PlayFiring();
	}
}


// The only major change needed here is TGun.User = self, that way the Turret
// has a reference of us to check to see if bFire == 0, ie whether or not
// we still want to Fire the gun.

exec function ActivateItem()
{
	local actor a;
	
	if (!bUsingTurret)
	{
		log("ActivateItem(): !bUsingTurret");
		foreach RadiusActors(class'Actor', a, 150)
			if (a.IsA('Turret'))
			{
				bUsingTurret = true;
				TGun = Turret(a);
				TGun.User = self;
				log("ActivateItem(): !bUsingTurret: a.IsA('Turret')");
			}
	}
	else
	{
		bUsingTurret = false;
		TGun.User = none;
		TGun.GotoState('Idle');
		TGun.setRotation(TGun.InitialRot);
		TGun = none;
	}
	
	if( bShowMenu || Level.Pauser!="" )
		return;
	if (SelectedItem!=None) 
		SelectedItem.Activate();
}


// PlayerInput has been completely changed now to incorporate the Mouse into
// the rotation of the Turret.  Instead of relying on aBaseX and aBaseY for
// movement, we use aForward and aLookUp for pitching the Turret, and aTurn
// and aStrafe for yawing the Turret. 

event PlayerInput( float DeltaTime )
{
	local float SmoothTime, MouseScale;
	
	if ( bShowMenu && (myHud != None) ) 
	{
		if ( myHud.MainMenu != None )
			myHud.MainMenu.MenuTick( DeltaTime );
		// clear inputs
		bEdgeForward = false;
		bEdgeBack = false;
		bEdgeLeft = false;
		bEdgeRight = false;
		bWasForward = false;
		bWasBack = false;
		bWasLeft = false;
		bWasRight = false;
		aStrafe = 0;
		aTurn = 0;
		aForward = 0;
		aLookUp = 0;
		return;
	}
	else if ( bDelayedCommand )
	{
		bDelayedCommand = false;
		ConsoleCommand(DelayedCommand);
	}
				

	// Check for Dodge move
	// flag transitions

	bEdgeForward = (bWasForward ^^ (aBaseY > 0));
	bEdgeBack = (bWasBack ^^ (aBaseY <0)); bEdgeLeft="(bWasLeft" ^^ (aStrafe> 0));
	bEdgeRight = (bWasRight ^^ (aStrafe <0)); bWasForward="(aBaseY"> 0);
	bWasBack = (aBaseY <0); bWasLeft="(aStrafe"> 0);
	bWasRight = (aStrafe <0); if (aLookUp !="0)" bKeyboardLook="true;" if (bSnapLevel !="0)" bKeyboardLook="false;" 
	// Smooth and amplify mouse movement

	SmoothTime = FMin(0.2, 3 * DeltaTime);
	MouseScale = MouseSensitivity * DesiredFOV * 0.0111;
	aMouseX = aMouseX * MouseScale;
	aMouseY = aMouseY * MouseScale;

	if ( (SmoothMouseX == 0) || (aMouseX == 0) 
			|| ((SmoothMouseX > 0) != (aMouseX > 0)) )
		SmoothMouseX = aMouseX;
	else if ( (SmoothMouseX <0.85 * aMouseX) || (SmoothMouseX> 1.17 * aMouseX) )
		SmoothMouseX = 5 * SmoothTime * aMouseX + (1 - 5 * SmoothTime) * SmoothMouseX;
	else
		SmoothMouseX = SmoothTime * aMouseX + (1 - SmoothTime) * SmoothMouseX;

	if ( (SmoothMouseY == 0) || (aMouseY == 0) 
			|| ((SmoothMouseY > 0) != (aMouseY > 0)) )
		SmoothMouseY = aMouseY;
	else if ( (SmoothMouseY <0.85 * aMouseY) || (SmoothMouseY> 1.17 * aMouseY) )
		SmoothMouseY = 5 * SmoothTime * aMouseY + (1 - 5 * SmoothTime) * SmoothMouseY;
	else
		SmoothMouseY = SmoothTime * aMouseY + (1 - SmoothTime) * SmoothMouseY;

	aMouseX = 0;
	aMouseY = 0;


	// Remap raw x-axis movement.

	if( bStrafe!=0 )
	{
		// Strafe.
		aStrafe += aBaseX + SmoothMouseX;
		aBaseX   = 0;
	}
	else
	{

		// Forward.

		aTurn  += aBaseX + SmoothMouseX;
		aBaseX  = 0;
	}


	// Remap mouse y-axis movement.

	if( bAlwaysMouseLook || (bLook!=0) )
	{
		// Look up/down.
		bKeyboardLook = false;
		if ( bInvertMouse )
			aLookUp -= SmoothMouseY;
		else
			aLookUp += SmoothMouseY;
	}
	else
	{

		// Move forward/backward.

		aForward += SmoothMouseY;
	}


	// Remap other y-axis movement.

	aForward += aBaseY;
	aBaseY    = 0;
	

	// Here is the change, basically we use aForward, aLookUp, aStrafe, and aTurn
	// because the rest of the code has already calculated both normal key movement
	// (aBaseX, aBaseY) and mouse movement.  Other than that we still rotate
	// the Turret as before.

	if (bUsingTurret && TGun != none)
	{
		if (aForward > 0 || aLookUp > 0)
			TGun.PitchTurret(-1);
		else if (aForward <0 || aLookUp < 0) TGun.PitchTurret(1); if (aStrafe> 0 || aTurn > 0)
			TGun.YawTurret(1);
		else if (aStrafe <0 || aTurn < 0) TGun.YawTurret(-1); 
		// clear inputs

		bEdgeForward = false;
		bEdgeBack = false;
		bEdgeLeft = false;
		bEdgeRight = false;
		bWasForward = false;
		bWasBack = false;
		bWasLeft = false;
		bWasRight = false;
		aStrafe = 0;
		aTurn = 0;
		aForward = 0;
		aLookUp = 0;
		return;
	}


	// Handle walking.

	HandleWalking();
}


// No change to UpdateRotation

function UpdateRotation(float DeltaTime, float maxPitch)
{
	local rotator newRotation;
	local vector X,Y,Z, newLoc;
	
	DesiredRotation = ViewRotation; //save old rotation
	ViewRotation.Pitch += 32.0 * DeltaTime * aLookUp;
	ViewRotation.Pitch = ViewRotation.Pitch & 65535;
	If ((ViewRotation.Pitch > 18000) && (ViewRotation.Pitch <49152)) { If (aLookUp> 0) 
			ViewRotation.Pitch = 18000;
		else
			ViewRotation.Pitch = 49152;
	}
	ViewRotation.Yaw += 32.0 * DeltaTime * aTurn;
	ViewShake(deltaTime);
	ViewFlash(deltaTime);
		
	newRotation = Rotation;
	newRotation.Yaw = ViewRotation.Yaw;
	newRotation.Pitch = ViewRotation.Pitch;
	If ( (newRotation.Pitch > maxPitch * RotationRate.Pitch) && (newRotation.Pitch <65536 maxPitch * RotationRate.Pitch) ) { If (ViewRotation.Pitch < 32768) newRotation.Pitch="maxPitch" * RotationRate.Pitch; else newRotation.Pitch="65536" maxPitch * RotationRate.Pitch; } if (bUsingTurret && TGun !="none)" { newRotation="TGun.Rotation;" GetAxes(newRotation, X,Y,Z); newLoc="TGun.Location" + X * 50; newLoc.Z="Location.Z;" SetLocation(newLoc); ViewRotation="newRotation;" } setRotation(newRotation); } defaultproperties { } 
//=============================================================================
// End TurretMaleOne
//=============================================================================



//=============================================================================
// So now the Turret is able to fire, and it has learned how to use the
// mouse to determine rotation.  There are definitely some areas where
// this Turret could be improved (but thats what coders are for:).  I hope
// this helps you with a starting base to make all of your wonderous (and
// destructive) Turret creations.  Good luck!
//
// -ca
// ca@planetunreal.com 
//=============================================================================

    
    
Opinions on this article, love it, hate it? - feedback