Core.Object | +--Engine.Actor | +--Engine.Pawn | +--RuneI.ScriptPawn | +--RuneI.Cuttle
float
ThrustDist
bool
bAttacking
bDigesting
string
debugstring
Actor
prey
vector
targetloc
void
CheckForEnemies()
Texture
PainSkin(int BodyPart)
PickEnemy()
PlayDeath(name DamageType)
//============================================================ // Animation functions //============================================================
PostBeginPlay()
PreSetMovement()
SideStepDestination(vector targetpos)
// Choose a side-step destination closer to target than we are now
ZoneChange(ZoneInfo newZone)
Timer()
Touch(Actor Other)
PickDestination()
SeePlayer(Actor seen)
BeginState()
PickTargetLocation()
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 }