RuneI
Class Cuttle

source: c:\runehov\RuneI\Classes\Cuttle.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Pawn
         |
         +--RuneI.ScriptPawn
            |
            +--RuneI.Cuttle
Direct Known Subclasses:None

class Cuttle
extends RuneI.ScriptPawn

//============================================================================= // Cuttle. //=============================================================================
Variables
 float ThrustDist
           Whether unable to hunt currently
 bool bAttacking
           Whether unable to hunt currently
 bool bDigesting
           Whether unable to hunt currently
 string debugstring
           Whether unable to hunt currently
 Actor prey
           Prey he is about to eat
 vector targetloc
           target location for FreeRoaming

States
OutOfWater, CuttleHunting, Flee, FreeRoaming, Idle

Function Summary
 void CheckForEnemies()
 Texture PainSkin(int BodyPart)
 bool PickEnemy()
 void PlayDeath(name DamageType)
     
//============================================================
// Animation functions
//============================================================
 void PostBeginPlay()
 void PreSetMovement()
 void SideStepDestination(vector targetpos)
     
// Choose a side-step destination closer to target than we are now
 void ZoneChange(ZoneInfo newZone)


State OutOfWater Function Summary


State CuttleHunting Function Summary
 void Timer()
 void Touch(Actor Other)
 void PickDestination()
 void SeePlayer(Actor seen)
 void BeginState()


State Flee Function Summary


State FreeRoaming Function Summary
 void PickDestination()
 void Touch(Actor Other)
 void PickTargetLocation()
 void Timer()
 void BeginState()


State Idle Function Summary
 void BeginState()



Source Code


