SarkBall
Class SarkBallBotGoblin

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

class SarkBallBotGoblin
extends SarkBall.SarkBallBot

//----------------------------------------------------------- // //-----------------------------------------------------------
Variables
 Actor CurrentPoint
 EGoblinHead GoblinHead
 EGoblinLimb GoblinLimb
 EGoblinTorso GoblinTorso
 bool bGoblinMask
 int breathcounter

States
DodgeBackflip, DodgeLeft, DodgeRight, DodgeBack, DodgeForward, Fighting, Charging, StayOnPaths, ThrowRocks, Excited, AlertSquawk, ThrowTest, MineRocksPartner2, MineRocksPartner1, MineRocks

Function Summary
 bool AddDefaultInventory()
 void ApplyGoreCap(int BodyPart)
     
//============================================================
//
// ApplyGoreCap
//
//============================================================
 void AttachMask()
     
//============================================================
//
// AttachMask
//
//============================================================
 eAttitude AttitudeToCreature(Pawn Other)
     
//------------------------------------------------
//
// AttitudeToCreature
//
//------------------------------------------------
 bool BodyPartCritical(int BodyPart)
     
//============================================================
//
// BodyPartCritical
//
//============================================================
 int BodyPartForJoint(int joint)
     
//============================================================
//
// BodyPartForJoint
//
// Returns the body part a joint is associated with
//============================================================
 int BodyPartForPolyGroup(int polygroup)
     
//============================================================
//
// BodyPartForPolyGroup
//
//============================================================
 bool BodyPartSeverable(int BodyPart)
     
//============================================================
//
// BodyPartSeverable
//
//============================================================
 void Breath()
     
//------------------------------------------------
//
// Sound Functions
//
//------------------------------------------------
 void Bump(Actor Other)
     
//===================================================================
//
// Bump
//
// If Pawns bump a destroyable decoration, they should smash it
//===================================================================
 bool CanPickup(Inventory item)
     
//============================================================
//
// CanPickup
//
// Let's pawn dictate what it can pick up
//============================================================
 void DrawPrimaryWeapon()
     
//===================================================================
//                         Functions
//===================================================================
 void LimbSevered(int BodyPart, vector Momentum)
     
//============================================================
//
// LimbSevered
//
//============================================================
 Texture PainSkin(int BodyPart)
     
//============================================================
//
// PainSkin
//
// returns the pain skin for a given polygroup
//============================================================
 void PlayBackDeath(name DamageType)
 void PlayBlockHigh(optional float)
 void PlayBlockLow(optional float)
 void PlayCower(optional float)
 void PlayDeath(name DamageType)
 void PlayDodgeBack(optional float)
 void PlayDodgeBackflip(optional float)
 void PlayDodgeDuck(optional float)
 void PlayDodgeForward(optional float)
 void PlayDodgeLeft(optional float)
 void PlayDodgeRight(optional float)
 void PlayDrownDeath(name DamageType)
 void PlayDrowning(optional float)
 void PlayFrontHit(float tween)
 void PlayHeadDeath(name DamageType)
 void PlayHuntStop(optional float)
 void PlayInAir(optional float)
 void PlayJumping(optional float)
 void PlayLeftDeath(name DamageType)
 void PlayMeleeHigh(optional float)
 void PlayMeleeLow(optional float)
 void PlayMoving(optional float)
 void PlayRightDeath(name DamageType)
 void PlaySkewerDeath(name DamageType)
 void PlayTaunting(optional float)
     
//function PlayTaunting(optional float tween)   { PlayAnim  ('pain',               1.0, tween);   }
 void PlayThrowing(optional float)
 void PlayTurning(optional float)
 void PlayWaiting(optional float)
     
//============================================================
// Animation functions
//============================================================
 void PreBeginPlay()
     
//============================================================
//
// PreBeginPlay
//
//============================================================
 void SetGoblinSkins(EGoblinLimb arms, EGoblinTorso torso, EGoblinHead head)
     
//============================================================
//
// SetGoblinSkins
//
//============================================================
 void SetupGoblin()
     
//============================================================
//
// SetupGoblin
//
//============================================================
 void TweenToHuntStop(float time)
 void TweenToJumping(float time)
 void TweenToMeleeHigh(float time)
 void TweenToMeleeLow(float time)
 void TweenToMoving(float time)
 void TweenToThrowing(float time)
 void TweenToTurning(float time)
 void TweenToWaiting(float time)
     
// Tween functions


State DodgeBackflip Function Summary
 void AmbientSoundTimer()


State DodgeLeft Function Summary
 void AmbientSoundTimer()


State DodgeRight Function Summary
 void AmbientSoundTimer()


State DodgeBack Function Summary
 void AmbientSoundTimer()


State DodgeForward Function Summary
 void AmbientSoundTimer()


State Fighting Function Summary
 bool InDangerFromAttack()
 bool ShouldDefend()
 void Timer()
 bool BlockRatherThanDodge()
 void AmbientSoundTimer()
 void EndState()
 void BeginState()


State Charging Function Summary
 void HitWall(vector HitNormal, Actor Wall)
 void PickPaceDest()
 void EnemyNotVisible()
 void Timer()
 void MayFall()
 void BeginState()
     
// Inherits EndState()


State StayOnPaths Function Summary
 void MayFall()
 void HitWall(vector norm, Actor wall)
 void PickDestination()
     
// Consider all destinations from OrderObject to stay close to enemy
 void EndState()
 void BeginState()


State ThrowRocks Function Summary
 bool EnemyInRange(float range)
 void SpawnRock()
 void EnemyNotVisible()


State Excited Function Summary
 void EnemyNotVisible()


State AlertSquawk Function Summary


State ThrowTest Function Summary
 void SpawnRock()
 void Timer()


State MineRocksPartner2 Function Summary


State MineRocksPartner1 Function Summary


State MineRocks Function Summary



Source Code


