Engine
Class Weapon

source: c:\runehov\Engine\Classes\Weapon.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Inventory
         |
         +--Engine.Weapon
Direct Known Subclasses:Axe, Hammer, InvisibleWeapon, NonStow, Sword

class Weapon
extends Engine.Inventory

//============================================================================= // Parent class of all weapons. //=============================================================================
Variables
 Texture BloodTexture
           PowerUp effect active locally
 int Damage
           PowerUp effect active locally
 name DamageType
           PowerUp effect active locally
 enum EMeleeType
 float ExtendedLength
           Extent of sweep lines
 int FrameOfAttackAnim
           TEST: for frame-rate independent attacks
 int HitMatterSoundCount
           PowerUp effect active locally
 Actor LastThrower
           RUNE: Last actor to throw this weapon...
 int NumEarthSounds
           testing sweep
 int NumFleshSounds
           testing sweep
 int NumMetalSounds
           testing sweep
 int NumStoneSounds
           testing sweep
 int NumThroughAirBerserkSounds
           testing sweep
 int NumThroughAirSounds
           testing sweep
 int NumWoodSounds
           testing sweep
 class PoweredUpSwipeClass
           testing sweep
 Texture PowerupIcon
           RUNE: Last actor to throw this weapon...
 Texture PowerupIconAnim
           RUNE: Last actor to throw this weapon...
 string PowerupMessage
           Duration of the powerup (weapon-specific... some weapons are not time-based)
 int Rating
           Higher rating means a better weapon
 float RunePowerDuration
           Duration of the powerup (weapon-specific... some weapons are not time-based)
 int RunePowerRequired
           Power needed to powerup the weapon
 byte StabMesh
           Duration of the powerup (weapon-specific... some weapons are not time-based)
 Actor StabbedActor
           Actor that was stabbed by the weapon
 byte StowMesh
           PowerUp effect active locally
 int SweepJoint1
           Extent of sweep lines
 int SweepJoint2
           Extent of sweep lines
 vector SweepVector
           vector defining weapon direction in holders joint coords (usually (0,1,0))
 WeaponSwipe Swipe
           testing sweep
 class SwipeClass
           testing sweep
 SwipeHit SwipeHits[16]
           testing sweep
 name ThrownDamageType
           PowerUp effect active locally
 int TimerCount
           Used for powerup pulsing
 float WeaponSweepExtent
           Extent of sweep lines
 bool bCanBePoweredUp
           Should use the two-handed anims when crouching
 bool bClientPoweredUp
           PowerUp effect active locally
 bool bCrouchTwoHands
           Should use the two-handed anims when crouching
 bool bPlayedDropSound
           Should use the two-handed anims when crouching
 bool bPoweredUp
           Should use the two-handed anims when crouching
 bool bWeaponStay
           Copy of weapon stays after being picked up
 vector gB1,gE1,gB2,gE2
           TEST: for frame-rate independent attacks
 lastpos1, lastpos2
           testing sweep

States
Swinging, Settling, Drop, Throw, Stow, Active, BeingPickedUp, Pickup

Function Summary
 int CalculateDamage(Actor Victim)
     
//=============================================================================
//
// CalculateDamage
//
// Calculates damage amount, based on strength modifier.
// Override with logic for rune powers
//=============================================================================
 void ClientWeaponEvent(name EventType)
 void Destroyed()
     
//=============================================================================
//
// Destroyed
//
//=============================================================================
 void DisableSwipeTrail()
     
//=============================================================================
//
// DisableSwipeTrail
//
//=============================================================================
 void EnableSwipeTrail()
     
//=============================================================================
//
// EnableSwipeTrail
//
//=============================================================================
 int GetUsePriority()
     
//============================================================================
//
// GetUsePriority
//
// Returns the priority of the weapon, lower is better
//============================================================================
 bool HandlePickupQuery(Inventory Item)
 EMatterType MatterForJoint(int joint)
     
//============================================================
//
// MatterForJoint
//
// Returns what kind of material joint is associated with
//============================================================
 void PlayHitMatterSound(EMatterType matter)
     
//============================================================
//
// PlayHitMatterSound
//
//============================================================
 void PlayNormalFrame()
     
//=============================================================================
//
// PlayNormalFrame
//
//=============================================================================
 void PlayThrowFrame()
     
//=============================================================================
//
// PlayThrowFrame
//
// Sets the frame with centered base for proper rotation
//=============================================================================
 void PostBeginPlay()
     
//=============================================================================
//
// PostBeginPlay
//
//=============================================================================
 
simulated
PostRender(Canvas Canvas)
 void PowerUp()
     
//=============================================================================
//
// Powerup
//
// This function is called when the weapon is initially powered up
//=============================================================================
 void PowerUpNotify1()
     
// Used for lightning powerup, get rid of
 void PowerUpNotify2()
 void PoweredUpCallback1()
 void PoweredUpCallback2()
 void PowerupEnd()
 void PowerupEnded()
 void PowerupEndingPulseOff()
 void PowerupEndingPulseOn()
 void PowerupInit()
     
//=============================================================================
// Powerup functions to override
//=============================================================================
 
simulated
PreRender(Canvas Canvas)
 float RateSelf(out int)
     
//=============================================================================
//
// RateSelf
//
// Returns a rating of the weapon
//=============================================================================
 
simulated
RemovePowerupEffect()
 void RemoveStab(Carcass Victim, int JointIndex)
     
//=============================================================================
//
// RemoveStab
//
//=============================================================================
 void SetWeaponStay()
 Inventory SpawnCopy(Pawn Other)
     
//=============================================================================
//
// SpawnCopy
//
// Either give this inventory to player Other, or spawn a copy
// and give it to the player Other, setting up original to be respawned.
// Also add Ammo to Other's inventory if it doesn't already exist
//
//=============================================================================
 
simulated
SpawnPowerupEffect()
 bool SplashJump()
 void StabActor(Pawn Victim)
     
//=============================================================================
//
// StabActor
//
// Stab the actor with a weapon, and attach the weapon
//
// NOTE:  Limit this to just swords?
//=============================================================================
 bool StickInWall(EMatterType matter)
 float SuggestAttackStyle()
     
//=============================================================================
//
// SuggestAttackStyle
//
// return delta to combat style
//=============================================================================
 float SuggestDefenseStyle()
     
//=============================================================================
//
// SuggestDefendStyle
//
// return delta to defend style
//=============================================================================
 void Timer()
 void WeaponFire(int SwingCount)
 void ZoneChange(ZoneInfo newZone)
     
//=============================================================================
//
// ZoneChange
//
// If the weapon enters a water zone, clear out the blood texture
//=============================================================================


State Swinging Function Summary
 void Tick(float DeltaTime)
     
