RuneI
Class Viking

source: c:\runehov\RuneI\Classes\Viking.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Pawn
         |
         +--RuneI.ScriptPawn
            |
            +--RuneI.Viking
Direct Known Subclasses:Alric, Berserker, Conrack, DarkViking, DarkWarrior, Elder, Jarl, Karl, LokiGuard, ScriptableRagnar, ScriptableSarkRagnar, ScriptableTownRagnar, Sigurd, Sven, Ulf, Wolfgar

class Viking
extends RuneI.ScriptPawn

//============================================================================= // Viking. //=============================================================================
Variables
 name CrucifiedAnim
 string EnemyStr
 name PreUninterrupedState
 Weapon StowWeapon
 int breathcounter

States
Dying, Fighting, Startup

Function Summary
 eAttitude AttitudeToCreature(Pawn Other)
     
//------------------------------------------------
//
// AttitudeToCreature
//
//------------------------------------------------


State Dying Function Summary
 void Bump(Actor Other)
 void AttackBuddy()
     
{
	return(ATTITUDE_Hate);
}
*/
 eAttitude AttitudeToCreature(Pawn Other)
     
/*
 void BeginState()


State Fighting Function Summary
 bool BodyPartCritical(int BodyPart)
 void EndState()
 bool JointDamaged(int damage, Pawn EventInstigator, vector HitLoc, vector Momentum, name DamageType, int joint)
 bool CanGotoPainState()
 bool CanPickup(Inventory item)
 void BeginState()
     
//------------------------------------------------------------
//
// Crucified
//
//------------------------------------------------------------
 void CalcJumpVelocity()
 void CalcStrafePosition2()
 void CalcStrafePosition()
 bool InDangerFromAttack()
 bool ShouldDefend()
 void Timer()
     
// Determine AttackAction based upon enemy movement and position
 bool CheckStrafeRight()
 bool CheckStrafeLeft()
 bool BlockRatherThanDodge()
 void AmbientSoundTimer()
 void EndState()
 void BeginState()


State Startup Function Summary
 void DoStow()
     
//===================================================================
//
// DoStow
//
// DoStow Notify
//===================================================================
 void TweenToThrowing(float time)
 void TweenToMeleeLow(float time)
 void TweenToMeleeHigh(float time)
 void TweenToJumping(float time)
 void TweenToTurning(float time)
 void TweenToMoving(float time)
 void TweenToWaiting(float time)
     
// Tween functions
 void PlayBackDeath(name DamageType)
 void PlayDeath(name DamageType)
 void PlaySkewerDeath(name DamageType)
 void PlayRightHit(float tweentime)
 void PlayLeftHit(float tweentime)
 void PlayBackHit(float tweentime)
 void PlayFrontHit(float tweentime)
     
// Pains
 void PlayBlockLow(optional float)
 void PlayBlockHigh(optional float)
 void PlayInAir(optional float)
 void PlayTaunting(optional float)
 void PlayThrowing(optional float)
 void PlayTurning(optional float)
 void PlayMeleeLow(optional float)
 void PlayMeleeHigh(optional float)
 void PlayJumping(optional float)
 void PlayBackup(optional float)
     
//============================================================
//
// PlayBackup
//
//============================================================
 void PlayStrafeRight(optional float)
     
//============================================================
//
// PlayStrafeRight
//
//============================================================
 void PlayStrafeLeft(optional float)
     
//============================================================
//
// PlayStrafeLeft
//
//============================================================
 void PlayMoving(optional float)
     
//============================================================
//
// PlayMoving
//
//============================================================
 void PlayWaiting(optional float)
     
//============================================================
// Animation functions
//============================================================
 bool InCombatRange(Actor Other)
     
//============================================================
//
// InCombatRange
//
//============================================================
 bool CanPickup(Inventory item)
     
//============================================================
//
// CanPickup
//
// Let's pawn dictate what it can pick up
//============================================================
 void MakeTwitchable()
     
//------------------------------------------------------------
//
// MakeTwitchable
//
// TODO: Move to carcass
//------------------------------------------------------------
 void LimbSevered(int BodyPart, vector Momentum)
     
//================================================
//
// LimbSevered
//
//================================================
 void ApplyGoreCap(int BodyPart)
     
//============================================================
//
// ApplyGoreCap
//
//============================================================
 bool BodyPartCritical(int BodyPart)
     
//============================================================
//
// BodyPartCritical
//
//============================================================
 bool BodyPartSeverable(int BodyPart)
     
//============================================================
//
// BodyPartSeverable
//
//============================================================
 int BodyPartForPolyGroup(int polygroup)
     
//============================================================
//
// BodyPartForPolyGroup
//
//============================================================
 int BodyPartForJoint(int joint)
     
//============================================================
//
// BodyPartForJoint
//
// Returns the body part a joint is associated with
//============================================================
 void Breath()
     
//------------------------------------------------
//
// Breath
//
//------------------------------------------------
 void TouchSurroundingObjects()
     
//============================================================
 void SpawnStartInventory()
     
//============================================================



Source Code


00001	//=============================================================================
00002	// Viking.
00003	//=============================================================================
00004	class Viking expands ScriptPawn
00005		abstract;
00006	
00007	const DEFAULT_TWEEN = 0.15;
00008	
00009	var string EnemyStr;
00010	
00011	var Weapon StowWeapon;
00012	
00013	var(AI) class<Weapon>	StartStowWeapon;		// Startup stow weapon
00014	
00015	var(Sounds) sound		PaceSound;
00016	var private int breathcounter;
00017	
00018	var name PreUninterrupedState;
00019	
00020	var() name CrucifiedAnim;
00021	
00022	
00023	//------------------------------------------------
00024	//
00025	// AttitudeToCreature
00026	//
00027	//------------------------------------------------
00028	function eAttitude AttitudeToCreature(Pawn Other)
00029	{
00030		if (Other.IsA('Sark') || Other.IsA('Goblin'))
00031			return ATTITUDE_Hate;
00032		else
00033			return Super.AttitudeToCreature(Other);
00034	}
00035	
00036	auto State Startup
00037	{
00038		//============================================================
00039		//
00040		// SpawnStartInventory
00041		//
00042		//============================================================
00043		
00044		function SpawnStartInventory()
00045		{
00046			Super.SpawnStartInventory();
00047	
00048			bStopMoveIfCombatRange = true;
00049			
00050			if(StartStowWeapon != None && StartStowWeapon.Default.MeleeType != MELEE_NON_STOW)
00051			{
00052				if(StartWeapon != None)
00053				{
00054					if(StartWeapon.Default.MeleeType == StartStowWeapon.Default.MeleeType)
00055					{ // The start weapon and stow weapon are of the same class, don't spawn the stow weapon
00056						return;
00057					}
00058				}
00059				StowWeapon = Spawn(StartStowWeapon, self);
00060			}
00061		}
00062		
00063		//============================================================
00064		//
00065		// TouchSurroundingObjects
00066		//
00067		//============================================================
00068	
00069		function TouchSurroundingObjects()
00070		{
00071			if(StowWeapon != None)
00072			{
00073				AddInventory(StowWeapon);
00074	
00075				switch(StowWeapon.MeleeType)
00076				{
00077				case MELEE_SWORD:
00078					AttachActorToJoint(StowWeapon, JointNamed('attatch_sword'));
00079					break;
00080				case MELEE_AXE:
00081					AttachActorToJoint(StowWeapon, JointNamed('attach_axe'));
00082					break;
00083				case MELEE_AXE:
00084					AttachActorToJoint(StowWeapon, JointNamed('attach_hammer'));
00085					break;
00086				default:
00087					// Unknown or non-stow item
00088					StowWeapon.Destroy();
00089				}
00090	
00091				StowWeapon.GotoState('Stow');
00092			}
00093	
00094			Super.TouchSurroundingObjects();
00095		}
00096	}
00097	
00098	//------------------------------------------------
00099	//
00100	// Breath
00101	//
00102	//------------------------------------------------
00103	function Breath()
00104	{
00105		local int joint;
00106		local vector l;
00107	
00108		if (++breathcounter > 1)
00109		{
00110			breathcounter = 0;
00111			OpenMouth(0.5, 0.5);
00112	
00113			if (HeadRegion.Zone.bWaterZone)
00114			{
00115				// Spawn Bubbles
00116				joint = JointNamed('jaw');
00117				if (joint != 0)
00118				{
00119					l = GetJointPos(joint);
00120					if(FRand() < 0.3)
00121					{
00122						Spawn(class'BubbleSystemOneShot',,, l,);
00123					}
00124				}
00125			}
00126			else
00127			{
00128				PlaySound(BreathSound, SLOT_Interface,,,, 1.0 + FRand()*0.2-0.1);
00129			}
00130		}
00131		else
00132		{
00133			OpenMouth(0.0, 0.3);
00134		}
00135	}
00136	
00137	//============================================================
00138	//
00139	// BodyPartForJoint
00140	//
00141	// Returns the body part a joint is associated with
00142	//============================================================
00143	function int BodyPartForJoint(int joint)
00144	{
00145		switch(joint)
00146		{
00147			case 24:					return BODYPART_LARM1;
00148			case 31:					return BODYPART_RARM1;
00149			case 6:  case 7:			return BODYPART_RLEG1;
00150			case 2:  case 3:			return BODYPART_LLEG1;
00151			case 17:					return BODYPART_HEAD;
00152			case 11:					return BODYPART_TORSO;
00153			default:					return BODYPART_BODY;
00154		}
00155	}
00156	
00157	//============================================================
00158	//
00159	// BodyPartForPolyGroup
00160	//
00161	//============================================================
00162	function int BodyPartForPolyGroup(int polygroup)
00163	{
00164		return BODYPART_BODY;
00165	}
00166	
00167	//============================================================
00168	//
00169	// BodyPartSeverable
00170	//
00171	//============================================================
00172	function bool BodyPartSeverable(int BodyPart)
00173	{
00174		switch(BodyPart)
00175		{
00176			case BODYPART_HEAD:
00177			case BODYPART_LARM1:
00178			case BODYPART_RARM1:
00179				return true;
00180		}
00181		return false;
00182	}
00183	
00184	//============================================================
00185	//
00186	// BodyPartCritical
00187	//
00188	//============================================================
00189	function bool BodyPartCritical(int BodyPart)
00190	{
00191		return (BodyPart == BODYPART_HEAD);
00192	}
00193	
00194	//============================================================
00195	//
00196	// ApplyGoreCap
00197	//
00198	//============================================================
00199	function ApplyGoreCap(int BodyPart)
00200	{
00201	}
00202	
00203	//================================================
00204	//
00205	// LimbSevered
00206	//
00207	//================================================
00208	function LimbSevered(int BodyPart, vector Momentum)
00209	{
00210		local int joint;
00211		local vector X,Y,Z,pos;
00212		local actor part;
00213		local class<actor> partclass;
00214		
00215		Super.LimbSevered(BodyPart, Momentum);
00216	
00217		ApplyGoreCap(BodyPart);
00218		partclass = SeveredLimbClass(BodyPart);
00219	
00220		part = None;
00221		switch(BodyPart)
00222		{
00223			case BODYPART_HEAD:
00224				joint = JointNamed('head');
00225				pos = GetJointPos(joint);
00226				part = Spawn(partclass,,, pos, Rotation);
00227				if(part != None)
00228				{
00229					part.Velocity = 0.75 * (momentum / Mass) + vect(0, 0, 300);
00230					part.GotoState('Drop');
00231				}
00232				part = Spawn(class'BloodSpurt', self,, pos, Rotation);
00233				if(part != None)
00234				{
00235					AttachActorToJoint(part, joint);
00236				}
00237				break;
00238			case BODYPART_LARM1:
00239				joint = JointNamed('lshoulda');
00240				pos = GetJointPos(joint);
00241				part = Spawn(partclass,,, pos, Rotation);
00242				if(part != None)
00243				{
00244					part.Velocity = Y * 100 + vect(0, 0, 175);
00245					part.GotoState('Drop');
00246				}
00247				part = Spawn(class'BloodSpurt', self,, pos, Rotation);
00248				if(part != None)
00249				{
00250					AttachActorToJoint(part, joint);
00251				}
00252				break;
00253			case BODYPART_RARM1:
00254				joint = JointNamed('rshoulda');
00255				pos = GetJointPos(joint);
00256				part = Spawn(partclass,,, pos, Rotation);
00257				if(part != None)
00258				{
00259					part.Velocity = Y * 100 + vect(0, 0, 175);
00260					part.GotoState('Drop');
00261				}
00262				part = Spawn(class'BloodSpurt', self,, pos, Rotation);
00263				if(part != None)
00264				{
00265					AttachActorToJoint(part, joint);
00266				}
00267				break;
00268		}
00269	}
00270	
00271	//------------------------------------------------------------
00272	//
00273	// MakeTwitchable
00274	//
00275	// TODO: Move to carcass
00276	//------------------------------------------------------------
00277	function MakeTwitchable()
00278	{
00279		local int j;
00280	
00281		// Turn all collision joints accelerative
00282		for (j=0; j<NumJoints(); j++)
00283		{
00284			if ((JointFlags[j] & JOINT_FLAG_COLLISION)==0)
00285				continue;
00286	
00287			switch(j)
00288			{
00289				case 11: case 2: case 6:
00290					break;
00291				default:
00292					JointFlags[j] = JointFlags[j] | JOINT_FLAG_ACCELERATIVE;
00293	//				SetJointRotThreshold(j, 16000);
00294	//				SetJointDampFactor(j, 0.025);
00295	//				SetAccelMagnitude(j, 8000);
00296					break;
00297			}
00298		}
00299	}
00300	
00301	//============================================================
00302	//
00303	// CanPickup
00304	//
00305	// Let's pawn dictate what it can pick up
00306	//============================================================
00307	function bool CanPickup(Inventory item)
00308	{
00309		if (Health <= 0)
00310			return false;
00311	
00312		if (item.IsA('Weapon') && (BodyPartHealth[BODYPART_RARM1] > 0) && (Weapon == None))
00313		{
00314			return (item.IsA('axe') || item.IsA('hammer') || item.IsA('Sword') || item.IsA('Torch'));
00315		}
00316		else if (item.IsA('Shield') && (BodyPartHealth[BODYPART_LARM1] > 0) && (Shield == None))
00317		{
00318			return item.IsA('Shield');
00319		}
00320		return(false);
00321	}
00322	
00323	//============================================================
00324	//
00325	// InCombatRange
00326	//
00327	//============================================================
00328	
00329	function bool InCombatRange(Actor Other)
00330	{
00331		if(Other == None)
00332			return(false);
00333	
00334		return (VSize(Location - Other.Location) < CollisionRadius + Other.CollisionRadius + CombatRange);
00335	}
00336	
00337	//============================================================
00338	// Animation functions
00339	//============================================================
00340	
00341	function PlayWaiting(optional float tween)
00342	{
00343		if(Weapon != None)
00344		{
00345			LoopAnim(Weapon.A_Idle, RandRange(0.8, 1.2), 0.2);
00346		}
00347		else
00348		{
00349			LoopAnim('neutral_idle', RandRange(0.8, 1.2), 0.2);
00350		}
00351	}
00352	
00353	//============================================================
00354	//
00355	// PlayMoving
00356	//
00357	//============================================================
00358	
00359	function PlayMoving(optional float tween)
00360	{
00361		if (Weapon == None)
00362			LoopAnim('MOV_ALL_run1_AA0N', 1.0, DEFAULT_TWEEN);
00363		else									
00364			LoopAnim(Weapon.A_Forward, 1.0, DEFAULT_TWEEN);
00365	}
00366	
00367	//============================================================
00368	//
00369	// PlayStrafeLeft
00370	//
00371	//============================================================
00372	
00373	function PlayStrafeLeft(optional float tween)
00374	{
00375		if (Weapon == None)
00376			LoopAnim('MOV_ALL_lstrafe1_AN0N', 1.0, DEFAULT_TWEEN);
00377		else									
00378			LoopAnim(Weapon.A_StrafeLeft, 1.0, DEFAULT_TWEEN);
00379	}
00380	
00381	//============================================================
00382	//
00383	// PlayStrafeRight
00384	//
00385	//============================================================
00386	
00387	function PlayStrafeRight(optional float tween)
00388	{
00389		if (Weapon == None)
00390			LoopAnim('MOV_ALL_rstrafe1_AN0N', 1.0, DEFAULT_TWEEN);
00391		else									
00392			LoopAnim(Weapon.A_StrafeRight, 1.0, DEFAULT_TWEEN);
00393	}
00394	
00395	//============================================================
00396	//
00397	// PlayBackup
00398	//
00399	//============================================================
00400	
00401	function PlayBackup(optional float tween)
00402	{
00403		if (Weapon == None)
00404			LoopAnim('MOV_ALL_runback1_AA0S', 1.0, DEFAULT_TWEEN);
00405		else									
00406			LoopAnim(Weapon.A_Backward, 1.0, DEFAULT_TWEEN);
00407	}
00408	
00409	function PlayJumping(optional float tween)    { PlayAnim  ('MOV_ALL_jump1_AA0S',      1.0, tween);   }
00410	
00411	function PlayMeleeHigh(optional float tween)
00412	{
00413		if(Weapon != None)
00414		{
00415			PlayAnim(Weapon.A_AttackA, 1.0, tween);
00416		}
00417	}
00418	function PlayMeleeLow(optional float tween)
00419	{
00420		if(Weapon==None)							PlayAnim  ('swipe',     1.0, tween);
00421		else										PlayAnim  ('attackb',   1.0, tween);
00422	}
00423	
00424	function PlayTurning(optional float tween)
00425	{
00426		if(Weapon != None)
00427			LoopAnim(Weapon.A_Idle, 1.0, tween);
00428		else
00429			LoopAnim('neutral_idle', 1.0, tween);
00430	}
00431	
00432	function PlayThrowing(optional float tween)   { PlayAnim('throwA',    1.0, tween); }
00433	function PlayTaunting(optional float tween)   { PlayAnim('s3_taunt', 1.0, tween); }
00434	function PlayInAir(optional float tween) 
00435	{
00436		local name anim;
00437	
00438		if(Weapon != None && Weapon.A_Jump != '')
00439			anim = Weapon.A_Jump;
00440		else
00441			anim = 'MOV_ALL_jump1_AA0S';
00442		
00443		PlayAnim(anim, 1.0, 0.1);
00444	}
00445	
00446	function PlayBlockHigh(optional float tween)  { LoopAnim  ('blocklow',  1.0, tween);   }
00447	function PlayBlockLow(optional float tween)   { LoopAnim  ('blocklow',  1.0, tween);   }
00448	
00449	// Pains
00450	function PlayFrontHit(float tweentime)        
00451	{
00452		if(Weapon == None)
00453		{ // Neutral anims
00454			PlayAnim('n_painFront', 1.0, 0.1);
00455		}
00456		else
00457		{ // Weapon-specific
00458			PlayAnim(Weapon.A_PainFront, 1.0, 0.1);
00459		}
00460	}
00461	
00462	function PlayBackHit(float tweentime)
00463	{
00464		if(Weapon == None)
00465		{ // Neutral anims
00466			PlayAnim('n_painBack', 1.0, 0.1);
00467		}
00468		else
00469		{ // Weapon-specific
00470			PlayAnim(Weapon.A_PainBack, 1.0, 0.1);
00471		}
00472	}
00473	
00474	function PlayLeftHit(float tweentime)         { PlayAnim('S1_painLeft', 1.0, 0.08); }
00475	function PlayRightHit(float tweentime)         { PlayAnim('S1_painRight', 1.0, 0.08); }
00476	
00477	function PlaySkewerDeath(name DamageType)	  { PlayAnim  ('deathb', 1.0, DEFAULT_TWEEN);	}
00478	function PlayDeath(name DamageType)           
00479	{ 
00480		local name anim;
00481	
00482		if(DamageType == 'decapitated')
00483			PlayAnim('DeathH', 1.0, DEFAULT_TWEEN);
00484		if(DamageType == 'fire')
00485			PlayAnim('DeathF', 1.0, DEFAULT_TWEEN);
00486		else
00487		{ // Normal death, randomly choose one
00488			anim = 'DTH_ALL_death1_AN0N';
00489	
00490			switch(RandRange(0, 5))
00491			{
00492			case 0:
00493				anim = 'DTH_ALL_death1_AN0N';
00494				break;
00495			case 1:
00496				anim = 'DeathH';
00497				break;
00498			case 2:
00499				anim = 'DeathL';
00500				break;
00501			case 3:
00502				anim = 'DeathB';
00503				break;
00504			case 4:
00505				anim = 'DeathKnockback';
00506				break;
00507			default:
00508				anim = 'DTH_ALL_death1_AN0N';
00509				break;
00510			}
00511	
00512			PlayAnim(anim, 1.0, DEFAULT_TWEEN);
00513		}
00514	}
00515	
00516	function PlayBackDeath(name DamageType)		
00517	{
00518		local name anim;
00519	
00520		if(FRand() < 0.25)
00521			anim = 'DeathH';
00522		else
00523			anim  = 'DeathFront';
00524	
00525		PlayAnim(anim, 1.0, 0.1);
00526		if(AnimProxy != None)
00527			AnimProxy.PlayAnim(anim, 1.0, 0.1);	
00528	}
00529	
00530	// Tween functions
00531	function TweenToWaiting(float time)
00532	{
00533		if(Weapon != None)
00534			TweenAnim(Weapon.A_Idle, time);
00535		else
00536			LoopAnim('neutral_idle', time);
00537	}
00538	
00539	function TweenToMoving(float time)
00540	{
00541		if(Weapon != None)
00542			TweenAnim(Weapon.A_Forward, time);
00543		else									
00544			TweenAnim('MOV_ALL_run1_AA0N', time);
00545	}
00546	
00547	function TweenToTurning(float time)
00548	{ // TODO:  Need turning anims
00549		if(Weapon != None)
00550			TweenAnim(Weapon.A_Idle, time);
00551		else
00552			TweenAnim('neutral_idle', time);
00553	}
00554	
00555	function TweenToJumping(float time)           {	TweenAnim ('MOV_ALL_jump1_AA0S', time); }
00556	function TweenToMeleeHigh(float time)
00557	{
00558	/*
00559		if (Weapon==None)							TweenAnim ('swipe',     time);
00560		else										TweenAnim ('attackb',   time);
00561	*/
00562	}
00563	function TweenToMeleeLow(float time)
00564	{
00565	/*
00566		if (Weapon==None)							TweenAnim ('swipe',     time);
00567		else										TweenAnim ('attackb',   time);
00568	*/
00569	}
00570	function TweenToThrowing(float time)          { TweenAnim ('throwA',    time);         }
00571	
00572	
00573	//===================================================================
00574	//
00575	// DoStow
00576	//
00577	// DoStow Notify
00578	//===================================================================
00579	
00580	function DoStow()
00581	{
00582		if(Weapon != None && Weapon.MeleeType == MELEE_NON_STOW)
00583		{ // Drop the weapon
00584			DropWeapon();
00585			Weapon = None;
00586			return;
00587		}
00588	
00589		Weapon = StowWeapon;
00590		
00591		switch(Weapon.MeleeType)
00592		{
00593		case MELEE_SWORD:
00594			DetachActorFromJoint(JointNamed('attatch_sword'));
00595			break;
00596		case MELEE_AXE:
00597			DetachActorFromJoint(JointNamed('attach_axe'));
00598			break;
00599		case MELEE_AXE:
00600			DetachActorFromJoint(JointNamed('attach_hammer'));
00601			break;
00602		case MELEE_NON_STOW:
00603			DropWeapon();
00604			break;
00605		}
00606		
00607		AttachActorToJoint(Weapon, JointNamed(WeaponJoint));
00608		Weapon.GotoState('Active');
00609		StowWeapon = None;
00610	}
00611	
00612	//===================================================================
00613	//					States
00614	//===================================================================
00615	
00616	//================================================
00617	//
00618	// Fighting
00619	//
00620	//================================================
00621	State Fighting
00622	{
00623	ignores EnemyAcquired;
00624	
00625		function BeginState()
00626		{
00627			bAvoidLedges = true;
00628			LookAt(Enemy);
00629			SetTimer(0.1, true);
00630		}
00631	
00632		function EndState()
00633		{
00634			bAvoidLedges = false;
00635	
00636			bSwingingHigh = false;
00637			bSwingingLow  = false;
00638	
00639			if(Weapon != None)
00640			{
00641				Weapon.FinishAttack();
00642				Weapon.DisableSwipeTrail();
00643			}
00644	
00645			LookAt(None);
00646			SetTimer(0, false);
00647		}
00648		
00649		function AmbientSoundTimer()
00650		{
00651			PlayAmbientFightSound();
00652		}
00653	
00654		function bool BlockRatherThanDodge()
00655		{
00656			if (Shield == None)
00657				return false;
00658	
00659			if (EnemyIncidence != INC_FRONT)
00660				return false;
00661	
00662			return (FRand() < BlockChance);
00663		}
00664	
00665		function bool CheckStrafeLeft()
00666		{ // Checks if the left strafe move is valid (not going to strafe into a wall)
00667			local vector HitLocation, HitNormal;
00668			local vector extent, end;
00669	
00670			extent.X = CollisionRadius;
00671			extent.Y = CollisionRadius;
00672			extent.Z = CollisionHeight * 0.5;
00673	
00674			CalcStrafePosition();
00675	
00676			end = Normal(Destination - Location) * 75;
00677	
00678			if(Trace(HitLocation, HitNormal, end, Location, true, extent) == None)
00679				return(true); // Nothing in the way
00680			else
00681				return(false);
00682		}
00683	
00684		function bool CheckStrafeRight()
00685		{ // Checks if the right strafe move is valid (not going to strafe into a wall)
00686			local vector HitLocation, HitNormal;
00687			local vector extent, end;
00688	
00689			extent.X = CollisionRadius;
00690			extent.Y = CollisionRadius;
00691			extent.Z = CollisionHeight * 0.5;
00692	
00693			CalcStrafePosition2();
00694	
00695			end = Normal(Destination - Location) * 75;
00696	
00697			if(Trace(HitLocation, HitNormal, end, Location, true, extent) == None)
00698				return(true); // Nothing in the way
00699			else
00700				return(false);
00701		}
00702	
00703		// Determine AttackAction based upon enemy movement and position
00704		function Timer()
00705		{
00706			GetEnemyProximity();
00707	
00708			LastAction = AttackAction;
00709					
00710			if(EnemyMovement == MOVE_STRAFE_LEFT && FRand() < 0.8 && CheckStrafeLeft())
00711			{
00712				AttackAction = AA_STRAFE_LEFT;
00713			}
00714			else if(EnemyMovement == MOVE_STRAFE_RIGHT && FRand() < 0.8 && CheckStrafeRight())
00715			{
00716				AttackAction = AA_STRAFE_RIGHT;
00717			}
00718			else if((EnemyMovement == MOVE_STANDING && FRand() < 0.65) || FRand() < 0.2)
00719			{
00720				AttackAction = AA_LUNGE;
00721			}		
00722		 	else if(FRand() < 0.9)
00723		 	{
00724		 		if(FRand() < 0.5 && LastAction != AA_STRAFE_RIGHT || LastAction == AA_STRAFE_LEFT
00725					&& CheckStrafeLeft())
00726		 		{
00727		 			AttackAction = AA_STRAFE_LEFT;
00728		 		}
00729		 		else if(LastAction != AA_STRAFE_LEFT || LastAction == AA_STRAFE_RIGHT && CheckStrafeRight())
00730		 		{
00731		 			AttackAction = AA_STRAFE_RIGHT;
00732		 		}
00733				else
00734				{
00735					AttackAction = AA_WAIT;
00736				}
00737		 	}
00738			else
00739			{
00740				AttackAction = AA_WAIT;
00741			}
00742		}
00743	
00744		function bool ShouldDefend()
00745		{
00746			return (FRand() > FightOrDefend && InDangerFromAttack());
00747		}
00748		
00749		function bool InDangerFromAttack()
00750		{
00751			if ((!Enemy.bSwingingHigh) && (!Enemy.bSwingingLow))
00752				return false;
00753	
00754			GetEnemyProximity();
00755				
00756			if (EnemyDist>CollisionRadius+Enemy.CollisionRadius+Enemy.MeleeRange)
00757				return false;
00758	
00759			return (EnemyVertical==VERT_LEVEL && EnemyFacing==FACE_FRONT);
00760		}
00761	
00762		function CalcStrafePosition()
00763		{		
00764			local vector V;
00765			local rotator R;
00766			local vector temp;
00767			
00768			if(Enemy == None)
00769			{
00770				Destination = Location;
00771				return;
00772			}
00773	
00774			V = Location - Enemy.Location;
00775			R = rotator(V);
00776			
00777			R.Yaw += 2000;
00778	
00779			// Strafe using the enemy's XY location, but the viking's location ground plane		
00780			temp = Enemy.Location;
00781			temp.Z = Location.Z;
00782	
00783			Destination = temp + vector(R) * CombatRange;
00784		}
00785		
00786		function CalcStrafePosition2()
00787		{		
00788			local vector V;
00789			local rotator R;
00790			local vector temp;
00791	
00792			if(Enemy == None)
00793			{
00794				Destination = Location;
00795				return;
00796			}
00797			
00798			V = Location - Enemy.Location;
00799			R = rotator(V);
00800			
00801			R.Yaw -= 2000;
00802	
00803			// Strafe using the enemy's XY location, but the viking's location ground plane		
00804			temp = Enemy.Location;
00805			temp.Z = Location.Z;
00806	
00807			Destination = temp + vector(R) * CombatRange;
00808		}
00809	
00810		function CalcJumpVelocity()
00811		{
00812			local float traj;
00813			local vector adjust;
00814	
00815			traj = (70 + Rand(5)) * 65536 / 360;
00816			adjust = Enemy.Location - Location; // Random adjustment to compensate for perfect accuracy
00817			AddVelocity(CalcArcVelocity(traj, Location, Enemy.Location + adjust));
00818		}
00819			
00820	Begin:
00821		if(Enemy == None)
00822			Goto('BackFromSubState');
00823	
00824		Acceleration = vect(0,0,0);
00825	
00826		// Turn to face enemy
00827		DesiredRotation.Yaw = rotator(Enemy.Location-Location).Yaw;
00828	
00829		if(Weapon != None && Weapon.MeleeType == MELEE_NON_STOW && StowWeapon != None)
00830		{ // The creature is carrying a non-stow (probably a torch), but 
00831			// has a weapon stowed, ditch the non-stow in favor of the stowed weapon
00832			PlayAnim('IDL_ALL_drop1_AA0S', 1.0, DEFAULT_TWEEN);
00833			FinishAnim();
00834		}
00835	
00836		// If the creature has a weapon stowed, unsheath it before attacking
00837		if(Weapon == None && StowWeapon != None)
00838		{ // Unsheath the stow weapon
00839			switch(StowWeapon.MeleeType)
00840			{
00841			case MELEE_SWORD:
00842				PlayAnim('IDL_ALL_sstow1_AA0S', 1.0, DEFAULT_TWEEN);
00843				break;
00844			case MELEE_AXE:
00845				PlayAnim('IDL_ALL_xstow1_AA0S', 1.0, DEFAULT_TWEEN);
00846				break;
00847			case MELEE_HAMMER:
00848				PlayAnim('IDL_ALL_hstow1_AA0S', 1.0, DEFAULT_TWEEN);
00849				break;
00850			}
00851			
00852			FinishAnim();	
00853		}
00854	
00855	//	PlayWaiting();
00856	
00857	Fight:
00858		if(!ValidEnemy())
00859			Goto('BackFromSubState');
00860	
00861		GetEnemyProximity();
00862		
00863		// Attack if close enough
00864		if(Weapon != None && (InMeleeRange(Enemy) || (EnemyMovement == MOVE_CLOSER && EnemyDist < MeleeRange * 2.5)))
00865		{
00866			if(LastAction != AA_LUNGE && FRand() < 0.2)
00867			{ // Random chance that the creature will dodge
00868				PlayMoving();
00869				if(FRand() < 0.7)
00870				{ // Either jump to the side, or back up
00871					// Back up
00872					bStopMoveIfCombatRange = false;
00873					ActivateShield(true);
00874					PlayBackup();
00875					StrafeFacing(Location - vector(Rotation) * (CombatRange - EnemyDist), Enemy);
00876					ActivateShield(false);
00877					bStopMoveIfCombatRange = true;
00878				}
00879				else
00880				{ // Dodge to the side
00881					bStopMoveIfCombatRange = false;
00882					ActivateShield(true);
00883					PlayStrafeRight();
00884					StrafeFacing(Location + vector(Rotation + rot(0, 16384, 0)) * CombatRange, Enemy);
00885					ActivateShield(false);
00886					bStopMoveIfCombatRange = true;				
00887				}
00888			}		
00889			else
00890			{
00891				WeaponActivate();
00892				Weapon.EnableSwipeTrail();
00893	
00894				PlayAnim(Weapon.A_AttackStandA, 1.0, 0.1);
00895				FinishAnim();
00896	
00897				if(Weapon.A_AttackStandB != 'None' && FRand() < 0.5)
00898				{
00899					ClearSwipeArray();
00900					PlayAnim(Weapon.A_AttackStandB, 1.0, 0.01);
00901					if(Enemy != None)
00902						TurnToward(Enemy);
00903					FinishAnim();
00904	
00905					// B-Return
00906					WeaponDeactivate();
00907	
00908					if(Weapon.A_AttackStandBReturn != 'None')
00909					{
00910						PlayAnim(Weapon.A_AttackStandBReturn, 1.0, 0.1);
00911						FinishAnim();
00912					}
00913				}
00914				else
00915				{ // A-Return
00916					WeaponDeactivate();
00917	
00918					if(Weapon.A_AttackStandAReturn != 'None')
00919					{
00920						PlayAnim(Weapon.A_AttackStandAReturn, 1.0, 0.1);
00921						FinishAnim();
00922					}
00923				}
00924	
00925				Weapon.DisableSwipeTrail();
00926			}
00927			
00928			Sleep(TimeBetweenAttacks);
00929		}
00930		else if(AttackAction == AA_LUNGE)
00931		{ // Random lunge
00932			PlayMoving();
00933			bStopMoveIfCombatRange = false;
00934			MoveTo(Enemy.Location - VecToEnemy * MeleeRange, MovementSpeed);
00935			bStopMoveIfCombatRange = true;
00936		}
00937		else if(AttackAction == AA_STRAFE_LEFT)
00938		{ // Strafe - Destination is calculated from Timer, when the strafe is initial decided upon
00939			PlayStrafeLeft();
00940			bStopMoveIfCombatRange = false;
00941			StrafeFacing(Destination, Enemy);
00942			bStopMoveIfCombatRange = true;
00943		}
00944		else if(AttackAction == AA_STRAFE_RIGHT)
00945		{ // Strafe - Destination is calculated from Timer, when the strafe is initial decided upon
00946			PlayStrafeRight();
00947			bStopMoveIfCombatRange = false;
00948			StrafeFacing(Destination, Enemy);
00949			bStopMoveIfCombatRange = true;
00950		}
00951		else if(AttackAction == AA_JUMP)
00952		{
00953			PlayJumping();
00954			CalcJumpVelocity();
00955			WaitForLanding();
00956			FinishAnim();		
00957		}
00958		else
00959		{
00960			PlayWaiting();
00961		}
00962	
00963		if(InCombatRange(Enemy))
00964		{
00965			Sleep(0.05);
00966			Goto('Begin');
00967		}
00968		
00969	BackFromSubState:
00970		GotoState('Charging', 'ResumeFromFighting');
00971	}
00972	
00973	//------------------------------------------------------------
00974	//
00975	// Crucified
00976	//
00977	//------------------------------------------------------------
00978	state() Crucified
00979	{
00980	ignores AddVelocity;
00981	
00982		function BeginState()
00983		{
00984			SetPhysics(PHYS_None);
00985		}
00986	
00987		function bool CanPickup(Inventory item)
00988		{
00989			return false;
00990		}
00991	
00992		function bool CanGotoPainState()
00993		{
00994			return(false);
00995		}
00996	
00997		function bool JointDamaged(int damage, pawn EventInstigator, vector HitLoc, vector Momentum, name DamageType, int joint)
00998		{
00999			if (Health > 10)
01000			{	// Concious
01001				Health -= damage;
01002				GotoState('Crucified', 'InPain');
01003			}
01004			else
01005			{	// Unconcious
01006				Health -= damage;
01007				if (Health <= 0)
01008				{
01009					Health = 1;	// Insure can be killed by final blow so death event fires
01010					if (damage > 10)
01011					{	// Only a big final blow will gib
01012						return Super.JointDamaged(1000, EventInstigator, HitLoc, Momentum, 'gibbed', 0);
01013					}
01014					else
01015					{
01016						return true;
01017					}
01018				}
01019			}
01020	
01021			return false;
01022		}
01023	
01024		function EndState()
01025		{
01026			SetMovementPhysics();
01027		}
01028	
01029		function bool BodyPartCritical(int BodyPart)
01030		{	// Don't flee when arm cut off, die
01031			return true;
01032		}
01033	
01034	InPain:
01035		switch(CrucifiedAnim)
01036		{
01037			case 'CrucifiedAIdle':
01038				PlayAnim('CrucifiedAPain', 1.0, 0.1);
01039				FinishAnim();
01040				break;
01041			case 'CrucifiedBIdle':
01042				PlayAnim('CrucifiedBPain', 1.0, 0.1);
01043				FinishAnim();
01044				break;
01045			case 'CrucifiedC':
01046				break;
01047		}
01048		if (Health > 10)
01049			Goto('Concious');
01050	
01051	Unconcious:
01052		switch(CrucifiedAnim)
01053		{
01054			case 'CrucifiedAIdle':
01055				PlayAnim('CrucifiedA', 1.0, 0.4);
01056				break;
01057			case 'CrucifiedBIdle':
01058				PlayAnim('CrucifiedB', 1.0, 0.4);
01059				break;
01060			case 'CrucifiedC':
01061				break;
01062		}
01063		Goto('Idle');
01064	
01065	Begin:
01066	Concious:
01067		LoopAnim(CrucifiedAnim, 1.0, 0.1);
01068	
01069	Idle:
01070	}
01071	
01072	
01073	//================================================
01074	//
01075	// Dying
01076	//
01077	//================================================
01078	
01079	state Dying
01080	{
01081		function BeginState()
01082		{
01083			local int joint;
01084			local vector X, Y, Z;
01085	
01086			// Drop any stowed weapons
01087			if(StowWeapon != None)
01088			{		
01089				switch(StowWeapon.MeleeType)
01090				{
01091				case MELEE_SWORD:
01092					joint = JointNamed('attatch_sword');
01093					break;
01094				case MELEE_AXE:
01095					joint = JointNamed('attach_axe');
01096					break;
01097				case MELEE_AXE:
01098					joint = JointNamed('attach_hammer');
01099					break;
01100				default:
01101					// Unknown or non-stow item
01102					return;
01103				}
01104	
01105				DetachActorFromJoint(joint);
01106					
01107				GetAxes(Rotation, X, Y, Z);
01108				StowWeapon.DropFrom(GetJointPos(joint));
01109			
01110				StowWeapon.SetPhysics(PHYS_Falling);
01111				StowWeapon.Velocity = Y * 100 + X * 75;
01112				StowWeapon.Velocity.Z = 50;
01113				
01114				StowWeapon.GotoState('Drop');
01115				StowWeapon.DisableSwipeTrail();
01116	
01117				StowWeapon = None; // Remove the StowWeapon from the actor
01118			}
01119	
01120			Super.BeginState();
01121		}
01122	}
01123	
01124	/*
01125	function eAttitude AttitudeToCreature(Pawn Other)
01126	{
01127		return(ATTITUDE_Hate);
01128	}
01129	*/
01130	
01131	function AttackBuddy()
01132	{
01133		local Pawn V;
01134		
01135		foreach AllActors(class'Pawn', V)
01136		{
01137			if(V != self && V.Health > 0 && !V.IsA('PlayerPawn'))
01138			{
01139				SetEnemy(V);
01140				return;
01141			}
01142		}
01143	}
01144	
01145	function Bump(Actor Other)
01146	{
01147		if(Other.IsA('Keg') || Other.IsA('Stool') || Other.IsA('Bucket'))
01148		{ // Vikings will smash kegs that are in the way
01149			UseActor = Other;
01150	
01151			if(Other.Location.Z < Location.Z || Weapon == None)
01152			{
01153				PlayUninterruptedAnim(UseActor.GetUseAnim());
01154			}
01155		}
01156	/*
01157		else if(Other.IsA('DecorationRune') && DecorationRune(Other).bDestroyable && Weapon != None)
01158		{ // Other things that the viking should just swipe at
01159			Weapon.StartAttack();
01160			Weapon.EnableSwipeTrail();
01161			PlayUninterruptedAnim(Weapon.A_AttackA);
01162		}
01163	*/
01164		else
01165		{
01166			Super.Bump(Other);
01167		}
01168	}
01169	
01170	simulated function Debug(Canvas canvas, int mode)
01171	{
01172		local vector offset;
01173		
01174		Super.Debug(canvas, mode);
01175		
01176		Canvas.DrawText("	DarkViking:");
01177		Canvas.CurY -= 8;
01178		Canvas.DrawText("	PreUninterrupt: " $ PreUninterrupedState);
01179		Canvas.CurY -= 8;
01180		Canvas.DrawText("	NextOrder/Tag: " $ NextState@NextLabel);
01181		Canvas.CurY -= 8;
01182		Canvas.DrawText("	Enemy String: " $ EnemyStr);
01183		EnemyStr = "None";
01184	
01185		Canvas.CurY -= 8;
01186		if(EnemyFacing == FACE_FRONT)
01187		{
01188			Canvas.DrawText("	Enemy Facing:  FRONT");		
01189		}
01190		else if(EnemyFacing == FACE_BACK)
01191		{
01192			Canvas.DrawText("	Enemy Facing:  BACK");		
01193		}
01194		else
01195		{
01196			Canvas.DrawText("	Enemy Facing:  SIDE");		
01197		}
01198		
01199		Canvas.CurY -= 8;
01200		if(EnemyVertical == VERT_ABOVE)
01201		{
01202			Canvas.DrawText("	Enemy Vertical:  ABOVE");		
01203		}
01204		else if(EnemyVertical == VERT_BELOW)
01205		{
01206			Canvas.DrawText("	Enemy Vertical:  BELOW");		
01207		}
01208		else
01209		{
01210			Canvas.DrawText("	Enemy Vertical:  LEVEL");		
01211		}
01212	
01213		Canvas.CurY -= 8;
01214		if(EnemyMovement == MOVE_CLOSER)
01215		{
01216			Canvas.DrawText("	Enemy Movement:  CLOSER");		
01217		}
01218		else if(EnemyMovement == MOVE_FARTHER)
01219		{
01220			Canvas.DrawText("	Enemy Movement:  FARTHER");		
01221		}
01222		else if(EnemyMovement == MOVE_STRAFE_LEFT)
01223		{
01224			Canvas.DrawText("	Enemy Movement:  STRAFE_LEFT");		
01225		}
01226		else if(EnemyMovement == MOVE_STRAFE_RIGHT)
01227		{
01228			Canvas.DrawText("	Enemy Movement:  STRAFE_RIGHT");		
01229		}
01230		else
01231		{
01232			Canvas.DrawText("	Enemy Movement:  STANDING");				
01233		}
01234		
01235		Canvas.CurY -= 8;
01236		Canvas.DrawText("   AttackAction:  " $ AttackAction);
01237		
01238		offset = Destination;
01239		Canvas.DrawLine3D(offset + vect(10, 0, 0), offset + vect(-10, 0, 0), 255, 0, 0);
01240		Canvas.DrawLine3D(offset + vect(0, 10, 0), offset + vect(0, -10, 0), 255, 0, 0);	
01241		Canvas.DrawLine3D(offset + vect(0, 0, 10), offset+ vect(0, 0, -10), 255, 0, 0);
01242	
01243	}
01244	
01245	defaultproperties
01246	{
01247	     StartStowWeapon=Class'RuneI.VikingBroadSword'
01248	     CrucifiedAnim=CrucifiedAidle
01249	     FightOrFlight=1.000000
01250	     FightOrDefend=1.000000
01251	     HighOrLow=0.500000
01252	     HighOrLowBlock=0.500000
01253	     BlockChance=1.000000
01254	     LungeRange=100.000000
01255	     PaceRange=100.000000
01256	     TimeBetweenAttacks=0.100000
01257	     StartShield=Class'RuneI.DarkShield'
01258	     ShadowScale=1.500000
01259	     A_PullUp=intropullupA
01260	     A_StepUp=pullupTest
01261	     CarcassType=Class'RuneI.CarcassDarkViking'
01262	     bCanStrafe=True
01263	     bCanGrabEdges=True
01264	     MeleeRange=60.000000
01265	     CombatRange=180.000000
01266	     GroundSpeed=200.000000
01267	     AccelRate=1000.000000
01268	     JumpZ=425.000000
01269	     MaxStepHeight=30.000000
01270	     AirControl=0.100000
01271	     WalkingSpeed=200.000000
01272	     ClassID=8
01273	     BodyPartHealth(1)=90
01274	     BodyPartHealth(3)=90
01275	     BodyPartHealth(5)=80
01276	     Intelligence=BRAINS_HUMAN
01277	     FootStepMetal(0)=Sound'FootstepsSnd.Metal.footmetal10'
01278	     FootStepMetal(1)=Sound'FootstepsSnd.Metal.footmetal11'
01279	     FootStepMetal(2)=Sound'FootstepsSnd.Metal.footmetal12'
01280	     FootStepStone(0)=Sound'FootstepsSnd.Earth.footgravel13'
01281	     FootStepStone(1)=Sound'FootstepsSnd.Earth.footgravel12'
01282	     FootStepStone(2)=Sound'FootstepsSnd.Earth.footgravel13'
01283	     FootStepIce(0)=Sound'FootstepsSnd.Ice.footice04'
01284	     FootStepIce(1)=Sound'FootstepsSnd.Ice.footice05'
01285	     FootStepIce(2)=Sound'FootstepsSnd.Ice.footice06'
01286	     FootStepEarth(0)=Sound'FootstepsSnd.Earth.footgravel03'
01287	     FootStepEarth(1)=Sound'FootstepsSnd.Earth.footgravel05'
01288	     FootStepEarth(2)=Sound'FootstepsSnd.Earth.footgravel06'
01289	     FootStepSnow(0)=Sound'FootstepsSnd.Snow.footsnow10'
01290	     FootStepSnow(1)=Sound'FootstepsSnd.Snow.footsnow11'
01291	     FootStepSnow(2)=Sound'FootstepsSnd.Snow.footsnow12'
01292	     WeaponJoint=attach_hand
01293	     ShieldJoint=attach_shielda
01294	     StabJoint=spineb
01295	     bCanLook=True
01296	     bHeadLookUpDouble=True
01297	     LFootJoint=5
01298	     RFootJoint=9
01299	     bLeadEnemy=True
01300	     CollisionRadius=24.000000
01301	     CollisionHeight=46.000000
01302	     Buoyancy=400.000000
01303	     RotationRate=(Pitch=0,Roll=0)
01304	     SkelMesh=2
01305	     Skeletal=SkelModel'Players.Ragnar'
01306	}

End Source Code