00001	//-----------------------------------------------------------
00002	//
00003	//-----------------------------------------------------------
00004	class SarkBallBotGoblin expands SarkBallBot;
00005	
00006	var(Sounds) sound          RollSound;
00007	var(Sounds) sound          PaceSound;
00008	
00009	
00010	enum EGoblinLimb
00011	{
00012	     LIMB_RANDOM,
00013	     LIMB_RANDOMWARPAINT,
00014	     LIMB_NORMAL,
00015	     LIMB_WARPAINT1
00016	};
00017	
00018	enum EGoblinTorso
00019	{
00020	     TORSO_RANDOM,
00021	     TORSO_RANDOMWARPAINT,
00022	     TORSO_NORMAL,
00023	     TORSO_WARPAINT1,
00024	     TORSO_WARPAINT2,
00025	     TORSO_WARPAINT3
00026	};
00027	
00028	enum EGoblinHead
00029	{
00030	     HEAD_RANDOM,
00031	     HEAD_RANDOMWARPAINT,
00032	     HEAD_NORMAL,
00033	     HEAD_WARPAINT1,
00034	     HEAD_WARPAINT2,
00035	     HEAD_WARPAINT3
00036	};
00037	
00038	
00039	var() EGoblinLimb     GoblinLimb;
00040	var() EGoblinTorso     GoblinTorso;
00041	var() EGoblinHead     GoblinHead;
00042	var() bool               bGoblinMask;
00043	
00044	var Actor CurrentPoint;
00045	var private int breathcounter;
00046	
00047	
00048	//===================================================================
00049	//                         Functions
00050	//===================================================================
00051	
00052	Function DrawPrimaryWeapon(){
00053	  local Weapon PendingWeapon;
00054	
00055	  PendingWeapon=Spawn(StartWeapon);
00056	  AddInventory(PendingWeapon);
00057	  AcquireInventory(PendingWeapon);
00058	  Weapon = PendingWeapon;
00059	  Weapon.GotoState('Active');
00060	  PendingWeapon.DesiredColorAdjust=SarkBallGame(level.game).GetTeamVectorColor(PlayerReplicationInfo.Team);
00061	  ChangedWeapon();
00062	
00063	}
00064	
00065	
00066	Function bool AddDefaultInventory(){
00067	  Local Shield newShield;
00068	
00069	  DrawPrimaryWeapon();
00070	
00071	  newShield=Spawn(StartShield);
00072	  AddInventory(newShield);
00073	  AcquireInventory(newShield);
00074	  AttachActorToJoint(newShield, JointNamed(ShieldJoint));
00075	  Shield = newShield;
00076	  Shield.GotoState('Active');
00077	  newShield.DesiredColorAdjust=SarkBallGame(level.game).GetTeamVectorColor(PlayerReplicationInfo.Team);
00078	
00079	  Return False;
00080	
00081	
00082	}
00083	
00084	//============================================================
00085	//
00086	// PreBeginPlay
00087	//
00088	//============================================================
00089	function PreBeginPlay()
00090	{
00091	     Super.PreBeginPlay();
00092	
00093	     SetupGoblin();
00094	}
00095	
00096	//------------------------------------------------
00097	//
00098	// AttitudeToCreature
00099	//
00100	//------------------------------------------------
00101	function eAttitude AttitudeToCreature(Pawn Other)
00102	{
00103	     if (Other.IsA('Dwarf') || Other.IsA('Viking') || Other.IsA('Zombie') || Other.IsA('Sark'))
00104	          return ATTITUDE_Hate;
00105	     else if (Other.IsA('Snowbeast'))
00106	          return ATTITUDE_Fear;
00107	     else
00108	          return Super.AttitudeToCreature(Other);
00109	}
00110	
00111	
00112	//============================================================
00113	//
00114	// SetupGoblin
00115	//
00116	//============================================================
00117	function SetupGoblin()
00118	{
00119	     local EGoblinLimb limbs;
00120	     local EGoblinTorso torso;
00121	     local EGoblinHead head;
00122	
00123	     limbs = GoblinLimb;
00124	     switch(GoblinLimb)
00125	     {
00126	          case LIMB_RANDOM:
00127	               switch(Rand(2))
00128	               {
00129	                    case 0:     limbs = LIMB_NORMAL;     break;
00130	                    case 1:     limbs = LIMB_WARPAINT1;     break;
00131	               }
00132	               break;
00133	          case LIMB_RANDOMWARPAINT:
00134	               limbs = LIMB_WARPAINT1;
00135	               break;
00136	     }
00137	
00138	     torso = GoblinTorso;
00139	     switch(GoblinTorso)
00140	     {
00141	          case TORSO_RANDOM:
00142	               switch(Rand(4))
00143	               {
00144	                    case 0:     torso = TORSO_NORMAL;          break;
00145	                    case 1:     torso = TORSO_WARPAINT1;     break;
00146	                    case 2:     torso = TORSO_WARPAINT2;     break;
00147	                    case 3:     torso = TORSO_WARPAINT3;     break;
00148	               }
00149	               break;
00150	          case TORSO_RANDOMWARPAINT:
00151	               switch(Rand(3))
00152	               {
00153	                    case 0:     torso = TORSO_WARPAINT1;     break;
00154	                    case 1:     torso = TORSO_WARPAINT2;     break;
00155	                    case 2:     torso = TORSO_WARPAINT3;     break;
00156	               }
00157	               break;
00158	     }
00159	     
00160	     head = GoblinHead;
00161	     switch(GoblinHead)
00162	     {
00163	          case HEAD_RANDOM:
00164	               switch(Rand(4))
00165	               {
00166	                    case 0:     head = HEAD_NORMAL;          break;
00167	                    case 1:     head = HEAD_WARPAINT1;     break;
00168	                    case 2:     head = HEAD_WARPAINT2;     break;
00169	                    case 3:     head = HEAD_WARPAINT3;     break;
00170	               }
00171	               break;
00172	          case HEAD_RANDOMWARPAINT:
00173	               switch(Rand(3))
00174	               {
00175	                    case 0:     head = HEAD_WARPAINT1;     break;
00176	                    case 1:     head = HEAD_WARPAINT2;     break;
00177	                    case 2:     head = HEAD_WARPAINT3;     break;
00178	               }
00179	               break;
00180	     }
00181	
00182	     SetGoblinSkins(limbs, torso, head);
00183	
00184	     if (bGoblinMask)
00185	          AttachMask();
00186	}
00187	
00188	
00189	//============================================================
00190	//
00191	// AttachMask
00192	//
00193	//============================================================
00194	function AttachMask()
00195	{
00196	     local actor mask;
00197	     mask = Spawn(class'GoblinMask',,, GetJointPos(JointNamed('head')),);
00198	     if (mask != None)
00199	     {
00200	          AttachActorToJoint(mask, JointNamed('head'));
00201	          mask.PlayAnim('on_face', 1.0, 0.1);
00202	     }
00203	     else slog("No spawn mask");
00204	}
00205	
00206	
00207	//============================================================
00208	//
00209	// SetGoblinSkins
00210	//
00211	//============================================================
00212	function SetGoblinSkins(EGoblinLimb arms, EGoblinTorso torso, EGoblinHead head)
00213	{
00214	     switch(arms)
00215	     {
00216	          case LIMB_NORMAL:
00217	               break;
00218	          case LIMB_WARPAINT1:
00219	               SkelGroupSkins[2] = texture'runei.goblinpaintedarmleg';
00220	               SkelGroupSkins[12] = texture'runei.goblinpaintedarmleg';
00221	               SkelGroupSkins[8] = texture'runei.goblinpaintedarmleg';
00222	               SkelGroupSkins[11] = texture'runei.goblinpaintedarmleg';
00223	               break;
00224	     }
00225	     switch(torso)
00226	     {
00227	          case TORSO_NORMAL:
00228	               break;
00229	          case TORSO_WARPAINT1:
00230	               SkelGroupSkins[7] = texture'runei.goblinpaintedbody';
00231	               break;
00232	          case TORSO_WARPAINT2:
00233	               SkelGroupSkins[7] = texture'runei.goblinpaintedbody2';
00234	               break;
00235	          case TORSO_WARPAINT3:
00236	               SkelGroupSkins[7] = texture'runei.goblinpaintedbody3';
00237	               break;
00238	     }
00239	     switch(head)
00240	     {
00241	          case HEAD_NORMAL:
00242	               break;
00243	          case HEAD_WARPAINT1:
00244	               SkelGroupSkins[1] = texture'runei.goblinpaintedhead';
00245	               SkelGroupSkins[6] = texture'runei.goblinpaintedhead';
00246	               break;
00247	          case HEAD_WARPAINT2:
00248	               SkelGroupSkins[1] = texture'runei.goblinpaintedhead2';
00249	               SkelGroupSkins[6] = texture'runei.goblinpaintedhead2';
00250	               break;
00251	          case HEAD_WARPAINT3:
00252	               SkelGroupSkins[1] = texture'runei.goblinpaintedhead3';
00253	               SkelGroupSkins[6] = texture'runei.goblinpaintedhead3';
00254	               break;
00255	     }
00256	}
00257	
00258	
00259	//============================================================
00260	//
00261	// CanPickup
00262	//
00263	// Let's pawn dictate what it can pick up
00264	//============================================================
00265	function bool CanPickup(Inventory item)
00266	{
00267	     if (Health <= 0)
00268	          return false;
00269	
00270	     if (item.IsA('Weapon') && (BodyPartHealth[BODYPART_RARM1] > 0) && (Weapon == None))
00271	     {
00272	          return (item.IsA('axe') || item.IsA('hammer') || item.IsA('Torch'));
00273	     }
00274	     else if (item.IsA('Shield') && (BodyPartHealth[BODYPART_LARM1] > 0) && (Shield == None))
00275	     {
00276	          return item.IsA('Shield');
00277	     }
00278	     return(false);
00279	}
00280	
00281	
00282	//============================================================
00283	//
00284	// PainSkin
00285	//
00286	// returns the pain skin for a given polygroup
00287	//============================================================
00288	function Texture PainSkin(int BodyPart)
00289	{
00290	     local Texture newpage;
00291	     local Texture oldpage;
00292	     
00293	     switch(BodyPart)
00294	     {
00295	          case BODYPART_TORSO:
00296	               oldpage = SkelGroupSkins[7];
00297	               if (oldpage == Texture'creatures.goblinbody')
00298	                    newpage = Texture'creatures.goblinpainbody';
00299	               else if (oldpage == Texture'creatures.goblinpaintedbody')
00300	                    newpage = Texture'creatures.goblinpainbodypainted1';
00301	               else if (oldpage == Texture'creatures.goblinpaintedbody2')
00302	                    newpage = Texture'creatures.goblinpainbodypainted2';
00303	               else if (oldpage == Texture'creatures.goblinpaintedbody3')
00304	                    newpage = Texture'creatures.goblinpainbodypainted3';
00305	               else
00306	                    newpage = oldpage;
00307	               SkelGroupSkins[7] = newpage;
00308	               break;
00309	          case BODYPART_HEAD:
00310	               oldpage = SkelGroupSkins[1];
00311	               if (oldpage == Texture'creatures.goblinhead')
00312	                    newpage = Texture'creatures.goblinpainhead';
00313	               else if (oldpage == Texture'creatures.goblinpaintedhead')
00314	                    newpage = Texture'creatures.goblinpainheadpainted';
00315	               else if (oldpage == Texture'creatures.goblinpaintedhead2')
00316	                    newpage = Texture'creatures.goblinpainheadpainted2';
00317	               else if (oldpage == Texture'creatures.goblinpaintedhead3')
00318	                    newpage = Texture'creatures.goblinpainheadpainted3';
00319	               else
00320	                    newpage = oldpage;
00321	               SkelGroupSkins[1] = newpage;
00322	               SkelGroupSkins[6] = newpage;
00323	               break;
00324	          case BODYPART_LARM1:
00325	               oldpage = SkelGroupSkins[2];
00326	               if (oldpage == Texture'creatures.goblinarmleg')
00327	                    newpage = Texture'creatures.goblinpainarmleg';
00328	               else if (oldpage == Texture'creatures.goblinpaintedarmleg')
00329	                    newpage = Texture'creatures.goblinpainarmlegpainted';
00330	               else
00331	                    newpage = oldpage;
00332	               SkelGroupSkins[2] = newpage;
00333	               SkelGroupSkins[8] = newpage;
00334	               break;
00335	          case BODYPART_RARM1:
00336	               oldpage = SkelGroupSkins[11];
00337	               if (oldpage == Texture'creatures.goblinarmleg')
00338	                    newpage = Texture'creatures.goblinpainarmleg';
00339	               else if (oldpage == Texture'creatures.goblinpaintedarmleg')
00340	                    newpage = Texture'creatures.goblinpainarmlegpainted';
00341	               else
00342	                    newpage = oldpage;
00343	               SkelGroupSkins[11] = newpage;
00344	               SkelGroupSkins[12] = newpage;
00345	               break;
00346	          case BODYPART_LLEG1:
00347	               oldpage = SkelGroupSkins[3];
00348	               if (oldpage == Texture'creatures.goblinarmleg')
00349	                    newpage = Texture'creatures.goblinpainarmleg';
00350	               else if (oldpage == Texture'creatures.goblinpaintedarmleg')
00351	                    newpage = Texture'creatures.goblinpainarmlegpainted';
00352	               else
00353	                    newpage = oldpage;
00354	               SkelGroupSkins[3] = newpage;
00355	               break;
00356	          case BODYPART_RLEG1:
00357	               oldpage = SkelGroupSkins[4];
00358	               if (oldpage == Texture'creatures.goblinarmleg')
00359	                    newpage = Texture'creatures.goblinpainarmleg';
00360	               else if (oldpage == Texture'creatures.goblinpaintedarmleg')
00361	                    newpage = Texture'creatures.goblinpainarmlegpainted';
00362	               else
00363	                    newpage = oldpage;
00364	               SkelGroupSkins[4] = newpage;
00365	               break;
00366	     }
00367	     return None;
00368	}
00369	
00370	
00371	//============================================================
00372	//
00373	// BodyPartForJoint
00374	//
00375	// Returns the body part a joint is associated with
00376	//============================================================
00377	function int BodyPartForJoint(int joint)
00378	{
00379	     switch(joint)
00380	     {
00381	          case 9:                              return BODYPART_LARM1;
00382	          case 15:                         return BODYPART_RARM1;
00383	          case 24:                         return BODYPART_RLEG1;
00384	          case 27:                         return BODYPART_LLEG1;
00385	          case 20:                         return BODYPART_HEAD;
00386	          case 1: case 4: case 5:          return BODYPART_TORSO;
00387	          default:                         return BODYPART_BODY;
00388	     }
00389	}
00390	
00391	//============================================================
00392	//
00393	// BodyPartForPolyGroup
00394	//
00395	//============================================================
00396	function int BodyPartForPolyGroup(int polygroup)
00397	{
00398	     switch(polygroup)
00399	     {
00400	          case 1: case 6:                              return BODYPART_HEAD;
00401	          case 2:                                        return BODYPART_LARM1;
00402	          case 12:                                   return BODYPART_RARM1;
00403	          case 3:                                        return BODYPART_LLEG1;
00404	          case 4:                                        return BODYPART_RLEG1;
00405	          case 5: case 7: case 8: case 9:
00406	               case 10: case 11:                    return BODYPART_TORSO;
00407	     }
00408	     return BODYPART_BODY;
00409	}
00410	
00411	//============================================================
00412	//
00413	// BodyPartSeverable
00414	//
00415	//============================================================
00416	function bool BodyPartSeverable(int BodyPart)
00417	{
00418	     switch(BodyPart)
00419	     {
00420	          case BODYPART_HEAD:
00421	          case BODYPART_LARM1:
00422	          case BODYPART_RARM1:
00423	               return true;
00424	     }
00425	     return false;
00426	}
00427	
00428	//============================================================
00429	//
00430	// BodyPartCritical
00431	//
00432	//============================================================
00433	function bool BodyPartCritical(int BodyPart)
00434	{
00435	     return (BodyPart == BODYPART_HEAD);
00436	}
00437	
00438	//============================================================
00439	//
00440	// ApplyGoreCap
00441	//
00442	//============================================================
00443	function ApplyGoreCap(int BodyPart)
00444	{
00445	     switch(BodyPart)
00446	     {
00447	          case BODYPART_LARM1:
00448	               SkelGroupSkins[9] = Texture'runefx.gore_bone';
00449	               SkelGroupFlags[9] = SkelGroupFlags[9] & ~POLYFLAG_INVISIBLE;
00450	               break;
00451	          case BODYPART_RARM1:
00452	               SkelGroupSkins[10] = Texture'runefx.gore_bone';
00453	               SkelGroupFlags[10] = SkelGroupFlags[10] & ~POLYFLAG_INVISIBLE;
00454	               break;
00455	          case BODYPART_HEAD:
00456	               SkelGroupSkins[5] = Texture'runefx.gore_bone';
00457	               SkelGroupFlags[5] = SkelGroupFlags[5] & ~POLYFLAG_INVISIBLE;
00458	               break;
00459	     }
00460	}
00461	
00462	//================================================
00463	//
00464	// SeveredLimbClass
00465	//
00466	//================================================
00467	function class<Actor> SeveredLimbClass(int BodyPart)
00468	{
00469	     switch(BodyPart)
00470	     {
00471	          case BODYPART_LARM1:
00472	               return class'GoblinLArm';
00473	          case BODYPART_RARM1:
00474	               return class'GoblinRArm';
00475	          case BODYPART_HEAD:
00476	               return class'GoblinHead';
00477	     }
00478	
00479	     return None;
00480	}
00481	
00482	
00483	//============================================================
00484	//
00485	// LimbSevered
00486	//
00487	//============================================================
00488	function LimbSevered(int BodyPart, vector Momentum)
00489	{
00490	     local int joint;
00491	     local actor part;
00492	     local vector X,Y,Z,pos;
00493	     local vector cameralocation;
00494	     local actor dummyactor;
00495	     local rotator camerarotation;
00496	     local class<actor> partclass;
00497	
00498	     Super.LimbSevered(BodyPart, Momentum);
00499	     
00500	     ApplyGoreCap(BodyPart);
00501	     partclass = SeveredLimbClass(BodyPart);
00502	
00503	     switch(BodyPart)
00504	     {
00505	          case BODYPART_LARM1:
00506	              //BroadcastMessage("Goblin_LeftArmSevered!",True);
00507	              //BroadcastMessage("BodyPartHealth:"$BodyPartHealth[BODYPART_LARM1],True);
00508	               joint = JointNamed('lshould');
00509	               pos = GetJointPos(joint);
00510	               GetAxes(Rotation, X, Y, Z);
00511	               part = Spawn(partclass,,, pos, Rotation);
00512	               if(part != None)
00513	               {
00514	                    part.Velocity = -Y * 100 + vect(0, 0, 175);
00515	                    part.GotoState('Drop');
00516	               }
00517	               part = Spawn(class'BloodSpurt', self,, pos, Rotation);
00518	               if(part != None)
00519	               {
00520	                    AttachActorToJoint(part, joint);
00521	               }
00522	               break;
00523	     
00524	          case BODYPART_RARM1:
00525	               joint = JointNamed('rshould');
00526	               pos = GetJointPos(joint);
00527	               GetAxes(Rotation, X, Y, Z);
00528	               part = Spawn(partclass,,, pos, Rotation);
00529	               if(part != None)
00530	               {
00531	                    part.Velocity = Y * 100 + vect(0, 0, 175);
00532	                    part.GotoState('Drop');
00533	               }
00534	               part = Spawn(class'BloodSpurt', self,, pos, Rotation);
00535	               if(part != None)
00536	               {
00537	                    AttachActorToJoint(part, joint);
00538	               }
00539	               break;
00540	          case BODYPART_HEAD:
00541	               joint = JointNamed('head');
00542	               pos = GetJointPos(joint);
00543	               part = Spawn(partclass,,, pos, Rotation);
00544	               if(part != None)
00545	               {
00546	/*
00547	                    if (Enemy != None && PlayerPawn(Enemy) != None && VSize(Enemy.Location-part.Location)<1000)
00548	                    {
00549	                         PlayerPawn(Enemy).PlayerCalcView(dummyactor, cameralocation, camerarotation);
00550	                         part.Velocity = CalcArcVelocity(8192, part.Location, cameralocation);
00551	                         part.Velocity *= 0.6;//testfloat;
00552	                    }
00553	                    else
00554	                    {
00555	                         part.Velocity = 0.75 * (momentum / Mass) + vect(0, 0, 300);
00556	                    }
00557	*/
00558	                    part.Velocity = 0.75 * (momentum / Mass) + vect(0, 0, 300);
00559	
00560	                    part.GotoState('Drop');
00561	                    part.SkelGroupSkins[4] = SkelGroupSkins[6]; // Set the Head texture properly
00562	               }
00563	               part = Spawn(class'BloodSpurt', self,, pos, Rotation);
00564	               if(part != None)
00565	               {
00566	                    AttachActorToJoint(part, joint);
00567	               }
00568	               break;
00569	     }
00570	}
00571	
00572	//===================================================================
00573	//
00574	// Bump
00575	//
00576	// If Pawns bump a destroyable decoration, they should smash it
00577	//===================================================================
00578	
00579	function Bump(Actor Other)
00580	{
00581	     if(Other.IsA('DecorationRune') && DecorationRune(Other).bDestroyable && Health>0)
00582	     {
00583	          if(Weapon == None)
00584	               PlayUninterruptedAnim('swipe');
00585	          else
00586	               PlayUninterruptedAnim('attackb');
00587	     }
00588	     else
00589	     {
00590	          Super.Bump(Other);
00591	     }
00592	}
00593	
00594	
00595	//============================================================
00596	// Animation functions
00597	//============================================================
00598	
00599	function PlayWaiting(optional float tween)
00600	{
00601	     if (BodyPartHealth[BODYPART_LARM1] <= 0 ^^
00602	          BodyPartHealth[BODYPART_RARM1] <= 0)
00603	     {
00604	          if (BodyPartHealth[BODYPART_LARM1]<=0)
00605	               LoopAnim  ('idleA_leftpain',  RandRange(0.8, 1.2), 0.1);
00606	          else
00607	               LoopAnim  ('idleA_rightpain', RandRange(0.8, 1.2), 0.1);
00608	     }
00609	     else if (Weapon==None)
00610	          LoopAnim  ('idleA',           RandRange(0.8, 1.2), 0.1);
00611	     else if (Weapon.IsA('Torch'))
00612	          LoopAnim  ('idleA_torch',     RandRange(0.8, 1.2), 0.1);
00613	     else
00614	          LoopAnim  ('w_idleA',         RandRange(0.8, 1.2), 0.1);
00615	}
00616	function PlayMoving(optional float tween)
00617	{
00618	     if (bHurrying)
00619	     {
00620	          if (Weapon==None)                              LoopAnim  ('w_gallopB',          1.0, tween);
00621	          else if (Weapon.IsA('Torch'))               LoopAnim  ('w_gallopB_torch', 1.0, tween);
00622	          else                                             LoopAnim  ('w_gallopB_weapon',1.0, tween);
00623	     }
00624	     else
00625	     {
00626	          if (Weapon==None)                              LoopAnim  ('walkB',               1.0, tween);
00627	          else                                             LoopAnim  ('walkB',               1.0, tween);
00628	     }
00629	}
00630	function PlayJumping(optional float tween)    { PlayAnim  ('jump',               1.0, tween);   }
00631	function PlayHuntStop(optional float tween)   { LoopAnim  ('w_idleA',          1.0, tween);   }
00632	function PlayMeleeHigh(optional float tween)
00633	{
00634	     if (Weapon==None)                                   PlayAnim  ('swipe',               1.0, tween);
00635	     else                                                  PlayAnim  ('attackb',          1.0, tween);
00636	}
00637	function PlayMeleeLow(optional float tween)
00638	{
00639	     if (Weapon==None)                                   PlayAnim  ('swipe',               1.0, tween);
00640	     else                                                  PlayAnim  ('attackb',          1.0, tween);
00641	}
00642	function PlayTurning(optional float tween)
00643	{
00644	     local int YawErr;
00645	     YawErr = Abs(DesiredRotation.Yaw - Rotation.Yaw);
00646	     //TODO: based on turn rate, turn amount, vary length of hop
00647	                                                            PlayAnim  ('hopA',               1.0, tween);
00648	}
00649	function PlayCower(optional float tween)      { LoopAnim  ('cower',               1.0, tween);   }
00650	function PlayThrowing(optional float tween)   { PlayAnim  ('throwA',          1.0, tween);   }
00651	//function PlayTaunting(optional float tween)   { PlayAnim  ('pain',               1.0, tween);   }
00652	function PlayTaunting(optional float tween)   { PlayAnim  ('flip2',               1.0, tween);   }
00653	
00654	function PlayInAir(optional float tween){
00655	  If (Frand()<0.5){
00656	     //LoopAnim  ('blockhigh',     1.0, tween);
00657	     LoopAnim  ('rollleft',     1.0, tween);
00658	  }else{
00659	    LoopAnim  ('rollright',     1.0, tween);
00660	
00661	  }
00662	}
00663	
00664	function PlayDodgeLeft(optional float tween)  { PlayAnim  ('rollleft',          1.0, tween);   }
00665	function PlayDodgeRight(optional float tween) { PlayAnim  ('rollright',          1.0, tween);   }
00666	function PlayDodgeForward(optional float tween){PlayAnim  ('hopA',               1.0, tween);   }
00667	function PlayDodgeBack(optional float tween)  { PlayAnim  ('dodgeback',          1.0, tween);   }
00668	function PlayDodgeBackflip(optional float tween){PlayAnim ('flip2',               1.0, tween);   }
00669	function PlayDodgeDuck(optional float tween)  { PlayAnim  ('duck',               1.0, tween);   }
00670	function PlayBlockHigh(optional float tween)  { LoopAnim  ('blocklow',          1.0, tween);   }
00671	function PlayBlockLow(optional float tween)   { LoopAnim  ('blocklow',          1.0, tween);   }
00672	
00673	function PlayFrontHit(float tween)            { PlayAnim  ('pain',               1.0, tween);   }
00674	function PlayDrowning(optional float tween)   { LoopAnim  ('drown',               1.0, tween);   }
00675	
00676	function PlayDeath(name DamageType)
00677	{
00678	     if (FRand()<0.5)
00679	                                                         PlayAnim('death',               1.0, 0.1);     
00680	     else
00681	                                                         PlayAnim('deathB',          1.0, 0.1);     
00682	}
00683	function PlayBackDeath(name DamageType)          { PlayAnim('deathS',          1.0, 0.1);     }
00684	function PlayLeftDeath(name DamageType)          { PlayAnim('deathR',          1.0, 0.1);     }
00685	function PlayRightDeath(name DamageType)     { PlayAnim('deathB',          1.0, 0.1);     }
00686	function PlayHeadDeath(name DamageType)          { PlayAnim('deathF',          1.0, 0.1);     }
00687	function PlaySkewerDeath(name DamageType)     { PlayAnim('death',               1.0, 0.1);     }
00688	function PlayDrownDeath(name DamageType)     { PlayAnim('drown_death',     1.0, 0.1);     }
00689	
00690	// Tween functions
00691	function TweenToWaiting(float time)
00692	{     if (BodyPartHealth[BODYPART_LARM1] <= 0 ^^
00693	          BodyPartHealth[BODYPART_RARM1] <= 0)
00694	     {     if (BodyPartHealth[BODYPART_LARM1]<=0)     TweenAnim ('idleA_leftpain',     time);
00695	          else                                             TweenAnim ('idleA_rightpain',     time);
00696	     }
00697	     else if (Weapon==None)                              TweenAnim ('idleA',                    time);
00698	     else if (Weapon.IsA('Torch'))                    TweenAnim ('idleA_torch',          time);
00699	     else                                                  TweenAnim ('w_idleA',               time);
00700	}
00701	function TweenToMoving(float time)
00702	{
00703	     if (bHurrying)
00704	     {
00705	          if (Weapon==None)                              TweenAnim ('w_gallopB',               time);
00706	          else if (Weapon.IsA('Torch'))               TweenAnim ('w_gallopB_torch',     time);
00707	          else                                             TweenAnim ('w_gallopB_weapon',     time);
00708	     }
00709	     else
00710	     {
00711	          if (Weapon==None)                              TweenAnim ('walkB',                    time);
00712	          else                                             TweenAnim ('walkB',                    time);
00713	     }
00714	}
00715	function TweenToTurning(float time)           {     TweenAnim ('hopA',                    time);     }
00716	function TweenToJumping(float time)           {     TweenAnim ('jump',                    time);     }
00717	function TweenToHuntStop(float time)          { TweenAnim ('w_idlaA',               time);     }
00718	function TweenToMeleeHigh(float time)
00719	{
00720	     if (Weapon==None)                                   TweenAnim ('swipe',                    time);
00721	     else                                                  TweenAnim ('attackb',               time);
00722	}
00723	function TweenToMeleeLow(float time)
00724	{
00725	     if (Weapon==None)                                   TweenAnim ('swipe',                    time);
00726	     else                                                  TweenAnim ('attackb',               time);
00727	}
00728	function TweenToThrowing(float time)          { TweenAnim ('throwA',               time);     }
00729	
00730	
00731	//------------------------------------------------
00732	//
00733	// Sound Functions
00734	//
00735	//------------------------------------------------
00736	function Breath()
00737	{
00738	     local int joint;
00739	     local vector l;
00740	     local actor A;
00741	
00742	     if (++breathcounter > 2)
00743	     {
00744	          breathcounter = 0;
00745	          OpenMouth(0.5, 0.5);
00746	
00747	          if (HeadRegion.Zone.bWaterZone)
00748	          {
00749	               // Spawn Bubbles
00750	               joint = JointNamed('jaw');
00751	               l = GetJointPos(joint);
00752	               if(FRand() < 0.3)
00753	               {
00754	                    Spawn(class'BubbleSystemOneShot',,, l,);
00755	               }
00756	          }
00757	          else
00758	          {
00759	               PlaySound(BreathSound, SLOT_Interface,,,, 1.0 + FRand()*0.2-0.1);
00760	          }
00761	     }
00762	     else
00763	     {
00764	          OpenMouth(0.0, 0.3);
00765	     }
00766	}
00767	
00768	
00769	//===================================================================
00770	//                         States
00771	//===================================================================
00772	State MineRocks
00773	{
00774	Begin:
00775	     LoopAnim('attackb', 1.0, 0.3);
00776	     Sleep(3);
00777	     FinishAnim();
00778	
00779	     TossWeapon();
00780	
00781	     OrderObject = NextPoint;
00782	     GotoState(NextState, NextLabel);
00783	}
00784	
00785	
00786	//============================================================
00787	//
00788	// MinRocksPartner1
00789	//
00790	//============================================================
00791	state MineRocksPartner1
00792	{
00793	     ignores SeePlayer, HearNoise, EnemyAcquired;
00794	
00795	Begin:
00796	Swing:
00797	     PlayAnim('attackb', 1.0, 0.2);
00798	     FinishAnim();
00799	     ReleaseTagged('miner2');
00800	WaitForPartner:
00801	     LoopAnim('w_idleA', 1.0, 0.2);
00802	     WaitForRelease();
00803	     FinishAnim();
00804	     goto('Swing');
00805	}
00806	
00807	
00808	//============================================================
00809	//
00810	// MineRocksPartner2
00811	//
00812	//============================================================
00813	state MineRocksPartner2
00814	{
00815	     ignores SeePlayer, HearNoise, EnemyAcquired;
00816	
00817	Begin:
00818	     Goto('WaitForPartner');
00819	Swing:
00820	     PlayAnim('attackb', 1.0, 0.2);
00821	     FinishAnim();
00822	     ReleaseTagged('miner1');
00823	WaitForPartner:
00824	     LoopAnim('w_idleA', 1.0, 0.2);
00825	     WaitForRelease();
00826	     FinishAnim();
00827	     goto('Swing');
00828	}
00829	
00830	
00831	//============================================================
00832	//
00833	// ThrowTest
00834	//
00835	//============================================================
00836	state ThrowTest
00837	{
00838	     function Timer()
00839	     {
00840	          if (DesiredMouthRot == 0)
00841	               OpenMouth(0.5, 0.5);
00842	          else
00843	               OpenMouth(0.0, 0.5);
00844	          SetTimer(0.5, false);
00845	     }
00846	
00847	     function SpawnRock()
00848	     {
00849	          local RockSmall rock;
00850	          rock = Spawn(class'RockSmall');
00851	          AttachActorToJoint(rock, JointNamed('weapon'));
00852	     }
00853	
00854	Begin:
00855	     PlayWaiting(0.2);
00856	     OpenMouth(1, 1.0);
00857	     Sleep(0.2);
00858	     SetTimer(0.2, false);
00859	     SpawnRock();
00860	     Sleep(5);
00861	     NextState = 'ThrowTest';
00862	     NextLabel = 'Begin';
00863	     OrderObject = ActorTagged('throwtarget');
00864	     GotoState('Throwing');
00865	}
00866	
00867	
00868	//============================================================
00869	//
00870	// AlertSquawk
00871	//
00872	//============================================================
00873	State AlertSquawk
00874	{
00875	Begin:
00876	     LookAt(Enemy);
00877	     SoundChance(AcquireSound, 1.0);
00878	     OpenMouth(1, 1);
00879	     Sleep(0.3);
00880	     OpenMouth(0, 1);
00881	     Sleep(2);
00882	     Goto('InformTeam');
00883	}
00884	
00885	State Excited
00886	{
00887	     function EnemyNotVisible()
00888	     {
00889	          GotoState('Startup', 'Restart');
00890	     }
00891	
00892	Begin:
00893	     if (Enemy == None)
00894	          Enemy = Pawn(OrderObject);
00895	
00896	     LookAt(Enemy);
00897	     PlayTurning();
00898	     TurnToward(Enemy);
00899	     FinishAnim();
00900	
00901	Jump:
00902	     if (FRand()<0.5)
00903	     {   BroadcastMessage("Excited_Jump",True);
00904	          PlayAnim('hopA', 1.0, 0.2);
00905	          AddVelocity(vect(0,0,200));
00906	          WaitForLanding();
00907	          FinishAnim();
00908	     }
00909	     else
00910	     {
00911	        BroadcastMessage("Excited_Flip",True);
00912	          TweenAnim('flip', 0.2);
00913	          FinishAnim();
00914	          PlayAnim('flip', 1.0);
00915	          Sleep(0.2);
00916	          AddVelocity(vect(0,0,500));
00917	          WaitForLanding();
00918	          FinishAnim();
00919	     }
00920	     if (FRand() < 0.8)
00921	          Goto('Jump');
00922	
00923	     PlayWaiting();
00924	     Sleep(RandRange(1.5, 4));
00925	     FinishAnim();
00926	     Goto('Jump');
00927	}
00928	
00929	//============================================================
00930	//
00931	// ThrowRocks
00932	//
00933	//============================================================
00934	State ThrowRocks
00935	{
00936	ignores SeePlayer, HearNoise, EnemyAcquired;
00937	
00938	     function EnemyNotVisible()
00939	     {
00940	          bAlerted = false;
00941	          OrderFinished();
00942	          GotoState('Startup', 'Restart');
00943	     }
00944	     
00945	     function SpawnRock()
00946	     {
00947	          local RockSmall rock;
00948	          rock = Spawn(class'RockSmall');
00949	          AttachActorToJoint(rock, JointNamed('weapon'));
00950	     }
00951	
00952	     function bool EnemyInRange(float range)
00953	     {
00954	          return VSize2D(Enemy.Location - Location) < range;
00955	     }
00956	     
00957	Begin:
00958	     PlayWaiting(0.2);
00959	
00960	     if (EnemyInRange(300))
00961	          GotoState('Acquisition');
00962	
00963	     if (Enemy == None || !EnemyInRange(1000))
00964	     {
00965	          Sleep(2);
00966	          Goto('Begin');
00967	     }
00968	     SpawnRock();
00969	     Sleep(3);
00970	     NextState = 'ThrowRocks';
00971	     NextLabel = 'Begin';
00972	     OrderObject = Enemy;
00973	     GotoState('Throwing');
00974	
00975	}
00976	
00977	
00978	//============================================================
00979	//
00980	// StayOnPaths
00981	//
00982	//============================================================
00983	State StayOnPaths
00984	{
00985	ignores SeePlayer, EnemyNotVisible, HearNoise;
00986	
00987	     function BeginState()
00988	     {
00989	          bHurrying = false;
00990	          UpdateMovementSpeed();
00991	     }
00992	
00993	     function EndState()
00994	     {
00995	          LookAt(None);
00996	     }
00997	
00998	     // Consider all destinations from OrderObject to stay close to enemy
00999	     function PickDestination()
01000	     {
01001	          local int numpaths, numpaths2, i, j;
01002	          local NavigationPoint dest, dest2, closest;
01003	          local float closestdist, dist;
01004	
01005	          if (NavigationPoint(CurrentPoint) != None)
01006	          {
01007	               numpaths = NavigationPoint(CurrentPoint).NumPaths();
01008	               closest = NavigationPoint(CurrentPoint);
01009	               closestdist = VSize(Enemy.Location - CurrentPoint.Location);
01010	               for (i=0; i<numpaths; i++)
01011	               {
01012	                    // Consider one step down the graph
01013	                    dest = NavigationPoint(NavigationPoint(CurrentPoint).PathEndPoint(i));
01014	                    if (dest != None)
01015	                    {
01016	                         dist = VSize(Enemy.Location - dest.Location);
01017	                         if (dist < closestdist)
01018	                         {
01019	                              closestdist = dist;
01020	                              closest = dest;
01021	                         }
01022	
01023	                         // Consider two steps down the graph
01024	                         numpaths2 = dest.NumPaths();
01025	                         for (j=0; j<numpaths2; j++)
01026	                         {
01027	                              dest2 = NavigationPoint(dest.PathEndPoint(j));
01028	                              if (dest2!=None)
01029	                              {
01030	                                   dist = VSize(Enemy.Location - dest2.Location);
01031	                                   if (dist < closestdist)
01032	                                   {
01033	                                        closestdist = dist;
01034	                                        closest = dest;
01035	                                   }
01036	                              }
01037	                         }
01038	                    }
01039	               }
01040	               OrderObject = closest;
01041	          }
01042	     }
01043	
01044	     function HitWall(vector norm, actor wall)
01045	     {
01046	//          slog("hit wall");
01047	     }
01048	     
01049	     function MayFall()
01050	     {
01051	//          slog("may fall");
01052	     }
01053	     
01054	Begin:
01055	     LookAt(Enemy);
01056	OrderObject = None;
01057	     // Stay on paths, staying as close to enemy as possible
01058	     if (OrderObject == None)
01059	          OrderObject = NearestNavPoint();
01060	     Goto('path');
01061	     
01062	     // OrderObject is my final destination
01063	     // MoveTarget is my next waypoint
01064	     
01065	Move:
01066	Path:
01067	//slog("orderobject="$OrderObject.name);
01068	     if (actorReachable(OrderObject))
01069	     {
01070	//     slog("..reachable - oo="$OrderObject);
01071	          PlayMoving(0.2);
01072	          MoveToward(OrderObject, MovementSpeed);
01073	          FinishAnim();
01074	          CurrentPoint = OrderObject;
01075	          Goto('Turn');
01076	     }
01077	     else if (FindBestPathToward(OrderObject))
01078	     {
01079	//     slog("..not reachable - path="$MoveTarget);
01080	          PlayMoving(0.1);
01081	          MoveToward(MoveTarget, MovementSpeed);
01082	          FinishAnim();
01083	          CurrentPoint = MoveTarget;
01084	          Goto('Path');
01085	     }
01086	     else
01087	     {
01088	//     slog("..not pathable - picking dest");
01089	          PickDestination();
01090	          if (CurrentPoint != OrderObject && OrderObject != None)
01091	          {
01092	               Sleep(0);
01093	               Goto('Move');
01094	          }
01095	          FinishAnim();
01096	          Acceleration = vect(0,0,0);
01097	          Goto('Wait');
01098	     }
01099	
01100	Turn:     
01101	     PlayTurning();
01102	     TurnToward(Enemy);
01103	     FinishAnim();
01104	     SoundChance(RoamSound, 1.0);
01105	
01106	Wait:
01107	     PlayWaiting();
01108	     Sleep(1);
01109	
01110	Check:
01111	     if (VSize(Enemy.Location-Location) < 4000)
01112	     {
01113	          OrderObject = Enemy.NearestNavPoint();
01114	          if (OrderObject != None && OrderObject != CurrentPoint)
01115	          {
01116	               Goto('Move');
01117	          }
01118	     }
01119	     
01120	     Sleep(2);
01121	     Goto('Check');
01122	}
01123	
01124	
01125	//================================================
01126	//
01127	// Charging
01128	//
01129	//================================================
01130	State Charging
01131	{
01132	ignores EnemyAcquired, SeePlayer, HearNoise;
01133	
01134	     // Inherits EndState()
01135	
01136	     function BeginState()
01137	     {
01138	          StopLookingToward();
01139	          LookAt(Enemy);
01140	          SetTimer(0.1, true);
01141	          bHurrying = true;
01142	          UpdateMovementSpeed();
01143	     }
01144	     
01145	
01146	     function MayFall()
01147	     {     // Only jump if reachable
01148	          bCanJump = ( (Enemy!=None) && actorReachable(Enemy) );
01149	     }
01150	
01151	     function Timer()
01152	     {
01153	          if (Enemy!=None && (Enemy.bSwingingHigh || Enemy.bSwingingLow) && InMeleeRange(Enemy))
01154	          {
01155	               GotoState('Fighting', 'CheckDefend');
01156	          }
01157	     }
01158	
01159	     function EnemyNotVisible()
01160	     {
01161	          GotoState('Hunting');
01162	     }
01163	     
01164	     function PickPaceDest()
01165	     {
01166	          local vector X,Y,Z;
01167	          local vector PaceVect;
01168	          
01169	          GetAxes(Enemy.Rotation, X, Y, Z);
01170	          PaceVect = Y * PaceRange * 0.3; // 1/3 the distance -- cjr
01171	          if (FRand() < 0.5)
01172	          {
01173	               Destination = Enemy.Location + PaceVect;
01174	          }
01175	          else
01176	          {
01177	               Destination = Enemy.Location - PaceVect;
01178	          }
01179	     }
01180	     
01181	     function HitWall(vector HitNormal, actor Wall)
01182	     {
01183	          if (Physics == PHYS_Falling)
01184	               return;
01185	               
01186	          //TODO: Test whether climbable, then set falling
01187	          if (bCanGrabEdges && bCanStrafe)
01188	          {
01189	               SetPhysics(PHYS_Falling);
01190	               return;
01191	          }
01192	          
01193	          if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) )
01194	          {
01195	               if ( SpecialPause > 0 )
01196	                    Acceleration = vect(0,0,0);
01197	               GotoState('Charging', 'SpecialNavig');
01198	               return;
01199	          }
01200	          Focus = Destination;
01201	          if (PickWallAdjust())
01202	               GotoState('Charging', 'AdjustFromWall');
01203	          else
01204	               MoveTimer = -1.0;
01205	     }
01206	     
01207	AdjustFromWall:
01208	     StrafeTo(Destination, Focus); 
01209	     Goto('CloseIn');
01210	
01211	ResumeCharge:
01212	     PlayMoving();
01213	     Goto('Charge');
01214	
01215	Begin:
01216	     if(debugstates) slog(name@"GoblinCharging");
01217	
01218	TweenIn:
01219	     TweenToMoving(0.15);
01220	     FinishAnim();
01221	     PlayMoving();
01222	
01223	Charge:
01224	     bFromWall = false;
01225	     
01226	CloseIn:
01227	     if ( JumpZ > 0 )          // This may have been set false in Mayfall, so reset
01228	          bCanJump = true;
01229	     if ( !ValidEnemy() )
01230	          GotoState('GoingHome');
01231	
01232	     if ( Enemy.Region.Zone.bWaterZone )
01233	     {     // Enemy entered water zone
01234	          if (!bCanSwim)
01235	               GotoState('TacticalDecision');
01236	     }
01237	     else if (!bCanFly && !bCanWalk)
01238	          // Enemy left water zone
01239	          GotoState('GoingHome');
01240	
01241	     if (Physics == PHYS_Falling)
01242	     {     // If falling, wait for land
01243	          if (NeedToTurn(Enemy.Location))
01244	          {
01245	               DesiredRotation = Rotator(Enemy.Location - Location);
01246	               Focus = Enemy.Location;
01247	               Destination = Enemy.Location;
01248	          }
01249	          WaitForLanding();
01250	     }
01251	
01252	Pace:
01253	     if( actorReachable(Enemy) )
01254	     {
01255	          if (bPaceAttack && FRand() < 0.75 && InPaceRange(Enemy))
01256	          {
01257	               PlayMoving(0.2);
01258	               PickPaceDest();
01259	               MoveTo(Destination, MovementSpeed);
01260	               PlayTurning(0.1);
01261	               TurnToward(Enemy);
01262	               SoundChance(PaceSound, 1.0);
01263	               FinishAnim();
01264	               PlayMoving(0.2);
01265	               if (FRand() < 0.5)
01266	               {     // Wait and continue pacing
01267	                    Acceleration = vect(0,0,0);
01268	                    SoundChance(ThreatenSound, 0.3);
01269	                    Goto('Pace');
01270	               }
01271	          }
01272	
01273	          if (bLungeAttack && FRand()<0.3 && InLungeRange(Enemy))
01274	          {
01275	               Goto('GotThere');
01276	          }
01277	          
01278	          SoundChance(ThreatenSound, 0.3);
01279	          MoveToward(Enemy, MovementSpeed);
01280	          if (bFromWall)
01281	          {
01282	               bFromWall = false;
01283	               if (PickWallAdjust())
01284	                    StrafeFacing(Destination, Enemy);
01285	               else
01286	                    GotoState('TacticalDecision');
01287	          }
01288	     }
01289	     else
01290	     {
01291	NoReach:
01292	          bCanSwing = false;
01293	          bFromWall = false;
01294	          if (!FindBestPathToward(Enemy))
01295	          {     // unreachable and unpathable
01296	               GotoState('Hunting');
01297	          }
01298	Moving:
01299	          if (VSize(MoveTarget.Location - Location) < 2.5 * CollisionRadius)
01300	          {
01301	               bCanSwing = true;
01302	               StrafeFacing(MoveTarget.Location, Enemy);
01303	          }
01304	          else
01305	          {
01306	               if ( !bCanStrafe || !LineOfSightTo(Enemy) ||
01307	                    (Skill - 2 * FRand() + (Normal(Enemy.Location - Location - vect(0,0,1) * (Enemy.Location.Z - Location.Z)) 
01308	                         Dot Normal(MoveTarget.Location - Location - vect(0,0,1) * (MoveTarget.Location.Z - Location.Z))) < 0) )
01309	               {
01310	                    MoveToward(MoveTarget, MovementSpeed);
01311	               }
01312	               else
01313	               {
01314	                    bCanSwing = true;
01315	                    StrafeFacing(MoveTarget.Location, Enemy);     
01316	               }
01317	               if ( !bFromWall )
01318	                    SoundChance(ThreatenSound, 0.8);
01319	          }
01320	     }
01321	
01322	CheckDistance:
01323	     if ( (bLungeAttack && !InLungeRange(Enemy)) || !InMeleeRange(Enemy))
01324	     {     // Lunge Attack
01325	          MoveTimer = 0.0;
01326	          bFromWall = false;
01327	          Goto('CloseIn');
01328	     }
01329	     Goto('GotThere');
01330	
01331	ResumeFromFighting:
01332	     if ( !ValidEnemy() )
01333	          GotoState('GoingHome');
01334	     if ( (bLungeAttack && !InLungeRange(Enemy)) || !InMeleeRange(Enemy))
01335	     {
01336	          MoveTimer = 0.0;
01337	          Goto('TweenIn');
01338	     }
01339	
01340	GotThere:
01341	     Target = Enemy;
01342	     GotoState('Fighting');
01343	}
01344	
01345	
01346	//================================================
01347	//
01348	// Fighting
01349	//
01350	//================================================
01351	State Fighting
01352	{
01353	ignores EnemyAcquired;
01354	
01355	     function BeginState()
01356	     {
01357	          LookAt(Enemy);
01358	          SetTimer(0.2, true);
01359	     }
01360	
01361	     function EndState()
01362	     {
01363	          bSwingingHigh = false;
01364	          bSwingingLow  = false;
01365	          if (Weapon!=None)
01366	          {
01367	               Weapon.FinishAttack();
01368	               SwipeEffectEnd();
01369	          }
01370	          LookAt(None);
01371	          SetTimer(0, false);
01372	     }
01373	
01374	     function AmbientSoundTimer()
01375	     {
01376	          PlayAmbientFightSound();
01377	     }
01378	
01379	     function bool BlockRatherThanDodge()
01380	     {
01381	          if (Shield == None)
01382	               return false;
01383	
01384	          if (EnemyIncidence != INC_FRONT)
01385	               return false;
01386	
01387	          return (FRand() < BlockChance);
01388	     }
01389	
01390	     function Timer()
01391	     {
01392	          if (Enemy != None && ShouldDefend())
01393	          {
01394	               GotoState('Fighting', 'Defend');
01395	          }
01396	     }
01397	
01398	     function bool ShouldDefend()
01399	     {
01400	          return (FRand() > FightOrDefend && InDangerFromAttack());
01401	     }
01402	     
01403	     function bool InDangerFromAttack()
01404	     {
01405	          if ((!Enemy.bSwingingHigh) && (!Enemy.bSwingingLow))
01406	               return false;
01407	
01408	          GetEnemyProximity();
01409	               
01410	          if (EnemyDist>CollisionRadius+Enemy.CollisionRadius+Enemy.MeleeRange)
01411	               return false;
01412	
01413	          return (EnemyVertical==VERT_LEVEL && EnemyFacing==FACE_FRONT);
01414	     }
01415	
01416	Begin:
01417	     if(debugstates) SLog(name@"GoblinFighting");
01418	     Acceleration = vect(0,0,0);
01419	     GetEnemyProximity();
01420	
01421	     // Turn to face enemy
01422	     DesiredRotation.Yaw = rotator(Enemy.Location-Location).Yaw;
01423	
01424	Fight:
01425	     // Decide high or low
01426	     if (FRand() < HighOrLow)
01427	     {
01428	          TweenToMeleeHigh(0.1);
01429	          bSwingingHigh = true;
01430	     }
01431	     else
01432	     {
01433	          TweenToMeleeLow(0.1);
01434	          bSwingingLow = true;
01435	     }
01436	     FinishAnim();
01437	
01438	     if (bLungeAttack && !InMeleeRange(Enemy))
01439	     {     // Lunge
01440	          AddVelocity( CalcArcVelocity(8000, Location, Enemy.Location) );
01441	     }
01442	
01443	     if (bSwingingHigh)
01444	          PlayMeleeHigh(0.1);
01445	     else
01446	          PlayMeleeLow(0.1);
01447	     FinishAnim();
01448	     bSwingingHigh = false;
01449	     bSwingingLow  = false;
01450	
01451	     Sleep(TimeBetweenAttacks);
01452	     
01453	     // Good chance of dodge back here (after attacking)
01454	     if (bDodgeAfterAttack)
01455	     {
01456	          if (FRand() < 0.5)
01457	               GotoState('DodgeBack');
01458	          else if (FRand() < 0.5)
01459	               GotoState('DodgeLeft');
01460	          else
01461	               GotoState('DodgeRight');
01462	     }
01463	
01464	     GotoState('Charging', 'ResumeFromFighting');
01465	
01466	CheckDefend:
01467	     Timer();
01468	     GotoState('Charging', 'ResumeFromFighting');
01469	
01470	Defend:
01471	     if (BlockRatherThanDodge())
01472	     {     // Try Block
01473	          Disable('Timer');
01474	          if (FRand() < HighOrLowBlock)
01475	          {     // Block High
01476	               ActivateShield(true);
01477	               PlayBlockHigh(0.1);
01478	               Sleep(RandRange(1, 2));
01479	               FinishAnim();
01480	               ActivateShield(false);
01481	          }
01482	          else
01483	          {     // Block Low
01484	               ActivateShield(true);
01485	               PlayBlockLow(0.1);
01486	               Sleep(RandRange(1, 2));
01487	               FinishAnim();
01488	               ActivateShield(false);
01489	          }
01490	          Enable('Timer');
01491	     }
01492	     else
01493	     {     // Try Dodge
01494	     
01495	          //TODO: handle above/below/level - high/low/vertical
01496	          
01497	          switch(EnemyIncidence)
01498	          {
01499	          case INC_RIGHT:
01500	               GotoState('DodgeLeft');
01501	               break;
01502	          case INC_LEFT:
01503	               if (FRand() < 0.5)
01504	                    GotoState('DodgeRight');
01505	               else
01506	                    GotoState('DodgeBack');
01507	               break;
01508	          case INC_FRONT:
01509	               if (FRand() < 0.5)
01510	                    GotoState('DodgeBackFlip');
01511	               else
01512	                    GotoState('DodgeBack');
01513	               break;
01514	          case INC_BACK:
01515	               if (FRand() < 0.5)
01516	                    GotoState('DodgeForward');
01517	               else if (FRand() < 0.5)
01518	                    GotoState('DodgeLeft');
01519	               else
01520	                    GotoState('DodgeRight');
01521	               break;
01522	          }
01523	     }
01524	
01525	BackFromSubState:
01526	     GotoState('Charging', 'ResumeFromFighting');
01527	}
01528	
01529	
01530	//================================================
01531	//
01532	// Fighting Sub-States
01533	//
01534	// Impliment in sub-classes
01535	//
01536	//================================================
01537	State DodgeForward
01538	{
01539	     ignores SeePlayer, HearNoise, EnemyAcquired;
01540	
01541	     function AmbientSoundTimer()
01542	     {
01543	          PlayAmbientFightSound();
01544	     }
01545	
01546	Begin:
01547	  BroadcastMessage("SarkBallBotGoblin_DodgeForward_Begin",True);
01548	     if(debugstates) SLog(name@"DodgeForward");
01549	     Acceleration = vect(0,0,0);
01550	     Velocity = vect(0,0,0);
01551	     PlayDodgeForward();
01552	     AddLocalVelocity(300, 0, 50);
01553	     FinishAnim();
01554	     WaitForLanding();
01555	     PlayLanded(Velocity.Z);
01556	
01557	     GotoState('Fighting', 'BackFromSubstate');
01558	}
01559	State DodgeBack
01560	{
01561	     ignores SeePlayer, HearNoise, EnemyAcquired;
01562	
01563	     function AmbientSoundTimer()
01564	     {
01565	          PlayAmbientFightSound();
01566	     }
01567	
01568	Begin:
01569	  BroadcastMessage("SarkBallBotGoblin_DodgeBack_Begin",True);
01570	     if(debugstates) SLog(name@"DodgeBack");
01571	     Acceleration = vect(0,0,0);
01572	     Velocity = vect(0,0,0);
01573	     PlayDodgeBack();
01574	     AddLocalVelocity(-200, 0, 50);
01575	     FinishAnim();
01576	     WaitForLanding();
01577	     PlayLanded(Velocity.Z);
01578	
01579	     GotoState('Fighting', 'BackFromSubstate');
01580	}
01581	State DodgeRight
01582	{
01583	     ignores SeePlayer, HearNoise, EnemyAcquired;
01584	     
01585	     function AmbientSoundTimer()
01586	     {
01587	          PlayAmbientFightSound();
01588	     }
01589	
01590	Begin:
01591	  BroadcastMessage("SarkBallBotGoblin_DodgeRight_Begin",True);
01592	     if(debugstates) SLog(name@"DodgeRight");
01593	     Acceleration = vect(0,0,0);
01594	     PlayDodgeRight();
01595	     AddLocalVelocity(0, 300, 100);
01596	     SoundChance(RollSound, 1.0);
01597	     FinishAnim();
01598	     WaitForLanding();
01599	     GotoState('Fighting', 'BackFromSubstate');
01600	}
01601	State DodgeLeft
01602	{
01603	     ignores SeePlayer, HearNoise, EnemyAcquired;
01604	     
01605	     function AmbientSoundTimer()
01606	     {
01607	          PlayAmbientFightSound();
01608	     }
01609	
01610	Begin:
01611	  BroadcastMessage("SarkBallBotGoblin_DodgeLeft_Begin",True);
01612	     if(debugstates) SLog(name@"DodgeLeft");
01613	     Acceleration = vect(0,0,0);
01614	     PlayDodgeLeft();
01615	     AddLocalVelocity(0, -300, 100);
01616	     SoundChance(RollSound, 1.0);
01617	     FinishAnim();
01618	     WaitForLanding();
01619	     GotoState('Fighting', 'BackFromSubstate');
01620	}
01621	State DodgeBackflip
01622	{
01623	     ignores SeePlayer, HearNoise, EnemyAcquired;
01624	     
01625	     function AmbientSoundTimer()
01626	     {
01627	          PlayAmbientFightSound();
01628	     }
01629	
01630	Begin:
01631	  BroadcastMessage("SarkBallBotGoblin_DodgeBackFlip_Begin",True);
01632	     if(debugstates) SLog(name@"DodgeBackflip");
01633	     Acceleration = vect(0,0,0);
01634	     Velocity = vect(0,0,0);
01635	     PlayDodgeBackFlip();
01636	
01637	     AddLocalVelocity(-200, 0, 400);
01638	     FinishAnim();
01639	     WaitForLanding();
01640	     PlayLanded(Velocity.Z);
01641	     
01642	     GotoState('Fighting', 'BackFromSubstate');
01643	}
01644	
01645	
01646	//===================================================================
01647	//                         Debug (temp)
01648	//===================================================================
01649	
01650	simulated function Debug(canvas Canvas, int mode)
01651	{
01652	     Super.Debug(Canvas, mode);
01653	
01654	     Canvas.DrawText("Goblin:");
01655	     Canvas.CurY -= 8;
01656	     Canvas.DrawText(" MoveTimer:"@MoveTimer);
01657	     Canvas.CurY -= 8;
01658	}
01659	
01660	defaultproperties
01661	{
01662	    fMaxGroundSpeedScale=1.50
01663	    bLungeAttack=True
01664	    FightOrFlight=0.99
01665	    FightOrDefend=0.50
01666	    HighOrLow=1.00
01667	    LatOrVertDodge=0.80
01668	    BlockChance=0.50
01669	    LungeRange=200.00
01670	    PaceRange=200.00
01671	    bDodgeAfterAttack=True
01672	    TimeBetweenAttacks=0.10
01673	    HuntTime=60.00
01674	    BreathSound=Sound'CreaturesSnd.Goblin.goblinbreath03'
01675	    AcquireSound=Sound'CreaturesSnd.Goblin.goblinamb04'
01676	    AmbientWaitSounds(0)=Sound'CreaturesSnd.Goblin.goblinbreath02'
01677	    AmbientWaitSounds(1)=Sound'CreaturesSnd.Goblin.goblinamb02'
01678	    AmbientWaitSounds(2)=Sound'CreaturesSnd.Goblin.goblinamb01'
01679	    AmbientFightSounds(0)=Sound'CreaturesSnd.Goblin.goblinattack17'
01680	    AmbientFightSounds(1)=Sound'CreaturesSnd.Goblin.goblinattack01'
01681	    AmbientFightSounds(2)=Sound'CreaturesSnd.Goblin.goblinattack18'
01682	    AmbientWaitSoundDelay=7.50
01683	    AmbientFightSoundDelay=5.00
01684	    StartWeapon=Class'SarkBallHandAxe'
01685	    StartShield=Class'RuneI.GoblinShield'
01686	    ShadowScale=1.00
01687	    A_PullUp=ClimbB
01688	    A_StepUp=ClimbC
01689	    MeleeRange=30.00
01690	    GroundSpeed=260.00
01691	    WaterSpeed=100.00
01692	    JumpZ=500.00
01693	    MaxStepHeight=50.00
01694	    WalkingSpeed=54.00
01695	    ClassID=5
01696	    Visibility=150
01697	    SightRadius=1500.00
01698	    PeripheralVision=-0.50
01699	    Health=50
01700	    BodyPartHealth(1)=35
01701	    BodyPartHealth(3)=35
01702	    BodyPartHealth(5)=40
01703	    UnderWaterTime=2.00
01704	    HitSound1=Sound'CreaturesSnd.Goblin.goblinhit08'
01705	    HitSound2=Sound'CreaturesSnd.Goblin.goblinhit16'
01706	    HitSound3=Sound'CreaturesSnd.Goblin.goblinhit28'
01707	    Die=Sound'CreaturesSnd.Goblin.goblindeath06'
01708	    Die2=Sound'CreaturesSnd.Goblin.goblindeath13'
01709	    Die3=Sound'CreaturesSnd.Goblin.goblindeath16'
01710	    LandGrunt=Sound'CreaturesSnd.Goblin.goblinhit32'
01711	    FootStepWood(0)=Sound'FootstepsSnd.Earth.footlandearth08'
01712	    FootStepWood(1)=Sound'FootstepsSnd.Earth.footlandearth08'
01713	    FootStepWood(2)=Sound'FootstepsSnd.Earth.footlandearth08'
01714	    FootStepMetal(0)=Sound'FootstepsSnd.Metal.footmetal07'
01715	    FootStepMetal(1)=Sound'FootstepsSnd.Metal.footmetal07'
01716	    FootStepMetal(2)=Sound'FootstepsSnd.Metal.footmetal07'
01717	    FootStepStone(0)=Sound'FootstepsSnd.Earth.footlandearth09'
01718	    FootStepStone(1)=Sound'FootstepsSnd.Earth.footlandearth09'
01719	    FootStepStone(2)=Sound'FootstepsSnd.Earth.footlandearth09'
01720	    FootStepFlesh(0)=Sound'FootstepsSnd.Earth.footlandearth09'
01721	    FootStepFlesh(1)=Sound'FootstepsSnd.Earth.footlandearth09'
01722	    FootStepFlesh(2)=Sound'FootstepsSnd.Earth.footlandearth09'
01723	    FootStepIce(0)=Sound'FootstepsSnd.Earth.footlandearth09'
01724	    FootStepIce(1)=Sound'FootstepsSnd.Earth.footlandearth09'
01725	    FootStepIce(2)=Sound'FootstepsSnd.Earth.footlandearth09'
01726	    FootStepEarth(0)=Sound'FootstepsSnd.Earth.footlandearth09'
01727	    FootStepEarth(1)=Sound'FootstepsSnd.Earth.footlandearth09'
01728	    FootStepEarth(2)=Sound'FootstepsSnd.Earth.footlandearth09'
01729	    FootStepSnow(0)=Sound'FootstepsSnd.Earth.footlandearth09'
01730	    FootStepSnow(1)=Sound'FootstepsSnd.Earth.footlandearth09'
01731	    FootStepSnow(2)=Sound'FootstepsSnd.Earth.footlandearth09'
01732	    WeaponJoint=Weapon
01733	    ShieldJoint=Shield
01734	    LookDegPerSec=720.00
01735	    MaxMouthRot=8192
01736	    MaxMouthRotRate=65535
01737	    DeathRadius=32.00
01738	    DeathHeight=6.00
01739	    AnimSequence=idleA
01740	    TransientSoundRadius=1000.00
01741	    CollisionRadius=16.00
01742	    CollisionHeight=32.00
01743	    Mass=50.00
01744	    Buoyancy=35.00
01745	    RotationRate=(Pitch=0,Yaw=45000,Roll=0)
01746	    SkelMesh=1
01747	    Skeletal=SkelModel'creatures.Goblin'
01748	}

End Source Code