/*
	
 void FinishAttack()
     
//=========================================================================
 void ClearSwipeArray()
 void StartAttack()
 void FrameNotify(int framepassed)
     
// Called each frame of animation
 void BeginState()


State Settling Function Summary
 void StartDamageCheck()
 void PlaySwipeSound()
     
//=============================================================================
//
// PlaySwipeSound
//
//=============================================================================
 void SpawnHitEffect(vector HitLoc, vector HitNorm, int LowMask, int HighMask, Actor HitActor)
     
//=============================================================================
//
// SpawnHitEffect
//
// Spawns an effect based upon what was struck
//=============================================================================
 bool DoWeaponSwipe(Actor A, int LowMask, int HighMask, vector HitLoc, vector HitNorm, vector Momentum)
     
//=============================================================================
//
// DoWeaponSwipe
//
// Returns true if the swipe can continue, false if the swipe should stop
//=============================================================================
 bool SwipeArrayCheck(Actor A, int LowMask, int HighMask)
     
//=============================================================================
//
// SwipeArrayCheck
//
// This maintains an array of actors (and joints within those actors)
// that are struck by the swipe.  Duplicates are not allowed.
// 
// The original intention for this was to not allow a given joint to be hit
// more than once, but to allow multiple joints within an actor to be hit.
// However, for gameplay purposes, this now ignores the joints and only
// allows each Actor to be struck once, regardless of the number of joints
// struck in the swipe.
//=============================================================================
 void ClearSwipeArray()
     
//=============================================================================
//
// ClearSwipeArray
//
//=============================================================================
 void ForceAltFire()
 void ForceFire()
 bool ClientAltFire(float Value)
 bool ClientFire(float Value)
 void DropFrom(vector StartLocation)
     
//=============================================================================
//
// DropFrom
//
//=============================================================================
 void FinishAttack()
     
//=============================================================================
//
// FinishAttack
//
//=============================================================================
 void StartAttack()
     
//=============================================================================
//
// StartAttack
//
//=============================================================================
 void Touch(Actor Other)
 void HitWall(vector HitNormal, Actor HitWall)
 bool CanBeUsed(Actor Other)
     
//============================================================================
 void Landed(vector HitNormal, Actor HitActor)
 void EndState()
 void BeginState()


State Drop Function Summary
 void Touch(Actor Other)
 void HitWall(vector HitNormal, Actor HitWall)
 void Landed(vector HitNormal, Actor HitActor)
 void EndState()
 void BeginState()


State Throw Function Summary
 void Touch(Actor Other)
     
//=========================================================================
 void HitWall(vector HitNormal, Actor HitWall)
 void Landed(vector HitNormal, Actor HitActor)
 bool CanBeUsed(Actor Other)
 void EndState()
 void ZoneChange(ZoneInfo newZone)
 void BeginState()


State Stow Function Summary
 void EndState()
 void BeginState()


State Active Function Summary
 void StartAttack()
 void EndState()
 void BeginState()


State BeingPickedUp Function Summary
 void BeginState()
     
{
	


State Pickup Function Summary
 void Touch(Actor Other)
 void EndState()
 void BeginState()



Source Code


00001	//=============================================================================
00002	// Parent class of all weapons.
00003	//=============================================================================
00004	class Weapon extends Inventory
00005		abstract
00006		native;
00007	//	nativereplication;
00008	
00009	#exec Texture Import File=Textures\Weapon.pcx Name=S_Weapon Mips=Off Flags=2
00010	
00011	/*
00012	   SOUND slot usage:
00013		SLOT_None				
00014		SLOT_Misc				HitXXXX
00015		SLOT_Pain				
00016		SLOT_Interact			DropSound
00017		SLOT_Ambient			AmbientSound
00018		SLOT_Talk				ThroughAir
00019		SLOT_Interface			Sheath,UnSheath
00020	*/
00021	
00022	// ----- STRUCTURES -----------------------------------------------------------
00023	
00024	struct SwipeHit
00025	{
00026		var Actor Actor;
00027		var int LowMask;
00028		var int HighMask;
00029	};
00030	
00031	// ----- VARIABLES ------------------------------------------------------------
00032	
00033	var() enum EMeleeType
00034	{
00035		MELEE_SWORD,
00036		MELEE_HAMMER,
00037		MELEE_AXE,
00038		MELEE_NON_STOW
00039	} MeleeType;
00040	
00041	var() bool bWeaponStay;				// Copy of weapon stays after being picked up
00042	var() bool bCrouchTwoHands;			// Should use the two-handed anims when crouching	
00043	var() bool bPoweredUp;
00044	var bool bCanBePoweredUp;
00045	var bool bPlayedDropSound;
00046	var bool bClientPoweredUp;			// PowerUp effect active locally
00047	var int HitMatterSoundCount;
00048	
00049	var() byte StowMesh;
00050	var() int Damage;
00051	var() name DamageType;
00052	var() name ThrownDamageType;
00053	var() Texture BloodTexture;
00054	var() int Rating;				// Higher rating means a better weapon
00055	var() float WeaponSweepExtent;	// Extent of sweep lines
00056	var() int SweepJoint1;
00057	var() int SweepJoint2;
00058	var() float ExtendedLength;
00059	var() int RunePowerRequired;	// Power needed to powerup the weapon
00060	var() float RunePowerDuration;	// Duration of the powerup (weapon-specific... some weapons are not time-based)
00061	var() localized string PowerupMessage;
00062	var() byte StabMesh;
00063	var int TimerCount;				// Used for powerup pulsing
00064	var() vector SweepVector;		// vector defining weapon direction in holders joint coords (usually (0,1,0))
00065	
00066	var int FrameOfAttackAnim;	// TEST: for frame-rate independent attacks
00067	var vector gB1,gE1,gB2,gE2;
00068	
00069	var Actor StabbedActor;	// Actor that was stabbed by the weapon
00070	
00071	var Actor LastThrower;	//RUNE: Last actor to throw this weapon...
00072	
00073	var(Sounds) Sound	ThroughAir[3];
00074	var(Sounds) Sound	ThroughAirBerserk[3];
00075	var(Sounds) Sound	HitFlesh[3];
00076	var(Sounds) Sound	HitWood[3];
00077	var(Sounds) Sound	HitStone[3];
00078	var(Sounds) Sound	HitMetal[3];
00079	var(Sounds) Sound	HitDirt[3];
00080	var(Sounds) Sound	HitShield;
00081	var(Sounds) Sound	HitWeapon;
00082	var(Sounds) Sound	HitBreakableWood;
00083	var(Sounds) Sound	HitBreakableStone;
00084	var(Sounds) Sound	SheathSound; 
00085	var(Sounds) Sound	UnsheathSound;
00086	var(Sounds) Sound	ThrownSoundLOOP;
00087	var(Sounds)	Sound	PowerUpSound;
00088	var(Sounds) Sound	PoweredUpSoundLOOP;
00089	var(Sounds) Sound	PoweredUpEndingSound;
00090	var(Sounds) Sound	PoweredUpEndSound;
00091	
00092	var(Sounds) float	PitchDeviation;		// Vary pitch of sounds by +/- this percentage
00093	
00094	var() Texture PowerupIcon;
00095	var() Texture PowerupIconAnim;
00096	
00097	var vector lastpos1, lastpos2;	// testing sweep
00098	
00099	var int NumThroughAirSounds;
00100	var int NumThroughAirBerserkSounds;
00101	var int NumFleshSounds;
00102	var int NumWoodSounds;
00103	var int NumStoneSounds;
00104	var int NumMetalSounds;
00105	var int NumEarthSounds;
00106	
00107	const HitCount = 16;
00108	var SwipeHit SwipeHits[16];
00109	
00110	// For the weapon swipe effect
00111	var WeaponSwipe Swipe;
00112	var() class<WeaponSwipe> SwipeClass;
00113	var() class<WeaponSwipe> PoweredUpSwipeClass;
00114	
00115	// Viking specific information (utilized to determine which animations should
00116	// be used for Ragnar and the enemy vikings using this weapon)
00117	var(Anims) name A_Idle;
00118	var(Anims) name A_TurnLeft;
00119	var(Anims) name A_TurnRight;
00120	var(Anims) name A_Forward;
00121	var(Anims) name A_Backward;
00122	var(Anims) name A_Forward45Right;
00123	var(Anims) name A_Forward45Left;
00124	var(Anims) name A_Backward45Right;
00125	var(Anims) name A_Backward45Left;
00126	var(Anims) name A_StrafeRight;
00127	var(Anims) name A_StrafeLeft;
00128	var(Anims) name A_Jump;
00129	var(Anims) name A_ForwardAttack; // This anim is only played on the legs while attacking
00130	
00131	var(Anims) name A_AttackA;	// attack moving forward
00132	var(Anims) name A_AttackAReturn;
00133	var(Anims) name A_AttackB;	// attack moving forward combo
00134	var(Anims) name A_AttackBReturn;	
00135	var(Anims) name A_AttackC;	// attack moving forward combo #2
00136	var(Anims) name A_AttackCReturn;
00137	var(Anims) name A_AttackD;	// attack moving forward combo #3
00138	var(Anims) name A_AttackDReturn;
00139	
00140	var(Anims) name A_AttackStandA;
00141	var(Anims) name A_AttackStandAReturn;
00142	var(Anims) name A_AttackStandB;
00143	var(Anims) name A_AttackStandBReturn;	
00144	
00145	var(Anims) name A_AttackBackupA;
00146	var(Anims) name A_AttackBackupAReturn;
00147	var(Anims) name A_AttackBackupB;
00148	var(Anims) name A_AttackBackupBReturn;
00149	
00150	var(Anims) name A_AttackStrafeRight;
00151	var(Anims) name A_AttackStrafeLeft;
00152	var(Anims) name A_JumpAttack;
00153	var(Anims) name A_Throw;
00154	
00155	var(Anims) name A_Powerup;
00156	
00157	var(Anims) name A_Defend;
00158	var(Anims) name A_DefendIdle;
00159	
00160	var(Anims) name A_PainFront;
00161	var(Anims) name A_PainBack;
00162	var(Anims) name A_PainLeft;
00163	var(Anims) name A_PainRight;
00164	
00165	var(Anims) name A_PickupGroundLeft;
00166	var(Anims) name A_PickupHighLeft;
00167	
00168	var(Anims) name A_Taunt;
00169	
00170	var(Anims) name A_PumpTrigger;
00171	var(Anims) name A_LeverTrigger;
00172	
00173	// more to come....
00174	
00175	replication
00176	{
00177		reliable if (Role==ROLE_Authority)
00178			bPoweredUp;
00179	
00180		// Function the server can call on the client
00181	//	unreliable if( Role==ROLE_Authority && bPoweredUp)
00182	//		ClientWeaponFire;
00183	}
00184	
00185	//=============================================================================
00186	//
00187	// PostBeginPlay
00188	//
00189	//=============================================================================
00190	function PostBeginPlay()
00191	{
00192		local int i;
00193	
00194		SetWeaponStay();
00195	
00196		NumThroughAirSounds = 0;
00197		NumThroughAirBerserkSounds = 0;
00198		NumFleshSounds = 0;
00199		NumWoodSounds = 0;
00200		NumStoneSounds = 0;
00201		NumMetalSounds = 0;
00202		NumEarthSounds = 0;
00203		for(i = 0; i < 3; i++)
00204		{
00205			if(ThroughAir[i] != None)
00206				NumThroughAirSounds++;
00207			if(ThroughAirBerserk[i] != None)
00208				NumThroughAirBerserkSounds++;
00209			if(HitFlesh[i] != None)
00210				NumFleshSounds++;
00211			if(HitWood[i] != None)
00212				NumWoodSounds++;
00213			if(HitStone[i] != None)
00214				NumStoneSounds++;
00215			if(HitMetal[i] != None)
00216				NumMetalSounds++;
00217			if(HitDirt[i] != None)
00218				NumEarthSounds++;
00219		}
00220	
00221		Super.PostBeginPlay();
00222	}
00223	
00224	function bool SplashJump()
00225	{
00226		return false;
00227	}
00228	
00229	simulated function PreRender( canvas Canvas );
00230	simulated function PostRender( canvas Canvas );
00231	
00232	function ClientWeaponEvent(name EventType);
00233	
00234	
00235	//=============================================================================
00236	//
00237	// CalculateDamage
00238	//
00239	// Calculates damage amount, based on strength modifier.
00240	// Override with logic for rune powers
00241	//=============================================================================
00242	
00243	function int CalculateDamage(actor Victim)
00244	{
00245		local int newDamage;
00246	
00247		newDamage = Damage;
00248	
00249		if(Owner != None && Pawn(Owner) != None)
00250			newDamage *= Pawn(Owner).PawnDamageModifier(self);
00251	
00252		// Don't hurt players/shield in neutral zones
00253		if((Owner.Region.Zone.bNeutralZone || Victim.Region.Zone.bNeutralZone) && (Victim.IsA('Pawn') || Victim.IsA('Shield')))
00254			newDamage = 0;
00255		else if(Victim.Owner != None && Victim.Owner.Region.Zone.bNeutralZone)
00256			newDamage = 0; // Shield could be sticking out of the neutral zone, but the owner is inside
00257	
00258		if (Level.Game.bTeamGame && Pawn(Victim) != None && Pawn(Owner) != None 
00259			&& Pawn(Victim).PlayerReplicationInfo.Team != 255 
00260			&& Pawn(Victim).PlayerReplicationInfo.Team == Pawn(Owner).PlayerReplicationInfo.Team)
00261			newDamage = 0; // Don't hurt the victim if on the same team
00262	
00263	//	if (Owner != None && Pawn(Owner) != None)
00264	//		newDamage += Pawn(Owner).Strength * 0.25;
00265	
00266		return newDamage;
00267	}
00268	
00269	//=============================================================================
00270	// Powerup functions to override
00271	//=============================================================================
00272	function PowerupInit()
00273	{
00274	//	DesiredColorAdjust.X = 191;
00275	//	DesiredFatness=170;
00276		SwipeClass = PoweredUpSwipeClass;
00277		SpawnPowerupEffect();
00278	}
00279	
00280	function PowerupEndingPulseOn()
00281	{
00282		DesiredFatness=170;
00283		DesiredColorAdjust.X = 191;
00284		PlaySound(PoweredUpEndingSound, SLOT_None);
00285	}
00286	
00287	function PowerupEndingPulseOff()
00288	{
00289		DesiredFatness=128;
00290		DesiredColorAdjust.X = 0;
00291	}
00292	
00293	function PowerupEnded()
00294	{
00295		DesiredColorAdjust.X = 0;
00296		DesiredFatness=128;
00297		SwipeClass = Default.SwipeClass;
00298		RemovePowerupEffect();
00299	}
00300	
00301	simulated function SpawnPowerupEffect()		{}
00302	simulated function RemovePowerupEffect()	{}
00303	
00304	// called on clients when bPoweredUp changes
00305	simulated event PowerupStatusChanged()
00306	{
00307		if (bPoweredUp && !bClientPoweredUp)
00308		{
00309			bClientPoweredUp = true;
00310			SpawnPowerupEffect();
00311		}
00312		else if (!bPoweredUp && bClientPoweredUp)
00313		{
00314			bClientPoweredUp = false;
00315			RemovePowerupEffect();
00316		}
00317	}
00318	
00319	
00320	//=============================================================================
00321	//
00322	// Powerup
00323	//
00324	// This function is called when the weapon is initially powered up
00325	//=============================================================================
00326	function PowerUp()
00327	{
00328		bPoweredUp = true;
00329		SetTimer(RunePowerDuration, false);
00330		TimerCount = 7;
00331		PlaySound(PowerUpSound);
00332		AmbientSound = PoweredUpSoundLOOP;
00333		Pawn(Owner).ClientMessage(PowerupMessage, '');
00334		PowerupInit();
00335	}
00336	
00337	function PowerupEnd()
00338	{
00339		bPoweredUp = false;
00340		SetTimer(0, false);
00341		PlaySound(PoweredUpEndSound);
00342		AmbientSound = None;
00343		PowerupEnded();
00344	}
00345	
00346	function Timer()
00347	{
00348		TimerCount--;
00349	
00350		switch(TimerCount)
00351		{
00352		case 5: case 3: case 1:
00353			PowerupEndingPulseOn();
00354			SetTimer(0.5, false);
00355			break;
00356		case 6: case 4: case 2:	
00357			PowerupEndingPulseOff();
00358			SetTimer(0.5, false);
00359			break;
00360		case 0:
00361			PowerupEnd();
00362			break;
00363		}
00364	}
00365	
00366	function WeaponFire(int SwingCount); // Event called at some point during the swing for powerups (swingcount is zero-based)
00367	
00368	// Used for lightning powerup, get rid of
00369	function PowerUpNotify1();
00370	function PowerUpNotify2();
00371	function PoweredUpCallback1();
00372	function PoweredUpCallback2();
00373	
00374	function bool StickInWall( EMatterType matter)
00375	{
00376		return false;
00377	}
00378	
00379	function SetWeaponStay()
00380	{
00381		if (Level.Game != None)
00382			bWeaponStay = bWeaponStay || Level.Game.bCoopWeaponMode;
00383	}
00384	
00385	function bool HandlePickupQuery( inventory Item )
00386	{
00387		local int OldAmmo;
00388		local Pawn P;
00389	
00390		if (Item.Class == Class)
00391		{
00392			P = Pawn(Owner);
00393	
00394			if (Level.Game.LocalLog != None)
00395				Level.Game.LocalLog.LogPickup(Item, Pawn(Owner));
00396			if (Level.Game.WorldLog != None)
00397				Level.Game.WorldLog.LogPickup(Item, Pawn(Owner));
00398			if (Item.PickupMessageClass == None)
00399				P.ClientMessage(Item.PickupMessage, 'Pickup');
00400			else
00401				P.ReceiveLocalizedMessage( Item.PickupMessageClass, 0, None, None, item.Class );
00402			Item.PlaySound(Item.PickupSound);
00403			Item.SetRespawn();   
00404			return true;
00405		}
00406		if ( Inventory == None )
00407			return false;
00408	
00409		return Inventory.HandlePickupQuery(Item);
00410	}
00411	
00412	//============================================================
00413	//
00414	// MatterForJoint
00415	//
00416	// Returns what kind of material joint is associated with
00417	//============================================================
00418	function EMatterType MatterForJoint(int joint)
00419	{
00420		return MATTER_WEAPON;
00421	}
00422	
00423	//============================================================
00424	//
00425	// PlayHitMatterSound
00426	//
00427	//============================================================
00428	function PlayHitMatterSound(EMatterType matter)
00429	{
00430		local int i;
00431		switch(matter)
00432		{
00433			case MATTER_FLESH:
00434				i = Rand(NumFleshSounds);
00435				PlaySound(HitFlesh[i], SLOT_Misc,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
00436				break;
00437			case MATTER_WOOD:
00438				i = Rand(NumWoodSounds);
00439				PlaySound(HitWood[i], SLOT_Misc,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
00440				break;
00441			case MATTER_STONE:
00442				i = Rand(NumStoneSounds);
00443				PlaySound(HitStone[i], SLOT_Misc,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
00444				break;
00445			case MATTER_METAL:
00446				i = Rand(NumMetalSounds);
00447				PlaySound(HitMetal[i], SLOT_Misc,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
00448				break;
00449			case MATTER_EARTH:
00450				i = Rand(NumEarthSounds);
00451				PlaySound(HitDirt[i], SLOT_Misc,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
00452				break;
00453			case MATTER_BREAKABLEWOOD:
00454				PlaySound(HitBreakableWood, SLOT_Misc,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
00455				break;
00456			case MATTER_BREAKABLESTONE:
00457				PlaySound(HitBreakableStone, SLOT_Misc,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
00458				break;
00459			case MATTER_WEAPON:
00460				PlaySound(HitWeapon, SLOT_Misc,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
00461				break;
00462			case MATTER_SHIELD:
00463				PlaySound(HitShield, SLOT_Misc,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
00464				break;
00465			case MATTER_ICE:
00466			case MATTER_WATER:
00467				break;
00468		}
00469	
00470		if (Pawn(Owner) != None)
00471		{
00472			Pawn(Owner).MakeNoise(1.0);
00473		}
00474	}
00475	
00476	//=============================================================================
00477	//
00478	// Destroyed
00479	//
00480	//=============================================================================
00481	
00482	function Destroyed()
00483	{
00484		Super.Destroyed();
00485		if((Pawn(Owner)!=None) && (Pawn(Owner).Weapon == self))
00486		{
00487			Pawn(Owner).Weapon = None;
00488		}
00489	}
00490	
00491	//=============================================================================
00492	//
00493	// TravelPostAccept
00494	//
00495	//=============================================================================
00496	
00497	event TravelPostAccept()
00498	{
00499		local PlayerPawn P;
00500		local int joint;
00501	
00502		Super.TravelPostAccept();
00503	
00504		if(Pawn(Owner) == None)
00505		{
00506			return;
00507		}
00508	
00509		if(self == Pawn(Owner).Weapon)
00510		{
00511			joint = Owner.JointNamed(Pawn(Owner).WeaponJoint);
00512			Owner.AttachActorToJoint(self, joint);
00513			GotoState('Active');
00514			
00515			return;
00516		}
00517	
00518		if(Owner.IsA('PlayerPawn'))
00519		{ // Player-specific travel code
00520			P = PlayerPawn(Owner);
00521	
00522			if(self == P.StowSpot[0])
00523				joint = P.JointNamed('attatch_sword'); // Compensate for a spelling error...
00524			else if(self == P.StowSpot[1])
00525				joint = P.JointNamed('attach_hammer');
00526			else if(self == P.StowSpot[2])
00527				joint = P.JointNamed('attach_axe');
00528			else
00529				joint = 0;
00530	
00531			if(joint != 0)
00532				P.AttachActorToJoint(self, joint);
00533			else
00534				bHidden = true; // Hide inventory items that are NOT on a stowspot
00535		
00536			GotoState('Stow');
00537		}
00538	}
00539	
00540	//=============================================================================
00541	//
00542	// PlayThrowFrame
00543	//
00544	// Sets the frame with centered base for proper rotation
00545	//=============================================================================
00546	function PlayThrowFrame()
00547	{
00548		PlayAnim('flying', 1.0, 0.0);
00549	}
00550	
00551	//=============================================================================
00552	//
00553	// PlayNormalFrame
00554	//
00555	//=============================================================================
00556	function PlayNormalFrame()
00557	{
00558		PlayAnim('baseframe', 1.0, 0.0);
00559	}
00560	
00561	//=============================================================================
00562	//
00563	// SuggestAttackStyle
00564	//
00565	// return delta to combat style
00566	//=============================================================================
00567	
00568	function float SuggestAttackStyle()
00569	{
00570		return 0.0;
00571	}
00572	
00573	//=============================================================================
00574	//
00575	// SuggestDefendStyle
00576	//
00577	// return delta to defend style
00578	//=============================================================================
00579	
00580	function float SuggestDefenseStyle()
00581	{
00582		return 0.0;
00583	}
00584	
00585	//=============================================================================
00586	//
00587	// RateSelf
00588	//
00589	// Returns a rating of the weapon
00590	//=============================================================================
00591	
00592	function float RateSelf(out int bUseAltMode)
00593	{
00594		return 1.0;
00595	}
00596	
00597	//============================================================================
00598	//
00599	// GetUsePriority
00600	//
00601	// Returns the priority of the weapon, lower is better
00602	//============================================================================
00603	
00604	function int GetUsePriority()
00605	{
00606		return(1);
00607	}
00608	
00609	//=============================================================================
00610	//
00611	// SpawnCopy
00612	//
00613	// Either give this inventory to player Other, or spawn a copy
00614	// and give it to the player Other, setting up original to be respawned.
00615	// Also add Ammo to Other's inventory if it doesn't already exist
00616	//
00617	//=============================================================================
00618	
00619	function inventory SpawnCopy( pawn Other )
00620	{
00621		local inventory Copy;
00622		local Weapon newWeapon;
00623	
00624		if( Level.Game.ShouldRespawn(self) )
00625		{
00626			Copy = spawn(Class,Other,,,rot(0,0,0));
00627			if (Copy == None)
00628				log(name@"cannot be spawned in spawncopy");
00629			Copy.Tag           = Tag;
00630			Copy.Event         = Event;
00631			if ( !bWeaponStay )
00632				GotoState('Sleeping');
00633		}
00634		else
00635			Copy = self;
00636	
00637		Copy.bTossedOut = true;
00638		Copy.RespawnTime = 0.0;
00639		Copy.GiveTo( Other );
00640		Copy.bHidden = false; // BecomeItem in Inventory automatically hides the item
00641		newWeapon = Weapon(Copy);
00642	//	newWeapon.Instigator = Other;
00643	//	newWeapon.SetSwitchPriority(Other);
00644	//	if ( !Other.bNeverSwitchOnPickup )
00645	//		newWeapon.WeaponSet(Other);
00646	//	newWeapon.AmbientGlow = 0;
00647		return newWeapon;
00648	}
00649	
00650	//=============================================================================
00651	//
00652	// EnableSwipeTrail
00653	//
00654	//=============================================================================
00655	
00656	function EnableSwipeTrail()
00657	{
00658		if(SwipeClass != None)
00659		{
00660			Swipe = Spawn(SwipeClass, self,, Location,);
00661			if(Swipe != None)
00662			{
00663				Swipe.BaseJointIndex = SweepJoint1;
00664				Swipe.OffsetJointIndex = SweepJoint2;
00665				Swipe.SystemLifeSpan = -1;	
00666				Swipe.SetBase(self.Owner);
00667			}
00668		}
00669	}
00670	
00671	//=============================================================================
00672	//
00673	// DisableSwipeTrail
00674	//
00675	//=============================================================================
00676	
00677	function DisableSwipeTrail()
00678	{
00679		if(Swipe != None)
00680		{
00681			Swipe.SystemLifeSpan = 3.0;
00682			Swipe.SetBase(None);
00683			Swipe = None;
00684		}
00685	}
00686	
00687	//=============================================================================
00688	//
00689	// ZoneChange
00690	//
00691	// If the weapon enters a water zone, clear out the blood texture
00692	//=============================================================================
00693	
00694	function ZoneChange(ZoneInfo newZone)
00695	{
00696		local int i;
00697	
00698		if(newZone.bWaterZone)
00699		{
00700			for (i=0; i<16; i++)
00701				SkelGroupSkins[i] = None; // Force the weapon to use the default skin
00702			SetDefaultPolygroups();
00703			if (bPoweredUp)
00704				PowerupEnd();
00705		}
00706	}
00707	
00708	//=============================================================================
00709	//
00710	// StabActor
00711	//
00712	// Stab the actor with a weapon, and attach the weapon
00713	//
00714	// NOTE:  Limit this to just swords?
00715	//=============================================================================
00716	
00717	function StabActor(Pawn Victim)
00718	{
00719		if(Victim.StabJoint == '')
00720			return;
00721	
00722		Victim.AttachActorToJoint(self, Victim.JointNamed(Victim.StabJoint));
00723		Victim.PainSkin(BODYPART_TORSO); // Bloody the chest
00724	
00725	//	SkelMesh = StabMesh;
00726		PlayAnim('skewer', 1.0, 0.0);
00727	}
00728	
00729	//=============================================================================
00730	//
00731	// RemoveStab
00732	//
00733	//=============================================================================
00734	
00735	function RemoveStab(Carcass Victim, int JointIndex)
00736	{
00737		local vector newLoc;
00738		local rotator newRot;
00739	
00740		PlayAnim('base', 1.0, 0.0);
00741	//	SkelMesh = Default.SkelMesh;
00742		newLoc = Victim.GetJointPos(JointIndex) + vect(0, 0, 38); // Tweak me
00743		SetLocation(newLoc);
00744		newRot = rot(0, 0, 16384); // Tweak me
00745		newRot.Yaw = Victim.Rotation.Yaw + 16384;
00746		SetRotation(newRot);
00747		SetPhysics(PHYS_None);
00748		GotoState('Pickup');
00749	}
00750	
00751	//-----------------------------------------------------------------------------
00752	//
00753	// State Pickup
00754	//
00755	// Melee Weapon is sitting on the ground waiting to be picked up
00756	//-----------------------------------------------------------------------------
00757	
00758	auto state Pickup
00759	{
00760		function BeginState()
00761		{
00762			bSweepable=false;
00763			BecomePickup();
00764			bCollideWorld = true;
00765			if (bTossedOut && bExpireWhenTossed)	// If not a placed item, expire after some time
00766				LifeSpan=ExpireTime;
00767		}
00768		
00769		function EndState()
00770		{
00771			bSweepable=Default.bSweepable;
00772			BecomeItem();
00773			bCollideWorld = false;
00774			LifeSpan=0;				// Disallow expire, since someone picked me up
00775	
00776			if(StabbedActor != None)
00777			{ // Animate the stabbed guy while removing the weapon
00778				StabbedActor.PlayStabRemove();
00779				StabbedActor = None;
00780			}
00781		}
00782		
00783		function Touch(Actor Other)
00784		{
00785			local inventory Copy;
00786	
00787			if(Other.IsA('Pawn'))
00788			{
00789				if(Pawn(Other).Health > 0 && Pawn(Other).CanPickUp(self))
00790				{
00791					if (Level.Game.LocalLog != None)
00792						Level.Game.LocalLog.LogPickup(Self, Pawn(Other));
00793					if (Level.Game.WorldLog != None)
00794						Level.Game.WorldLog.LogPickup(Self, Pawn(Other));
00795					Copy = SpawnCopy(Pawn(Other));
00796					
00797					if(PickupMessageClass == None)
00798						Pawn(Other).ClientMessage(PickupMessage, 'Pickup');
00799					else
00800						Pawn(Other).ReceiveLocalizedMessage( PickupMessageClass, 0, None, None, Self.Class);
00801	
00802					Copy.PlaySound (PickupSound);
00803					if ( Level.Game.Difficulty > 1 )
00804						Other.MakeNoise(0.1 * Level.Game.Difficulty);
00805					Pawn(Other).AcquireInventory(Copy);
00806	
00807					if(!Pawn(Other).IsInState('PlayerSwimming'))
00808						Copy.GotoState('Active');
00809				}
00810			}
00811		}
00812		
00813	begin:
00814		AmbientGlow = 0;
00815		SkelMesh = Default.SkelMesh;
00816	
00817		if (Role==ROLE_Authority)
00818			bSimFall = false;	// Don't Replicate physics or simulate falling
00819	}
00820	
00821	//-----------------------------------------------------------------------------
00822	//
00823	// State BeingPickedUp
00824	//
00825	// Melee Weapon is about to be picked up by another actor
00826	//
00827	//-----------------------------------------------------------------------------
00828	/*
00829	state BeingPickedUp
00830	{
00831		function BeginState()
00832		{
00833			Pawn(Owner).AcquireInventory(self);
00834			GotoState('Active');
00835		}
00836		
00837	begin:
00838	}
00839	*/
00840	
00841	//-----------------------------------------------------------------------------
00842	//
00843	// State Active
00844	//
00845	// Melee Weapon is Active and in the actor's hand, waiting to be used
00846	//-----------------------------------------------------------------------------
00847	
00848	state Active
00849	{
00850		function BeginState()
00851		{
00852			SetPhysics(PHYS_None);
00853		}
00854		
00855		function EndState()
00856		{
00857		}
00858	
00859		function StartAttack()
00860		{	
00861			lastpos1 = GetJointPos(SweepJoint1);
00862			lastpos2 = GetJointPos(SweepJoint2);
00863	
00864			ClearSwipeArray();
00865		
00866			GotoState('Swinging');
00867		}
00868	
00869	begin:
00870	}
00871	
00872	//-----------------------------------------------------------------------------
00873	//
00874	// State Stow
00875	//
00876	// Melee Weapon is non-active and stowed on the actor
00877	//-----------------------------------------------------------------------------
00878	
00879	state Stow
00880	{
00881		function BeginState()
00882		{
00883			bSweepable = false;
00884	
00885			if (bPoweredUp)
00886				PowerupEnd();
00887	
00888			PlaySound(SheathSound, SLOT_Interface,,,, 1.0 + (FRand() * 0.2 - 0.1));
00889			SkelMesh = StowMesh;
00890			JointFlags[1] = JointFlags[1] & ~JOINT_FLAG_COLLISION;
00891		}
00892		
00893		function EndState()
00894		{
00895			bSweepable = Default.bSweepable;
00896	
00897			if(!Region.Zone.bWaterZone)
00898				PlaySound(UnsheathSound, SLOT_Interface,,,, 1.0 + (FRand() * 0.2 - 0.1));
00899	
00900			SkelMesh = Default.SkelMesh;
00901			JointFlags[1] = JointFlags[1] | JOINT_FLAG_COLLISION;
00902		}
00903	
00904	begin:	
00905	}
00906	
00907	//-----------------------------------------------------------------------------
00908	//
00909	// State Throw
00910	//
00911	// Melee weapon was thrown
00912	//
00913	//-----------------------------------------------------------------------------
00914	
00915	state Throw
00916	{
00917		function BeginState()
00918		{
00919			local int i;
00920			local rotator wepRot;
00921	
00922			bSimFall = true;	// Replicate physics and simulate falling during throw
00923	
00924			if (bPoweredUp)
00925				PowerupEnd();
00926	
00927			ClearSwipeArray();
00928			
00929			SetPhysics(PHYS_Falling);
00930			SetCollision(true, false, false);
00931			bCollideWorld = true;
00932			bBounce = true;		
00933			bFixedRotationDir = true;
00934			bLookFocusPlayer = true;
00935			
00936			if(Owner != None)
00937			{
00938				wepRot.Yaw = Owner.Rotation.Yaw - 16384 + 32768;
00939				LastThrower = Owner;
00940			}
00941	
00942			wepRot.Pitch = 32768;
00943			wepRot.Roll = 0;
00944			SetRotation(wepRot);
00945			
00946			RotationRate.Pitch = 0;
00947			RotationRate.Yaw = 0;
00948			DesiredRotation.Roll = -32768; //Rotation.Roll - 2000;
00949			RotationRate.Roll = VSize(Velocity) * 2000 / Mass;
00950			PlayThrowFrame();
00951	
00952			AmbientSound = ThrownSoundLOOP;
00953			bPlayedDropSound=false;
00954			HitMatterSoundCount=0;
00955		}
00956	
00957		function ZoneChange(ZoneInfo newZone)
00958		{
00959			global.ZoneChange(newZone);
00960			if(newZone.bWaterZone)
00961			{
00962				GotoState('drop');
00963			}
00964		}
00965	
00966		function EndState()
00967		{
00968			bBounce = false;
00969			SetCollision(false, false, false);
00970			bCollideWorld = false;
00971			bBounce = false;		
00972			bFixedRotationDir = false;
00973			SetOwner(None);
00974	
00975			DisableSwipeTrail();
00976			AmbientSound = None;
00977							
00978			PlayNormalFrame();
00979		}
00980	
00981		function bool CanBeUsed(Actor Other)
00982		{ // Cannot be used while in the thrown state, meaning it cannot be picked up
00983			return(false);
00984		}
00985	
00986		function Landed(vector HitNormal, actor HitActor)
00987		{
00988			HitWall(HitNormal, HitActor);
00989		}
00990	
00991		function HitWall(vector HitNormal, actor HitWall)
00992		{
00993			local float speed;
00994			local int DamageAmount;
00995			local EMatterType matter;
00996			local bool bNoStickInWall;
00997	
00998			AmbientSound = None;
00999	
01000			// Damage movers or polyobjects
01001			if ( (Role == ROLE_Authority) && ( (Mover(HitWall) != None) || (PolyObj(HitWall) != None) ))
01002			{
01003				bNoStickInWall=true;
01004				if(SwipeArrayCheck(HitWall, 0, 0))
01005				{
01006					DamageAmount = CalculateDamage(HitWall);
01007					if (DamageAmount != 0)
01008						HitWall.JointDamaged(DamageAmount, instigator, Location, Velocity*0.5, ThrownDamageType, 0);
01009				}
01010			}
01011			speed = VSize(velocity);
01012	
01013			if (HitNormal.Z > 0.8)
01014			{	// Hit floor
01015				if (!bPlayedDropSound && !Region.Zone.bWaterZone)
01016				{	// Play twice
01017					bPlayedDropSound=true;
01018					PlaySound(DropSound, SLOT_Interact);
01019					if (Instigator != None)
01020						MakeNoise(1.0);
01021				}
01022			}
01023			else if (speed > 300)
01024			{	// Hit wall fast
01025				if (HitMatterSoundCount<3)
01026				{
01027					HitMatterSoundCount++;
01028					matter = MatterTrace(Location-HitNormal*30, Location, 20);
01029					PlayHitMatterSound(matter);
01030				}
01031	
01032				if (!bNoStickInWall && StickInWall(matter))
01033				{	// Stick in wall
01034					bBounce = false;
01035					bFixedRotationDir = false;
01036					SetPhysics(PHYS_None);
01037					GotoState('Pickup');
01038					SetOwner(None);
01039					if ( (Role == ROLE_Authority) && ( (Mover(HitWall) != None) || (PolyObj(HitWall) != None) ))
01040					{	// Stick in mover
01041						SetBase(HitWall);
01042					}
01043					return;
01044				}
01045			}
01046	
01047			if(AnimSequence != 'skewer')
01048				GotoState('Settling');
01049	
01050			return;
01051	
01052	/* 
01053			if((HitNormal.Z > 0.8) && (speed < 60))
01054			{
01055				if(DesiredRotation.Roll ~= Rotation.Roll
01056					&& DesiredRotation.Pitch ~= Rotation.Pitch)
01057				{
01058					SetPhysics(PHYS_None);
01059					bBounce = false;
01060					bFixedRotationDir = false;
01061	
01062					GotoState('Pickup');
01063				}
01064				else
01065				{
01066					DesiredRotation.Roll = 0;
01067					DesiredRotation.Pitch = 0;
01068					RotationRate.Roll = 40000;
01069					RotationRate.Pitch = 40000;
01070					bRotateToDesired = true;
01071					bFixedRotationDir = false;
01072	
01073					Velocity.Z = 60;
01074					SetPhysics(PHYS_Falling);
01075				}
01076			}
01077			else
01078			{			
01079				SetPhysics(PHYS_Falling);
01080				RotationRate.Yaw = VSize(Velocity) * 2000 / Mass;
01081				RotationRate.Pitch = VSize(Velocity) * 2000 / Mass;
01082				Velocity = 0.4 * (Velocity - 2 * HitNormal * (Velocity Dot HitNormal));
01083				DesiredRotation = rotator(HitNormal);
01084			}
01085			SetOwner(None);	// Allow pickup now that it's just waiting to come to rest
01086	*/
01087		}
01088	
01089		//=========================================================================
01090		//
01091		// Touch
01092		// 
01093		// Touched an actor, does a simple check to see which joints the weapon struck
01094		//=========================================================================
01095		function Touch(Actor Other)
01096		{
01097			local int hitjoint;
01098			local vector HitLoc;
01099			local int DamageAmount;
01100			local int LowMask, HighMask;
01101			local actor HitActor;
01102			local PlayerPawn P;
01103			local vector VectOther;
01104			local float dp;
01105	
01106			if (Other == Owner)
01107				return;
01108			if (Owner == None)
01109				return;	// Already hit wall, no more damage after that
01110			if (Other.IsA('Inventory') && Other.GetStateName() == 'Pickup' && !Other.IsA('Lizard'))
01111				return;
01112	
01113			AmbientSound = None;
01114	
01115			HitActor = Other;
01116	
01117			if(Other.IsA('PlayerPawn') && Other.AnimProxy != None) 
01118			{
01119				P = PlayerPawn(Other);
01120				// Determine the direction the player is attempting to move
01121				VectOther = Normal((self.Location - Other.Location) * vect(1, 1, 0));
01122				dp = vector(P.Rotation) dot VectOther;
01123	
01124				if(dp > 0)
01125				{
01126					if(P.Shield != None && P.AnimProxy.GetStateName() == 'Defending')
01127					{
01128						HitActor = P.Shield;
01129					}
01130					else if(P.Weapon != None && P.AnimProxy.GetStateName() == 'Attacking')
01131					{
01132						HitActor = P.Weapon;
01133					}
01134				}
01135			}
01136	
01137			DamageAmount = CalculateDamage(HitActor);
01138	
01139			if(SwipeArrayCheck(HitActor, 0, 0))
01140			{
01141				if(HitActor.JointDamaged(DamageAmount, Pawn(Owner), HitLoc, Velocity*Mass, ThrownDamageType, 0))
01142				{	// Hit something solid, bounce
01143				}
01144	
01145				SpawnHitEffect(HitLoc, Normal(Location - HitActor.Location), 0, 0, HitActor);
01146				SetPhysics(PHYS_Falling);
01147				RotationRate.Yaw = VSize(Velocity) * 2000 / Mass;
01148				RotationRate.Pitch = VSize(Velocity) * 2000 / Mass;
01149				Velocity = -0.1 * Velocity;
01150			}
01151			
01152	/* Pre-shield blocking/weapon blocking of thrown weapons
01153			if (Other.Skeletal != None)
01154			{
01155				hitjoint = Other.ClosestJointTo(Location);
01156				HitLoc = Other.GetJointPos(hitjoint);
01157			}
01158			else
01159			{
01160				hitjoint = 0;
01161				HitLoc = Other.Location;
01162			}
01163			if(SwipeArrayCheck(Other, 0, 0))
01164			{
01165				DamageAmount = CalculateDamage(Other);
01166				if (DamageAmount != 0)
01167				{
01168					if (Other.JointDamaged(DamageAmount, Pawn(Owner), HitLoc, Velocity*Mass, ThrownDamageType, hitjoint))
01169					{	// Hit something solid, bounce
01170					}
01171	
01172					if (hitjoint<32)
01173					{
01174						LowMask = 1 << hitjoint;
01175						HighMask = 0;
01176					}
01177					else
01178					{
01179						LowMask = 0;
01180						HighMask = 1 << (hitjoint - 32);
01181					}
01182					SpawnHitEffect(HitLoc, Normal(Location-Other.Location), LowMask, HighMask, Other);
01183	
01184					SetPhysics(PHYS_Falling);
01185					RotationRate.Yaw = VSize(Velocity) * 2000 / Mass;
01186					RotationRate.Pitch = VSize(Velocity) * 2000 / Mass;
01187					Velocity = -0.1 * Velocity;
01188				}
01189			}
01190	*/
01191		}
01192	
01193	begin:
01194	}
01195	
01196	//-----------------------------------------------------------------------------
01197	//
01198	// State Drop
01199	//
01200	// Melee weapon was dropped
01201	//-----------------------------------------------------------------------------
01202	
01203	state Drop
01204	{
01205		function BeginState()
01206		{		
01207			if (bPoweredUp)
01208				PowerupEnd();
01209			SetPhysics(PHYS_Falling);
01210			SetCollision(true, false, false);
01211			SetOwner(None);
01212			bCollideWorld = true;
01213			bBounce = true;
01214			bFixedRotationDir = true;
01215			DesiredRotation.Yaw = Rotation.Yaw + Rand(2000) - 1000;		
01216			RotationRate.Yaw = 60000 / Mass;
01217			DesiredRotation.Pitch = Rotation.Pitch + Rand(2000) - 1000;		
01218			RotationRate.Pitch = 60000 / Mass;
01219			bPlayedDropSound = false;
01220			HitMatterSoundCount=0;
01221			DisableSwipeTrail();
01222		}
01223		
01224		function EndState()
01225		{
01226			bBounce = false;
01227			SetCollision(false, false, false);
01228			bCollideWorld = false;
01229			bBounce = false;
01230			bFixedRotationDir = false;
01231		}
01232		
01233		function Landed(vector HitNormal, actor HitActor)
01234		{
01235			HitWall(HitNormal, HitActor);
01236		}
01237		
01238		function HitWall(vector HitNormal, actor HitWall)
01239		{
01240			local float speed;
01241	
01242			speed = VSize(velocity);
01243	
01244			if (!bPlayedDropSound && !Region.Zone.bWaterZone)
01245			{
01246				bPlayedDropSound=true;
01247				PlaySound(DropSound, SLOT_Interact);
01248				if (Instigator != None)
01249					MakeNoise(1.0);
01250			}
01251	
01252			if(AnimSequence != 'skewer')
01253				GotoState('Settling');
01254	
01255			return;
01256	/*
01257			if((HitNormal.Z > 0.8) && (speed < 60))
01258			{
01259				if(DesiredRotation.Roll ~= Rotation.Roll
01260					&& DesiredRotation.Pitch ~= Rotation.Pitch)
01261				{
01262					SetPhysics(PHYS_None);
01263					bBounce = false;
01264					bFixedRotationDir = false;
01265	
01266					GotoState('Pickup');
01267				}
01268				else
01269				{
01270					DesiredRotation.Roll = 0;
01271					DesiredRotation.Pitch = 16384;
01272					RotationRate.Roll = 40000;
01273					RotationRate.Pitch = 40000;
01274					bRotateToDesired = true;
01275					bFixedRotationDir = false;
01276	
01277					Velocity.Z = 60;
01278					SetPhysics(PHYS_Falling);
01279				}
01280			}
01281			else
01282			{			
01283				SetPhysics(PHYS_Falling);
01284				RotationRate.Yaw = VSize(Velocity) * 2000 / Mass;
01285				RotationRate.Pitch = VSize(Velocity) * 2000 / Mass;
01286				
01287				Velocity = 0.55 * (Velocity - 2 * HitNormal * (Velocity Dot HitNormal));
01288				DesiredRotation = rotator(HitNormal);
01289			}
01290	*/
01291		}
01292	
01293		function Touch(Actor Other)
01294		{
01295			local inventory Copy;
01296	
01297			if(Other.IsA('Pawn'))
01298			{
01299				if(Pawn(Other).Health > 0 && Pawn(Other).CanPickUp(self))
01300				{
01301					if (Level.Game.LocalLog != None)
01302						Level.Game.LocalLog.LogPickup(Self, Pawn(Other));
01303					if (Level.Game.WorldLog != None)
01304						Level.Game.WorldLog.LogPickup(Self, Pawn(Other));
01305					Copy = SpawnCopy(Pawn(Other));
01306	
01307					if(PickupMessageClass == None)
01308						Pawn(Other).ClientMessage(PickupMessage, 'Pickup');
01309					else
01310						Pawn(Other).ReceiveLocalizedMessage( PickupMessageClass, 0, None, None, Self.Class);
01311					
01312					Copy.PlaySound (PickupSound);
01313					if ( Level.Game.Difficulty > 1 )
01314						Other.MakeNoise(0.1 * Level.Game.Difficulty);
01315					Pawn(Other).AcquireInventory(Copy);
01316	
01317					if(!Pawn(Other).IsInState('PlayerSwimming'))
01318						Copy.GotoState('Active');
01319				}
01320			}
01321		}
01322	
01323	begin:
01324	}
01325	
01326	
01327	//-----------------------------------------------------------------------------
01328	//
01329	// State Settling
01330	//
01331	// Weapon has hit ground, settle into rest position/orientation
01332	//-----------------------------------------------------------------------------
01333	state Settling
01334	{
01335		function BeginState()
01336		{
01337			SetCollision(true, false, false);
01338			bCollideWorld = true;
01339	
01340			SetOwner(None);	// Allow pickup now that it's just waiting to come to rest
01341			bFixedRotationDir = false;
01342			bRotateToDesired = true;
01343	
01344			if (FRand() < 0.5)
01345				DesiredRotation.Pitch = 49152;
01346			else
01347				DesiredRotation.Pitch = 16384;
01348			DesiredRotation.Yaw = Rotation.Yaw;
01349			DesiredRotation.Roll = 16384 + FRand()*32768;
01350			RotationRate.Pitch = 40000;
01351			RotationRate.Yaw = 0;
01352			RotationRate.Roll = 40000;
01353			SetPhysics(PHYS_Falling);
01354			bBounce = true;
01355		}
01356		
01357		function EndState()
01358		{
01359			SetCollision(false, false, false);
01360			bCollideWorld = false;
01361			bBounce = false;
01362			bFixedRotationDir = false;
01363		}
01364	
01365		function Landed(vector HitNormal, actor HitActor)
01366		{
01367			HitWall(HitNormal, HitActor);
01368		}
01369	
01370		//============================================================================
01371		//
01372		// CanBeUsed (from Pickup)
01373		//
01374		//============================================================================
01375		function bool CanBeUsed(Actor Other)
01376		{
01377			if(Other.IsA('PlayerPawn') && Other.AnimProxy != None)
01378			{
01379				if(Other.AnimProxy.WantsToPickup(self))
01380				{
01381					return(true);
01382				}
01383			}
01384			return(false);
01385		}
01386	
01387		function HitWall(vector HitNormal, actor HitWall)
01388		{
01389			local float speed;
01390			local EMatterType matter;
01391	
01392			speed = VSize(velocity);
01393	
01394			// Play hit or drop sound
01395			if (HitNormal.Z > 0.8)
01396			{	// Hit floor
01397				if (!bPlayedDropSound && !Region.Zone.bWaterZone)
01398				{	// Play twice
01399					bPlayedDropSound=true;
01400					PlaySound(DropSound, SLOT_Interact);
01401					if (Instigator != None)
01402						MakeNoise(1.0);
01403				}
01404			}
01405			else if (speed > 300)
01406			{	// Hit wall fast
01407				if (HitMatterSoundCount<3)
01408				{
01409					HitMatterSoundCount++;
01410					matter = MatterTrace(Location-HitNormal*30, Location, 20);
01411					PlayHitMatterSound(matter);
01412				}
01413			}
01414	
01415			if((HitNormal.Z > 0.8) && (speed < 60))
01416			{
01417				if(DesiredRotation.Roll ~= Rotation.Roll
01418					&& DesiredRotation.Pitch ~= Rotation.Pitch)
01419				{
01420					SetPhysics(PHYS_None);
01421					bBounce = false;
01422					bFixedRotationDir = false;
01423	
01424					GotoState('Pickup');
01425				}
01426				else
01427				{
01428					SetPhysics(PHYS_Falling);
01429					Velocity.Z = 60;
01430				}
01431			}
01432			else
01433			{
01434				SetPhysics(PHYS_Falling);
01435				Velocity = 0.55 * (Velocity - 2 * HitNormal * (Velocity Dot HitNormal));
01436			}
01437		}
01438	
01439		function Touch(Actor Other)
01440		{
01441			local inventory Copy;
01442	
01443			if(Other.IsA('Pawn'))
01444			{
01445				if(Pawn(Other).Health > 0 && Pawn(Other).CanPickUp(self))
01446				{
01447					if (Level.Game.LocalLog != None)
01448						Level.Game.LocalLog.LogPickup(Self, Pawn(Other));
01449					if (Level.Game.WorldLog != None)
01450						Level.Game.WorldLog.LogPickup(Self, Pawn(Other));
01451					Copy = SpawnCopy(Pawn(Other));
01452	
01453					if(PickupMessageClass == None)
01454						Pawn(Other).ClientMessage(PickupMessage, 'Pickup');
01455					else
01456						Pawn(Other).ReceiveLocalizedMessage( PickupMessageClass, 0, None, None, Self.Class);
01457	
01458					Copy.PlaySound (PickupSound);
01459					if ( Level.Game.Difficulty > 1 )
01460						Other.MakeNoise(0.1 * Level.Game.Difficulty);
01461					Pawn(Other).AcquireInventory(Copy);
01462	
01463					if(!Pawn(Other).IsInState('PlayerSwimming'))
01464						Copy.GotoState('Active');
01465				}
01466			}
01467		}
01468	
01469	}
01470	
01471	//=============================================================================
01472	//
01473	// StartAttack
01474	//
01475	//=============================================================================
01476	
01477	function StartAttack()
01478	{
01479	}
01480	
01481	//=============================================================================
01482	//
01483	// FinishAttack
01484	//
01485	//=============================================================================
01486	
01487	function FinishAttack()
01488	{
01489	}
01490	
01491	//=============================================================================
01492	//
01493	// DropFrom
01494	//
01495	//=============================================================================
01496	
01497	function DropFrom(vector StartLocation)
01498	{
01499		bCollideWorld = true;
01500	
01501		if(!SetLocation(StartLocation))
01502		{
01503			return;
01504		}
01505			
01506		SetPhysics(PHYS_Falling);
01507		BecomePickup();
01508		SetCollision(true, false, false);
01509		SetOwner(None);
01510		AmbientSound = None;
01511		
01512		GotoState('Drop');
01513	}
01514	
01515	simulated function TweenToStill();
01516	
01517	simulated function bool ClientFire( float Value )
01518	{
01519		return true;
01520	}
01521	
01522	simulated function bool ClientAltFire( float Value )
01523	{
01524		return true;
01525	}
01526	
01527	function ForceFire();
01528	function ForceAltFire();
01529	
01530	//=============================================================================
01531	//
01532	// ClearSwipeArray
01533	//
01534	//=============================================================================
01535	function ClearSwipeArray()
01536	{
01537		local int i;
01538		for(i = 0; i < HitCount; i++)
01539		{
01540			SwipeHits[i].Actor = None;
01541			SwipeHits[i].LowMask = 0;
01542			SwipeHits[i].HighMask = 0;
01543		}
01544	}
01545	
01546	//=============================================================================
01547	//
01548	// SwipeArrayCheck
01549	//
01550	// This maintains an array of actors (and joints within those actors)
01551	// that are struck by the swipe.  Duplicates are not allowed.
01552	// 
01553	// The original intention for this was to not allow a given joint to be hit
01554	// more than once, but to allow multiple joints within an actor to be hit.
01555	// However, for gameplay purposes, this now ignores the joints and only
01556	// allows each Actor to be struck once, regardless of the number of joints
01557	// struck in the swipe.
01558	//=============================================================================
01559	
01560	function bool SwipeArrayCheck(Actor A, int LowMask, int HighMask)
01561	{
01562		local int i;
01563		local Pawn P;
01564	
01565		// Check if this actor is valid to be struck
01566		if(A == Owner || A.Owner == Owner || A == self)
01567		{
01568			return(false);
01569		}
01570	
01571		if (!A.bSweepable)
01572			return false;
01573	
01574		// Check this actor against the SwipeHit array
01575		for(i = 0; i < HitCount; i++)
01576		{
01577			if(SwipeHits[i].Actor == A)
01578			{ // Found this actor in the list
01579				return(false);
01580			}
01581		}
01582		
01583		// The actor/joint combo wasn't in the list, so add it
01584		for(i = 0; i < HitCount; i++)
01585		{
01586			if(SwipeHits[i].Actor == None)
01587			{
01588				SwipeHits[i].Actor = A;
01589				SwipeHits[i].LowMask = LowMask;
01590				SwipeHits[i].HighMask = HighMask;
01591	
01592				if(A.Owner != None && !A.IsA('Weapon'))
01593				{ // Also add this actor's owner to the list (for shields...weapons owners are NOT added to the list)
01594					SwipeArrayCheck(A.Owner, 0, 0);
01595				}
01596	
01597				if(A.IsA('Pawn'))
01598				{ // Struck flesh before a weapon/shield, so add both to the swipe array list so that those aren't hit this swipe
01599					P = Pawn(A);
01600	
01601					if(P.Weapon != None)
01602					{
01603						SwipeArrayCheck(P.Weapon, 0, 0);
01604					}
01605					if(P.Shield != None)
01606					{
01607						SwipeArrayCheck(P.Shield, 0, 0);
01608					}
01609				}
01610	
01611				return(true);
01612			}		
01613		}
01614		
01615	//	SLog("WARNING:  SwipeCheck actor count exceeded.");
01616		
01617		return(false);	
01618	}
01619	
01620	//=============================================================================
01621	//
01622	// DoWeaponSwipe
01623	//
01624	// Returns true if the swipe can continue, false if the swipe should stop
01625	//=============================================================================
01626	
01627	function bool DoWeaponSwipe(Actor A, int LowMask, int HighMask, vector HitLoc, vector HitNorm, vector Momentum)
01628	{
01629		local int j;
01630		local int DamageAmount;
01631		local bool rtn;
01632	
01633		rtn = true; // default to allowing the swipe to continue
01634	
01635		if(Owner != None && Pawn(Owner) != None && !Pawn(Owner).AllowWeaponToHitActor(self, A))
01636		{
01637			return(true);
01638		}
01639	
01640	/*
01641		if(A.CheckDefending())
01642		{
01643			return(true);
01644		}
01645	*/
01646		if (Level.Game.bTeamGame && Pawn(A)!=None && Pawn(Owner)!=None && Pawn(A).PlayerReplicationInfo.Team != 255 &&
01647			Pawn(A).PlayerReplicationInfo.Team == Pawn(Owner).PlayerReplicationInfo.Team)
01648		{	// Don't hit teammates
01649			return true;
01650		}
01651	
01652		if(A.IsA('Shield') && Level.Game.bTeamGame && Pawn(A.Owner)!=None && Pawn(Owner)!=None 
01653			&& Pawn(A.Owner).PlayerReplicationInfo.Team != 255 
01654			&& Pawn(A.Owner).PlayerReplicationInfo.Team == Pawn(Owner).PlayerReplicationInfo.Team)
01655		{	// Don't hit teammates shields
01656			return true;
01657		}
01658	
01659		DamageAmount = CalculateDamage(A);
01660		if (DamageAmount == 0)
01661			return rtn;
01662	
01663		if (A.Skeletal != None)
01664		{
01665			if (LowMask==0 && HighMask==0)
01666			{
01667				rtn = A.JointDamaged(DamageAmount, Pawn(Owner), HitLoc, Momentum, DamageType, 0);
01668			}
01669			else
01670			{
01671				for (j=0; j<A.NumJoints(); j++)
01672				{
01673					if(((j < 32) && ((LowMask & (1 << j)) != 0))
01674						|| ((j >= 32) && (j < 64) && ((HighMask & (1 << (j - 32))) != 0)))
01675					{	
01676						if(!A.JointDamaged(DamageAmount, Pawn(Owner), HitLoc, Momentum, DamageType, j))
01677						{
01678							return(false);
01679						}
01680					}
01681				}
01682			}
01683		}
01684		else
01685		{ // Hit an actor that doesn't have a skeleton (probably the world)
01686	//		Slog("Hit: "$A);
01687			if (A.IsA('PolyObj') ||
01688				A.IsA('Mover') ||
01689				A.IsA('ParticleSystem') ||
01690				(A.IsA('Trigger') && Trigger(A).TriggerType==TT_Damage) )
01691				rtn = A.JointDamaged(DamageAmount, Pawn(Owner), HitLoc, Momentum, DamageType, 0);
01692			else
01693				rtn = false;
01694		}
01695	
01696		return(rtn);
01697	}
01698	
01699	//=============================================================================
01700	//
01701	// SpawnHitEffect
01702	//
01703	// Spawns an effect based upon what was struck
01704	//=============================================================================
01705	
01706	function SpawnHitEffect(vector HitLoc, vector HitNorm, int LowMask, int HighMask, Actor HitActor)
01707	{	
01708	}
01709	
01710	//=============================================================================
01711	//
01712	// PlaySwipeSound
01713	//
01714	//=============================================================================
01715	
01716	function PlaySwipeSound()
01717	{
01718		// If the player is bloodlusting, then play the bloodlust through air sounds
01719		if(Owner != None && Owner.IsA('PlayerPawn') && PlayerPawn(Owner).bBloodLust && NumThroughAirBerserkSounds > 0)
01720			PlaySound(ThroughAirBerserk[Rand(NumThroughAirBerserkSounds)], SLOT_None,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
01721		else
01722			PlaySound(ThroughAir[Rand(NumThroughAirSounds)], SLOT_None,,,, 1.0 + (FRand()-0.5)*2.0*PitchDeviation);
01723	}
01724	
01725	function StartDamageCheck();	//TEST
01726	
01727	//-----------------------------------------------------------------------------
01728	//
01729	// Swinging State
01730	//
01731	//-----------------------------------------------------------------------------
01732	
01733	state Swinging
01734	{
01735		function BeginState()
01736		{
01737			PlaySwipeSound();
01738			FrameOfAttackAnim=0;
01739		}
01740	
01741		// Called each frame of animation
01742		function FrameNotify(int framepassed)
01743		{
01744			local vector NewPos1, NewPos2, WeaponVector;
01745			NewPos1 = GetJointPos(SweepJoint1);
01746			NewPos2 = GetJointPos(SweepJoint2);
01747			WeaponVector = SweepVector * (VSize(NewPos2-NewPos1) + ExtendedLength);
01748	
01749			FrameSweep(framepassed, WeaponVector, lastpos1, lastpos2);
01750		}
01751	
01752		event FrameSwept(vector B1, vector E1, vector B2, vector E2)
01753		{
01754			local int LowMask,HighMask;
01755			local vector HitLoc, HitNorm, NewPos1, NewPos2;
01756			local vector Momentum;
01757			local actor A;
01758	
01759			// Update the weapon swipes here
01760	/*
01761			if(Swipe != None)
01762			{
01763				Swipe.CreateSwipeParticle(0.0, B1, E1, B2, E2);
01764			}
01765	*/
01766			// Now sweep these frame-rate independent coordinates
01767			Momentum = (E2 - E1) * Mass;
01768			foreach SweepActors(class'actor', A,
01769				B1, E1, B2, E2, WeaponSweepExtent, HitLoc, HitNorm, LowMask, HighMask)
01770			{
01771				if(SwipeArrayCheck(A, LowMask, HighMask))
01772				{ // First time hitting this actor and/or joint
01773					if(!DoWeaponSwipe(A, LowMask, HighMask, HitLoc, HitNorm, Momentum))
01774					{ // Hit something that should stop the attack
01775					}
01776					SpawnHitEffect(HitLoc, HitNorm, LowMask, HighMask, A);
01777				}
01778			}
01779	
01780			gB1 = B1;
01781			gE1 = E1;
01782			gB2 = B2;
01783			gE2 = E2;
01784		}
01785	
01786		function StartAttack()
01787		{
01788		}
01789	
01790		function ClearSwipeArray()
01791		{
01792			global.ClearSwipeArray();
01793		}
01794	
01795		//=========================================================================
01796		//
01797		// FinishAttack
01798		// 
01799		//=========================================================================
01800	
01801		function FinishAttack()
01802		{
01803			Disable('Tick');
01804			GotoState('Active');
01805		}
01806	
01807		//=========================================================================
01808		//
01809		// Tick
01810		// 
01811		//=========================================================================
01812	/*
01813		function Tick(float DeltaTime)
01814		{
01815			local int LowMask,HighMask;
01816			local vector HitLoc, HitNorm, NewPos1, NewPos2;
01817			local actor A;
01818			local vector Momentum;
01819	
01820			NewPos1 = GetJointPos(SweepJoint1);
01821			NewPos2 = GetJointPos(SweepJoint2);
01822	
01823			// Extend the weapon length if necessary
01824			if(ExtendedLength > 0)
01825			{			
01826				NewPos2 += Normal(NewPos2 - NewPos1) * ExtendedLength;
01827			}
01828	
01829			Momentum = (NewPos2 - lastPos2) * Mass;
01830	
01831			foreach SweepActors(class'actor', A,
01832				lastpos1, lastpos2, NewPos1, NewPos2, WeaponSweepExtent, HitLoc, HitNorm, LowMask, HighMask)
01833			{
01834				if(SwipeArrayCheck(A, LowMask, HighMask))
01835				{ // First time hitting this actor and/or joint
01836					if(!DoWeaponSwipe(A, LowMask, HighMask, HitLoc, HitNorm, Momentum))
01837					{ // Hit something that should stop the attack
01838					}
01839					SpawnHitEffect(HitLoc, HitNorm, LowMask, HighMask, A);
01840				}
01841			}
01842	
01843			lastpos1 = NewPos1;
01844			lastpos2 = NewPos2;
01845		}
01846	*/
01847	begin:
01848		Enable('Tick');		
01849	}
01850	
01851	//=============================================================================
01852	//
01853	// Debug
01854	//
01855	//=============================================================================
01856	
01857	simulated function Debug(Canvas canvas, int mode)
01858	{
01859		local vector pos1, pos2;
01860	
01861		Super.Debug(canvas, mode);
01862	
01863		Canvas.DrawText("MeleeWeapon:");
01864		Canvas.CurY -= 8;
01865		Canvas.DrawText("  bRenderedLastFrame: " $bRenderedLastFrame);
01866		Canvas.CurY -= 8;
01867		Canvas.DrawText("  ExpireTime: " $ExpireTime);
01868		Canvas.CurY -= 8;
01869		
01870		Canvas.DrawText("LastThrower: " $LastThrower);
01871		Canvas.CurY -= 8;
01872	
01873		Canvas.DrawLine3D(gB1, gE1, 155, 155, 0);
01874		Canvas.DrawLine3D(gB2, gE2, 255, 255, 0);
01875	/*
01876		if(GetStateName() == 'Swinging')
01877		{
01878			pos1 = GetJointPos(SweepJoint1);
01879			pos2 = GetJointPos(SweepJoint2);
01880	
01881			if(ExtendedLength > 0)
01882			{			
01883				pos2 += Normal(pos2 - pos1) * ExtendedLength;
01884			}
01885	
01886	//		Canvas.DrawLine3D(GetJointPos(SweepJoint1), lastpos1, 0, 255, 0);
01887	//		Canvas.DrawLine3D(GetJointPos(SweepJoint2), lastpos2, 0, 255, 0);
01888			Canvas.DrawTube(pos1, pos2, WeaponSweepExtent, WeaponSweepExtent, 0, 255, 0);
01889			Canvas.DrawTube(lastpos1, lastpos2, WeaponSweepExtent, WeaponSweepExtent, 0, 255, 0);
01890		}
01891	*/
01892	}
01893	
01894	defaultproperties
01895	{
01896	     ThrownDamageType=ThrownWeaponBlunt
01897	     WeaponSweepExtent=8.000000
01898	     SweepJoint2=1
01899	     ExtendedLength=10.000000
01900	     RunePowerRequired=40
01901	     RunePowerDuration=20.000000
01902	     SweepVector=(Y=1.000000)
01903	     PitchDeviation=0.090000
01904	     Icon=Texture'Engine.S_Weapon'
01905	     Texture=Texture'Engine.S_Weapon'
01906	     LODDistMax=4000.000000
01907	     LODCurve=LOD_CURVE_ULTRA_CONSERVATIVE
01908	     SoundRadius=38
01909	     CollisionHeight=10.000000
01910	     Mass=10.000000
01911	     Buoyancy=4.000000
01912	}

End Source Code