00001	//=============================================================================
00002	// Cuttle.
00003	//=============================================================================
00004	class Cuttle expands ScriptPawn;
00005	
00006	
00007	
00008	/* Description:
00009		Ambient creature which can be interested in the player, but will not attack.  It eats
00010		dealie fish when it can and squirts ink when threatened.  Upon death, it releases it's
00011		ink and sinks.	Movement is a side-stepping hover, always facing it's target.
00012		
00013	   TODO:
00014	   	make killing a dealie actually make it hidden, move to school, sleep, and restart
00015	   		(to avoid the nasty thrashing from actually destroying/respawning)
00016		ink squirt
00017	   	get interested in ragnar for a while
00018		make user settable vars for parameters
00019	*/
00020	
00021	
00022	var actor prey;			// Prey he is about to eat
00023	var vector targetloc;	// target location for FreeRoaming
00024	var bool bDigesting;	// Whether unable to hunt currently
00025	var float ThrustDist;
00026	var bool bAttacking;
00027	
00028	var string debugstring;
00029	
00030	
00031	function CheckForEnemies()
00032	{
00033	}
00034	
00035	function Texture PainSkin(int BodyPart)
00036	{
00037	}
00038	
00039	function PreSetMovement()
00040	{
00041		bCanJump = false;
00042		bCanWalk = false;
00043		bCanSwim = true;
00044		bCanFly = false;
00045		MinHitWall = -0.6;
00046		bCanOpenDoors = false;
00047		bCanDoSpecial = false;
00048	}
00049	
00050	function PostBeginPlay()
00051	{
00052		Super.PostBeginPlay();
00053		ThrustDist = 200;
00054		bAttacking = false;
00055		HomeBase = Location;
00056	}
00057	
00058	function ZoneChange(ZoneInfo newZone)
00059	{
00060		if (!newZone.bWaterZone)
00061		{
00062			SetPhysics(PHYS_Falling);
00063			GotoState('OutOfWater');
00064		}
00065		else
00066		{
00067			SetPhysics(PHYS_Swimming);
00068		}
00069	}
00070	
00071	function bool PickEnemy()
00072	{
00073		local int count, pick;
00074		local DealieFish A;
00075	
00076		Enemy = None;
00077		
00078		// Pick a randomly distributed fish	
00079		foreach VisibleActors(class'DealieFish', A)
00080		{
00081			if (A.Health > 0)
00082				count++;
00083		}
00084		pick = FRand() * count;
00085		foreach VisibleActors(class'DealieFish', A)
00086		{
00087			if (A.Health > 0)
00088			{
00089				if (--pick <= 0)
00090				{
00091					Enemy = A;
00092					break;
00093				}
00094			}
00095		}
00096		return(Enemy!=None);
00097	}
00098	
00099	// Choose a side-step destination closer to target than we are now
00100	function SideStepDestination(vector targetpos)
00101	{	
00102		local vector ToTarget, ToSide, ToHeight;
00103		
00104		ToTarget = targetpos - Location;
00105		if (ToTarget.Z > 0)
00106			ToHeight = vect(0,0,1);
00107		else
00108			ToHeight = vect(0,0,-1);
00109		ToTarget.Z = 0;
00110		ToTarget = Normal(ToTarget);
00111		ToSide = ToTarget cross vect(0,0,1);
00112		if (FRand() < 0.5)
00113			ToSide *= -1;
00114		Destination = Location +
00115			ToTarget*RandRange(50, 100) +
00116			ToSide*RandRange(25,50) +
00117			ToHeight*RandRange(40,50) +
00118			vect(0,0,1)*RandRange(-10,10);
00119	}
00120	
00121	
00122	
00123	//============================================================
00124	// Animation functions
00125	//============================================================
00126	
00127	function PlayDeath(name DamageType)	          { PlayAnim  ('death', 1.0, 0.1);     }
00128	
00129	
00130	//============================================================
00131	// States
00132	//============================================================
00133	
00134	auto state Idle
00135	{
00136		function BeginState()
00137		{
00138			ZoneChange(Region.Zone);
00139		}
00140		
00141	Begin:
00142		LoopAnim('swim', 1.0, 0.1);
00143	CanSee:
00144		if (PlayerCanSeeMe())
00145			GotoState('FreeRoaming');
00146		Sleep(1);
00147		Goto('CanSee');
00148	}
00149	
00150	
00151	state FreeRoaming
00152	{
00153		ignores Bump, SeePlayer;
00154	
00155		function BeginState()
00156		{
00157			RotationRate.Yaw = 3000;
00158			bDigesting = true;
00159			SetTimer(RandRange(2, 15), false);	// Start Digesting
00160			Enable('SeePlayer');
00161		}
00162	
00163		function Timer()
00164		{
00165			bDigesting = false;
00166			PickTargetLocation();
00167		}
00168			
00169		function PickTargetLocation()
00170		{
00171			// Try to find an enemy
00172			if (!bDigesting && PickEnemy())
00173				GotoState('CuttleHunting', 'PickDest');
00174	
00175			targetloc = Location + Velocity*2 + VRand()*RandRange(100,500);
00176	
00177			// Make sure target location is in water
00178			
00179		}
00180	
00181		function Touch(actor Other)
00182		{
00183			if (DealieFish(Other) == None)
00184			{	// Run away if not a dealie
00185				Destination = Location + (Location - Other.Location) * 3 + VRand()*2;
00186				GotoState('Flee');
00187			}
00188		}
00189	
00190		function PickDestination()
00191		{
00192			// If target is reached, pick a new target
00193			if (VSize(targetloc - Location) < 100)
00194			{
00195				GotoState('FreeRoaming', 'PickTarget');
00196			}
00197			else if (!pointReachable(targetloc))
00198			{
00199				targetloc = HomeBase;
00200				SideStepDestination(targetloc);
00201			}
00202			else
00203			{
00204				SideStepDestination(targetloc);
00205			}
00206		}
00207	
00208	Begin:
00209		SetPhysics(PHYS_Swimming);
00210	PickTarget:
00211		PickTargetLocation();
00212	PickWayPoint:
00213		PickDestination();
00214	Swim:
00215		MoveTo(Destination);
00216		if (FRand()<0.3)
00217			Sleep(RandRange(0.1,1.0));
00218		Goto('PickWaypoint');
00219	}
00220	
00221	
00222	// Flee to destination, then resume FreeRoaming
00223	state Flee
00224	{
00225		ignores HearNoise, SeePlayer, Bump, Touch;
00226		
00227	Begin:
00228		LoopAnim('Swim', 1.0, 0.1);
00229		MoveTo(Destination);
00230		Sleep(1);
00231		GotoState('FreeRoaming');
00232	}
00233	
00234	
00235	state CuttleHunting
00236	{
00237		ignores Bump;
00238		
00239		function BeginState()
00240		{
00241			RotationRate.Yaw = default.RotationRate.Yaw;
00242			SetTimer(0.2, true);	// Search for nearby prey
00243		}
00244	
00245		function SeePlayer(actor seen)
00246		{
00247			// chance of following player
00248		}
00249	
00250		function PickDestination()
00251		{
00252			local vector ToEnemy;
00253	
00254			if (Enemy == None)
00255				GotoState('FreeRoaming');
00256			else if (Enemy.Health<=0)
00257				GotoState('FreeRoaming');
00258			else
00259			{
00260				ToEnemy = Enemy.Location - Location;
00261				SideStepDestination(Enemy.Location);
00262			}
00263		}
00264		
00265		function Touch(actor Other)
00266		{
00267			if (DealieFish(Other) == None)
00268			{	// Run away if not a dealie
00269				Destination = Location + (Location - Other.Location) * 5;
00270				bAttacking = false;
00271				SetPhysics(PHYS_Swimming);
00272				GotoState('Flee');
00273			}
00274			else if (bAttacking && (Other==Enemy))
00275			{	// Thrusting at this dealie
00276				Enemy.TakeDamage(Enemy.Health + 30, self, Enemy.Location, vect(0,0,0), 'eaten');
00277				Enemy = None;
00278			}
00279		}
00280		
00281		function Timer()
00282		{	// Check for any targets close enough for a thrust
00283			local DealieFish A;
00284			local vector ToEnemy;
00285	
00286			foreach RadiusActors(class'DealieFish', A, ThrustDist, Location)
00287			{
00288				if (A.Health > 0)
00289				{
00290					ToEnemy = A.Location - Location;
00291					if ((VSize(ToEnemy) < ThrustDist) && Abs(ToEnemy.Z)<50)
00292					{
00293						Enemy = A;
00294						SetTimer(0, false);
00295						GotoState('CuttleHunting', 'ThrustAttack');
00296						break;
00297					}
00298				}
00299			}
00300		}
00301	
00302	Begin:
00303		SetPhysics(PHYS_Swimming);
00304	PickDest:
00305		PickDestination();
00306	Swim:
00307		if (Enemy!=None)
00308			StrafeFacing(Destination, Enemy);
00309		if (FRand()<0.3)
00310			Sleep(RandRange(0.1,1.0));
00311		Goto('PickDest');
00312	ThrustAttack:
00313		Disable('SeePlayer');
00314		SetPhysics(PHYS_Falling);
00315		bAttacking = true;
00316	
00317		// Put fish to sleep	
00318		Enemy.bMovable = false;
00319		TurnToward(Enemy);
00320		
00321		// .5 second thrust move covering distance to 
00322		Destination = Enemy.Location;
00323		Velocity = (Destination - Location) * 2 * 2;
00324		Acceleration = Velocity / 0.5;
00325		PlayAnim('AttackA', 1.0, 0.1);
00326		Sleep(0.5);
00327	
00328		// If the fish survived, wake him up
00329		if (Enemy!=None)
00330		{
00331			Enemy.bMovable = true;
00332		}
00333		
00334		LoopAnim('Swim', 1.0, 0.1);
00335		SetPhysics(PHYS_Swimming);
00336		bAttacking = false;
00337		Enable('SeePlayer');
00338	
00339		GotoState('FreeRoaming');
00340	}
00341	
00342	
00343	State OutOfWater
00344	{
00345		ignores Bump, Touch, SeePlayer, HearNoise;
00346	
00347	Begin:
00348	}
00349	
00350	
00351	simulated function Debug(Canvas canvas, int mode)
00352	{
00353		local vector ToEnemy;
00354	
00355		Super.Debug(canvas, mode);
00356	
00357		Canvas.DrawText("Cuttle:");
00358		Canvas.CurY -= 8;
00359		Canvas.DrawText(" WaterSpeed: "$WaterSpeed);
00360		Canvas.CurY -= 8;
00361		Canvas.DrawText(" Destination: "$Destination);
00362		Canvas.CurY -= 8;
00363		Canvas.DrawText(" Enemy: "$Enemy);
00364		Canvas.CurY -= 8;
00365		Canvas.DrawText(" DebugString: "$DebugString);
00366		Canvas.CurY -= 8;
00367		Canvas.DrawText(" bAttacking: "$bAttacking);
00368		Canvas.CurY -= 8;
00369		Canvas.DrawText(" MoveTimer: "$MoveTimer);
00370		Canvas.CurY -= 8;
00371	
00372		if (Enemy!=None)
00373			ToEnemy = Enemy.Location - Location;
00374		else
00375			ToEnemy = targetloc - Location;
00376		
00377		Canvas.DrawText(" ToTarget: "$ToEnemy);
00378		Canvas.CurY -= 8;
00379		
00380		// If within range, thrust attack at the fish
00381		if (VSize(ToEnemy) < 200)
00382			Canvas.SetColor(255, 255, 255);
00383		else
00384			Canvas.SetColor(255, 0, 0);
00385		Canvas.DrawText(" In Range");
00386		Canvas.CurY -= 8;
00387		
00388		if (Abs(ToEnemy.Z)<40)
00389			Canvas.SetColor(255, 255, 255);
00390		else
00391			Canvas.SetColor(255, 0, 0);
00392		Canvas.DrawText(" Within Z");
00393		Canvas.CurY -= 8;
00394	
00395		Canvas.DrawLine3D(Location, Location+ToEnemy, 0,   0, 255);
00396		Canvas.DrawLine3D(Location, Destination,    255, 255, 255);
00397	}
00398	
00399	defaultproperties
00400	{
00401	     bBurnable=False
00402	     bCanStrafe=True
00403	     ClassID=17
00404	     PeripheralVision=-1.000000
00405	     AttitudeToPlayer=ATTITUDE_Ignore
00406	     HitSound1=Sound'CreaturesSnd.Fish.fish03'
00407	     HitSound2=Sound'CreaturesSnd.Fish.fish03'
00408	     HitSound3=Sound'CreaturesSnd.Fish.fish03'
00409	     Die=Sound'CreaturesSnd.Fish.fish05'
00410	     Die2=Sound'CreaturesSnd.Fish.fish05'
00411	     Die3=Sound'CreaturesSnd.Fish.fish05'
00412	     DrawScale=3.000000
00413	     SoundRadius=20
00414	     SoundVolume=90
00415	     SoundPitch=121
00416	     AmbientSound=Sound'EnvironmentalSnd.Bubbles.bubbleswater01L'
00417	     TransientSoundRadius=800.000000
00418	     CollisionRadius=30.000000
00419	     CollisionHeight=9.000000
00420	     bBlockActors=False
00421	     bBlockPlayers=False
00422	     Buoyancy=100.000000
00423	     RotationRate=(Pitch=0,Yaw=30000,Roll=0)
00424	     Skeletal=SkelModel'creatures.Cuttle'
00425	}

End Source Code