Engine
Class Weapon

source: C:\XIII\Engine\Classes\Weapon.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Inventory
         |
         +--Engine.Weapon
Direct Known Subclasses:XIIIWeapon

class Weapon
extends Engine.Inventory

//============================================================================= // Parent class of all weapons. //=============================================================================
Variables
 float AIRating
           used for shakes on AltFire
 Rotator AdjustedAim
           how far instant hit trace Altfires go (Units = Meters sorry for the non-metric system guys)
 class AltAmmoName
           Type of Alt ammo used.
 Ammunition AltAmmoType
           Inventory Alt Ammo being used.
 float AltFireNoise
           Noise made by the weapon when firing
 vector AltFireOffset
           Offset from first person eye position for projectile/trace start
 byte AltFlashCount
           when incremented, draw alt muzzle flash for current frame (on-line used)
 int AltPickupAmmoCount
           Amount of Alt ammo initially in pick-up item.
 byte AltReloadCount
           Amount of Alt ammo depletion before reloading. 0 if no reloading is done.
 float AltShakeCycles
           used for shakes on AltFire
 float AltShakeMag
           used for shakes on AltFire
 vector AltShakeSpeed
           used for shakes on AltFire
 float AltShakeTime
           used for shakes on AltFire
 vector AltShakeVert
           used for shakes on AltFire
 float AltTraceDist
           how far instant hit trace Altfires go (Units = Meters sorry for the non-metric system guys)
 vector AltViewFeedBack
           to make view change when altfiring, X = horiz, Y = Vert,
 class AmmoName
           Type of ammo used.
 Ammunition AmmoType
           Inventory Ammo being used.
 Texture CrossHair
           Crosshair Texture
 bool DBDual
           when incremented, reload for clients
 bool DBWeap
           when incremented, reload for clients
 name EmptyAltFiringAnim
           texture to use for Zoomed mode to show stability
 name EmptyFiringAnim
           texture to use for Zoomed mode to show stability
 vector FPMFRelativeLoc
           FirstPersonMuzzleFlash relative Location
 Rotator FPMFRelativeRot
           FirstPersonMuzzleFlash relative Rotation
 float FireNoise
           Noise made by the weapon when firing
 vector FireOffset
           Offset from first person eye position for projectile/trace start
 name FiringMode
           firing mode to use, sent to the pawn to play right anim
 InventoryAttachment FirstPersonMF
           FirstPerson Muzzle Flash actor
 class FirstPersonMFClass
           FirstPerson Muzzle Flash actor class
 byte FlashCount
           when incremented, draw muzzle flash for current frame (on-line used)
 float FlashTime
           time when muzzleflash will be cleared (set in RenderOverlays())
 name LoadedAltFiringAnim
           texture to use for Zoomed mode to show stability
 name LoadedFiringAnim
           texture to use for Zoomed mode to show stability
 Texture MFTexture
           first-person muzzle flash sprite
 string MeshName
           to allow dynamic load of mesh (optimize memory)
 string MessageNoAmmo
           Playing on Active Waiting
 Weapon MySlave
           the actor being the slave if bHaveSlave.
 name NextSlaveState
           Used to handle Salve unsynchronized behaviour
 int PickupAmmoCount
           Amount of ammo initially in pick-up item.
 float ReLoadNoise
           Noise made by the weapon when ReLoading
 byte ReloadClientCount
           when incremented, reload for clients
 byte ReloadCount
           Amount of ammo depletion before reloading. 0 if no reloading is done.
 int RumbleFXNum
           Rumble FX effect to use for this weapon.
 float ScopeFOV
           FOV to use in zoom
 float ShakeCycles
           used for shakes on Fire
 float ShakeMag
           used for shakes on Fire
 vector ShakeSpeed
           used for shakes on Fire
 float ShakeTime
           used for shakes on Fire/
 vector ShakeVert
           used for shakes on Fire
 float ShotTime
           How long we wait after a shoot to go again // Used by IA controllers
 Actor Silencer
           the silencer object to put on weapon.
 Weapon SlaveOf
           the actor being the master if bIsSlave.
 Texture StabilityTex
           texture to use for Zoomed mode to show stability
 float StopFiringTime
           repeater weapons use this
 float TraceAccuracy
           Accuracy of the traces (in 21211447f TraceDist)
 float TraceDist
           how far instant hit trace fires go (Units = Meters sorry for the non-metric system guys)
 vector ViewFeedBack
           to make view change when firing, X = horiz, Y = Vert,
 Emitter WRE
           WaterRingsEmmiter, to setup the HitSoundType on the emitter.
 Texture ZCrosshair
           texture to use for Zoomed Crosshair
 Texture ZCrosshairDot
           texture to use for Zoomed Crosshair (the dot)
 bool bAllowEmptyShot
           some weapons don't allow empty shot.
 bool bAllowShot
           lock Shot for Semi-auto weapons if keeping fire pressed (must press fire again)
 bool bAltEmptyShot
           True if we tried to Altshoot a weapon without ammo
 bool bAutoReload
           Should we reload just after firing ?
 bool bCanHaveSlave
           Can we have a slave ? (Dual weapons)
 bool bCanThrow
           if true, player can toss this weapon out
 bool bChangeWeapon
           Used in Active State
 bool bDrawAltMuzzleFlash
           enable first-person muzzle flash for AltFire
 bool bDrawCrosshairOutZoom
           To be used for sniping weapons (no crosshair if not in zoom)
 bool bDrawMuzzleFlash
           enable first-person muzzle flash
 bool bDrawZoomedCrosshair
           if we need to draw the zoomed crosshair (because Interaction draw after HUD = bug of zoomed CH masking everything else)
 bool bEmptyShot
           True if we tried to shoot a weapon without ammo
 bool bEnableSlave
           to allow use of Altfire to switch between single/dual weapon
 bForceFire, bForceAltFire
           Used to handle forcing fire in Finish
 bool bForceReload
           used to handle reload in Finish
 bool bHaveAltFire
           this weapon have a AltFire
 bool bHaveBoredSfx
           To enable bored effect
 bool bHaveScope
           Do we have a zoom on this weapon (used by Altfire)
 bool bHaveSlave
           do the weapon have a slave ? (Dual Weapons)
 bool bHeavyWeapon
           Used to slow pawn when holding this
 bool bIsSlave
           is this weapon a slave ? (dual Weapons)
 bool bMeleeWeapon
           Weapon is only a melee weapon
 bool bMuzzleFlash
           if !=0 show first-person muzzle flash
 bool bRapidFire
           used by pawn animations in determining firing animation, and for net replication
 bool bRendered
           used to be unhidden only when rendering overlays
 bool bSetFlashTime
           reset FlashTime clock when false
 bool bShouldGoThroughTraversable
           true if we want the shoots go through the XIIIMover with bTraversable=True
 bool bTraceBullets
           Do we trace bullets
 bool bUnderWaterWork
           true if the weapon works underwater.
 bool bUseSilencer
           true if the weapon can use the silencer.
 bool bZoomed
           to use zoom
 enum eWeaponHand
           used to be unhidden only when rendering overlays
 enum eWeaponMode
           used to be unhidden only when rendering overlays
 float fAltZoomValue[3]
           Values of the Fov factors for each levels of Alt zooming system
 float fTraceBulletCount
           to decide if we should trace the bullet using bool bTraceBullets
 float fVarAccuracy
           variable accuracy (low for First shot, up to TraceAccuracy in 5 shots)
 sound hActWaitSound
           Playing on Active Waiting
 sound hAltFireSound
           Playing on AltFire
 sound hFireSound
           Playing on Fire
 sound hNoAmmoSound
           Playing on EmptyFire
 sound hReloadSound
           Playing on Reload
 sound hSelectWeaponSound
           Playing on SelectWeapon
 sound hZoomSound
           Playing on Zooming (params for zoom/unzoom/stop)
 int iAltZoomLevel
           Number of zooming levels (for Alternative zooming system)
 int iBoredCount
           For special 'i'm bored' effect :)
 int iBurstCount
           to handle burst mode
 sWeaponModeSemiAuto, sWeaponModeBurst
           Rumble FX effect to use for this weapon.

States
PendingClientWeaponSet, ClientFiring, DownWeapon, Active, while, Reloading, Idle, NormalAltFire, NormalFire

Function Summary
 
simulated
AltFire(float Value)
     
/* AltFire()
Weapon mode change.
*/
 float AmmoStatus()
     
//_____________________________________________________________________________
//return percent of full ammo (0 to 1 range)
 
simulated
AnimEnd(int Channel)
 
simulated
BringUp()
     
//_____________________________________________________________________________
 
simulated
BringUpNoSlave()
     
//_____________________________________________________________________________
 void CauseAltFire()
 
simulated
ClientFinish()
 void ClientForceReload()
 void ClientReLoad()
     
//_____________________________________________________________________________
// Need this to force the server to reload.
 
simulated
ClientWeaponSet(bool bOptionalSet)
     
//_____________________________________________________________________________
// Compare self to current weapon.  If better than current weapon, then switch
 
simulated
DisplayDebug(Canvas Canvas, out float, out float)
     
//_____________________________________________________________________________
// list important controller attributes on canvas
 void DropFrom(vector StartLocation)
     
//_____________________________________________________________________________
// Toss this weapon out
 void Finish()
     
// Finish a sequence
 
simulated
Fire(float Value)
 
simulated
ForceReload()
     
/* Force reloading even though clip isn't empty.  Called by player controller exec function,
and implemented in idle state */
 string GetAmmoText(out int)
     
//_____________________________________________________________________________
 vector GetFireStart(vector X, vector Y, vector Z)
     
//_____________________________________________________________________________
simulated 
 vector GetFireStart(vector X, vector Y, vector Z)
     
//_____________________________________________________________________________
simulated 
 vector GetFireStart(vector X, vector Y, vector Z)
     
//_____________________________________________________________________________
simulated 
 
simulated
GiveAltAmmo(Pawn Other)
     
//_____________________________________________________________________________
// ELR ADD Possibility that PickUpAmmoCount < ReLoadCount (else Bug)
 void GiveAmmo(Pawn Other)
     
//_____________________________________________________________________________
 void GiveTo(Pawn Other)
     
//_____________________________________________________________________________
 bool HandlePickupQuery(Pickup Item)
     
//_____________________________________________________________________________
// If picking up another weapon of the same class, add its ammo.
// If ammo count was at zero, check if should auto-switch to this weapon.
 bool HasAltAmmo()
     
//_____________________________________________________________________________
 bool HasAmmo()
     
/*
simulated 
 bool HasAmmo()
     
/*
simulated 
 bool HasSilencer()
     
//_____________________________________________________________________________
 
simulated
IncrementAltFlashCount()
     
//_____________________________________________________________________________
//Tell WeaponAttachment to cause client side weapon firing effects
 
simulated
IncrementFlashCount()
     
//_____________________________________________________________________________
//Tell WeaponAttachment to cause client side weapon firing effects
// 473 
 
simulated
IncrementReloadClientCount()
     
//_____________________________________________________________________________
//Tell WeaponAttachment to cause client side weapon firing effects
 
simulated
LocalFire()
 bool NeedsToReload()
 void NewWeaponNotify(Pawn Other)
     
//_____________________________________________________________________________
 Weapon NextWeapon(Weapon CurrentChoice, Weapon CurrentWeapon)
     
//_____________________________________________________________________________
 Weapon PrevWeapon(Weapon CurrentChoice, Weapon CurrentWeapon)
     
//_____________________________________________________________________________
// Find the previous weapon (using the Inventory group)
 void ProjectileFire()
     
{
    if ( bZoomed )
      return (Instigator.Location + Instigator.EyePosition() + FireOffset.X * X);
    else
      return (Instigator.Location + Instigator.EyePosition() + FireOffset.X * X + FireOffset.Y * Y + FireOffset.Z * Z);
}
*/
 float RateSelf()
     
//_____________________________________________________________________________
// sets appropriate weapon configuration, and returns rating based on that configuration
 Weapon RecommendWeapon(out float)
 
simulated
RenderSlaveOverlays(Canvas Canvas)
     
//_____________________________________________________________________________
// If this is called then just setup pos & render because primary weapon is already rendered
 bool RepeatFire()
     
//**************************************************************************************
//
// Firing functions and states
//
 
simulated
RumbleFX()
     
//_____________________________________________________________________________
// Prototype
 void ServerAltFire()
 void ServerFire()
 void ServerForceReload()
 void ServerRapidFire()
 void ServerReLoad()
     
//_____________________________________________________________________________
// Need this to force the server to reload.
 void ServerStopFiring()
 
simulated
SetHand(float Hand)
     
//_____________________________________________________________________________
// set which hand is holding weapon
 void SetUpDual(Weapon Dual, Pawn other)
     
//_____________________________________________________________________________
 
simulated
SetupMuzzleFlash()
     
//_____________________________________________________________________________
 bool ShouldDrawCrosshair(optional Canvas)
     
//_____________________________________________________________________________
 
simulated
SlaveBringUp()
     
//_____________________________________________________________________________
 
simulated
SlaveFire()
     
//_____________________________________________________________________________
 void StaticParseDynamicLoading(LevelInfo MyLI)
     
//_____________________________________________________________________________
 float SwitchPriority()
     
// Return the switch priority of the weapon (normally AutoSwitchPriority, but may be
// modified by environment (or by other factors for bots)
 void TraceFire(float Accuracy, float YOffset, float ZOffset)
 void Transfer(Pawn Other)
     
//_____________________________________________________________________________
 Weapon WeaponChange(byte F)
     
//_____________________________________________________________________________
// Change weapon to that specificed by F matching inventory weapon's Inventory Group.
 Weapon WeaponSelect(byte F)
     
//_____________________________________________________________________________
// ELR New function from WeaponChange to avoid potential bugs (this is to be used for SelectWeapon bind)


State PendingClientWeaponSet Function Summary
 void PlayFiringSound(optional bool)
 bool PutDown()


State ClientFiring Function Summary
 void ClientWeaponSet()
     
/* PendingClientWeaponSet
Weapon on network client side may be set here by the replicated 
 void AltFire(float Value)
 void Fire(float Value)


State DownWeapon Function Summary
 bool PutDown()
 void ServerAltFire()
 void ServerFire()
 void AltFire(float Value)
 void Fire(float Value)


State Active Function Summary
 bool PutDown()
 void ServerAltFire()
 void ServerFire()
 void AltFire(float Value)
 void Fire(float Value)


State while Function Summary


State Reloading Function Summary
 bool PutDown()
 void ServerAltFire()
 void ServerFire()
 void AltFire(float Value)
 void Fire(float Value)
 void ClientForceReload()
 void ServerForceReload()


State Idle Function Summary
 bool PutDown()
 void ServerForceReload()


State NormalAltFire Function Summary
 void EndState()
 void AnimEnd(int Channel)
 void AltFire(float F)
 void Fire(float F)
 void ServerAltFire()
 void ServerFire()


State NormalFire Function Summary
 void EndState()
 void AnimEnd(int Channel)
 void AltFire(float F)
 void Fire(float F)
 void ServerAltFire()
 void ServerFire()



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 MASKED=1 COMPRESS=DXT1
00010	
00011	//_____________________________________________________________________________
00012	// Bools
00013	var bool bChangeWeapon;             // Used in Active State
00014	var bool bCanThrow;                 // if true, player can toss this weapon out
00015	var bool bRapidFire;                // used by pawn animations in determining firing animation, and for net replication
00016	var bool bForceReload;              // used to handle reload in Finish
00017	var bool bMeleeWeapon;              // Weapon is only a melee weapon
00018	var bool bForceFire, bForceAltFire; // Used to handle forcing fire in Finish
00019	var bool bHaveAltFire;              // this weapon have a AltFire
00020	var bool bEmptyShot;                // True if we tried to shoot a weapon without ammo
00021	var bool bAllowEmptyShot;           // some weapons don't allow empty shot.
00022	var bool bAllowShot;                // lock Shot for Semi-auto weapons if keeping fire pressed (must press fire again)
00023	var bool bHaveScope;                // Do we have a zoom on this weapon (used by Altfire)
00024	var bool bZoomed;                   // to use zoom
00025	var bool bDrawCrosshairOutZoom;     // To be used for sniping weapons (no crosshair if not in zoom)
00026	var bool bUnderWaterWork;           // true if the weapon works underwater.
00027	var bool bUseSilencer;              // true if the weapon can use the silencer.
00028	var bool bShouldGoThroughTraversable; // true if we want the shoots go through the XIIIMover with bTraversable=True
00029	var bool bTraceBullets;             // Do we trace bullets
00030	var bool bDrawZoomedCrosshair;      // if we need to draw the zoomed crosshair (because Interaction draw after HUD = bug of zoomed CH masking everything else)
00031	var bool bAutoReload;               // Should we reload just after firing ?
00032	var bool bAltEmptyShot;             // True if we tried to Altshoot a weapon without ammo
00033	var bool bDrawAltMuzzleFlash;       // enable first-person muzzle flash for AltFire
00034	var bool bHeavyWeapon;              // Used to slow pawn when holding this
00035	var bool bHaveBoredSfx;             // To enable bored effect
00036	var bool bCanHaveSlave;             // Can we have a slave ? (Dual weapons)
00037	var bool bHaveSlave;                // do the weapon have a slave ? (Dual Weapons)
00038	var bool bIsSlave;                  // is this weapon a slave ? (dual Weapons)
00039	var bool bEnableSlave;              // to allow use of Altfire to switch between single/dual weapon
00040	var bool bMuzzleFlash;              // if !=0 show first-person muzzle flash
00041	var bool bSetFlashTime;             // reset FlashTime clock when false
00042	var bool bDrawMuzzleFlash;          // enable first-person muzzle flash
00043	var bool bRendered;                 // used to be unhidden only when rendering overlays
00044	
00045	var enum eWeaponHand
00046	{
00047	    WHA_Fist,
00048	    WHA_1HShot,
00049	    WHA_2HShot,
00050	    WHA_Throw,
00051	    WHA_Deco,
00052	} WHand;                            // Weapon type (hand using) meant for animsations & restrictions
00053	var enum eWeaponMode
00054	{
00055	    WM_Auto,
00056	    WM_SemiAuto,
00057	    WM_Burst,
00058	} WeaponMode;                       // Weapon Mode for Semi-auto guns.
00059	
00060	//_____________________________________________________________________________
00061	// Weapon/ammo information:
00062	var class<ammunition> AmmoName;     // Type of ammo used.
00063	var class<ammunition> AltAmmoName;  // Type of Alt ammo used.
00064	var int PickupAmmoCount;            // Amount of ammo initially in pick-up item.
00065	var int AltPickupAmmoCount;         // Amount of Alt ammo initially in pick-up item.
00066	var travel ammunition AmmoType;     // Inventory Ammo being used.
00067	var travel ammunition	AltAmmoType;  // Inventory Alt Ammo being used.
00068	var travel byte ReloadCount;               // Amount of ammo depletion before reloading. 0 if no reloading is done.
00069	var travel byte AltReloadCount;            // Amount of Alt ammo depletion before reloading. 0 if no reloading is done.
00070	var string MeshName;                // to allow dynamic load of mesh (optimize memory)
00071	var actor Silencer;                 // the silencer object to put on weapon.
00072	var float StopFiringTime;           // repeater weapons use this
00073	var vector FireOffset;              // Offset from first person eye position for projectile/trace start
00074	var vector AltFireOffset;           // Offset from first person eye position for projectile/trace start
00075	var texture CrossHair;              // Crosshair Texture
00076	var float TraceAccuracy;            // Accuracy of the traces (in % of TraceDist)
00077	var int iBurstCount;                // to handle burst mode
00078	var float fVarAccuracy;             // variable accuracy (low for First shot, up to TraceAccuracy in 5 shots)
00079	var float ScopeFOV;                 // FOV to use in zoom
00080	var float ShotTime;                 // How long we wait after a shoot to go again // Used by IA controllers
00081	var name FiringMode;                // firing mode to use, sent to the pawn to play right anim
00082	var float FireNoise;                // Noise made by the weapon when firing
00083	var float ReLoadNoise;              // Noise made by the weapon when ReLoading
00084	var float AltFireNoise;             // Noise made by the weapon when firing
00085	var float fTraceBulletCount;        // to decide if we should trace the bullet using bool bTraceBullets
00086	var texture ZCrosshair;             // texture to use for Zoomed Crosshair
00087	var texture ZCrosshairDot;          // texture to use for Zoomed Crosshair (the dot)
00088	var texture StabilityTex;           // texture to use for Zoomed mode to show stability
00089	var name LoadedFiringAnim;
00090	var name EmptyFiringAnim;
00091	var name LoadedAltFiringAnim;
00092	var name EmptyAltFiringAnim;
00093	var vector ViewFeedBack;            // to make view change when firing, X = horiz, Y = Vert,
00094	var vector AltViewFeedBack;         // to make view change when altfiring, X = horiz, Y = Vert,
00095	var int iAltZoomLevel;              // Number of zooming levels (for Alternative zooming system)
00096	var float fAltZoomValue[3];         // Values of the Fov factors for each levels of Alt zooming system
00097	                                    // Should be -(85/factor - 90)/88 defaults to x3, x8 & x12
00098	var int iBoredCount;                // For special 'i'm bored' effect :)
00099	var int RumbleFXNum;                // Rumble FX effect to use for this weapon.
00100	var const localized string sWeaponModeAuto, sWeaponModeSemiAuto, sWeaponModeBurst;
00101	                                    // to display Weapon mode
00102	var InventoryAttachment FirstPersonMF;              // FirstPerson Muzzle Flash actor
00103	var class<InventoryAttachment> FirstPersonMFClass;  // FirstPerson Muzzle Flash actor class
00104	var() vector FPMFRelativeLoc;       // FirstPersonMuzzleFlash relative Location
00105	var() Rotator FPMFRelativeRot;      // FirstPersonMuzzleFlash relative Rotation
00106	var Emitter WRE;                    // WaterRingsEmmiter, to setup the HitSoundType on the emitter.
00107	// dual Weapon / Slave handling
00108	var Weapon MySlave;                 // the actor being the slave if bHaveSlave.
00109	var Weapon SlaveOf;                 // the actor being the master if bIsSlave.
00110	var name NextSlaveState;            // Used to handle Salve unsynchronized behaviour
00111	
00112	//_____________________________________________________________________________
00113	// SFXs Info
00114	var float ShakeMag;                 // used for shakes on Fire
00115	var float ShakeTime;                // used for shakes on Fire/
00116	var vector ShakeVert;               // used for shakes on Fire
00117	var vector ShakeSpeed;              // used for shakes on Fire
00118	var float ShakeCycles;              // used for shakes on Fire
00119	var float AltShakeMag;              // used for shakes on AltFire
00120	var float AltShakeTime;             // used for shakes on AltFire
00121	var vector AltShakeVert;            // used for shakes on AltFire
00122	var vector AltShakeSpeed;           // used for shakes on AltFire
00123	var float AltShakeCycles;           // used for shakes on AltFire
00124	
00125	//_____________________________________________________________________________
00126	// AI information
00127	var float AIRating;
00128	var float TraceDist;                // how far instant hit trace fires go (Units = Meters sorry for the non-metric system guys)
00129	var float AltTraceDist;             // how far instant hit trace Altfires go (Units = Meters sorry for the non-metric system guys)
00130	var Rotator AdjustedAim;
00131	
00132	//-----------------------------------------------------------------------------
00133	// Sound Assignments
00134	var() sound hFireSound;             // Playing on Fire
00135	var() sound hReloadSound;           // Playing on Reload
00136	var() sound hNoAmmoSound;           // Playing on EmptyFire
00137	var() sound hSelectWeaponSound;     // Playing on SelectWeapon
00138	var() sound hZoomSound;             // Playing on Zooming (params for zoom/unzoom/stop)
00139	//var() sound hShellsSound;           // Playing on spawning shells
00140	var() sound hAltFireSound;          // Playing on AltFire
00141	var() sound hActWaitSound;          // Playing on Active Waiting
00142	
00143	// messages
00144	var() Localized string MessageNoAmmo;
00145	
00146	//_____________________________________________________________________________
00147	// first person Muzzle Flash
00148	// weapon is responsible for setting and clearing bMuzzleFlash whenever it wants the
00149	// MFTexture drawn on the canvas (see RenderOverlays() )
00150	var float FlashTime;                    // time when muzzleflash will be cleared (set in RenderOverlays())
00151	var(MuzzleFlash) float MuzzleScale;     // scaling of muzzleflash
00152	var(MuzzleFlash) float FlashOffsetY;    // flash center offset from centered Y (as pct. of Canvas Y size)
00153	var(MuzzleFlash) float FlashOffsetX;    // flash center offset from centered X (as pct. of Canvas X size)
00154	var(MuzzleFlash) float FlashLength;     // How long muzzle flash should be displayed in seconds
00155	var(MuzzleFlash) float MuzzleFlashSize; // size of (square) texture
00156	var texture MFTexture;                  // first-person muzzle flash sprite
00157	var byte FlashCount;                    // when incremented, draw muzzle flash for current frame (on-line used)
00158	var byte AltFlashCount;                 // when incremented, draw alt muzzle flash for current frame (on-line used)
00159	var byte ReloadClientCount;             // when incremented, reload for clients
00160	
00161	var bool DBDual;
00162	var bool DBWeap;
00163	CONST BOREDSFXTHRESHOLD=10;
00164	
00165	//_____________________________________________________________________________
00166	// Network replication !! NATIVEREPLICATION !!
00167	replication
00168	{
00169	    // Things the server should send to the client.
00170	    reliable if( bNetOwner && bNetDirty && (Role==ROLE_Authority) )
00171	      AmmoType, ReloadCount, bAllowShot, AltAmmoType, AltReloadCount;
00172	
00173	    // Functions called by server on client
00174	    reliable if( Role==ROLE_Authority )
00175	      ClientWeaponSet, ClientForceReload, ClientReload;
00176	
00177	    // functions called by client on server
00178	    reliable if( Role<ROLE_Authority )
00179	      ServerForceReload, ServerFire, ServerAltFire, ServerRapidFire, ServerStopFiring, ServerReload;
00180	}
00181	
00182	//_____________________________________________________________________________
00183	Static function StaticParseDynamicLoading(LevelInfo MyLI)
00184	{
00185	    Log("Weapon StaticParseDynamicLoading class="$default.class);
00186	    Super.StaticParseDynamicLoading(MyLI);
00187	    if ( default.AmmoName != none )
00188	    {
00189	      MyLI.ForcedClasses[MyLI.ForcedClasses.Length] = default.AmmoName;
00190	      (default.AmmoName).Static.StaticParseDynamicLoading(MyLI);
00191	    }
00192	    if ( default.AltAmmoName != none )
00193	    {
00194	      MyLI.ForcedClasses[MyLI.ForcedClasses.Length] = default.AltAmmoName;
00195	      (default.AltAmmoName).Static.StaticParseDynamicLoading(MyLI);
00196	    }
00197	    MyLI.ForcedMeshes[MyLI.ForcedMeshes.Length] =
00198	      Mesh(DynamicLoadObject(default.MeshName, class'mesh'));
00199	}
00200	
00201	//_____________________________________________________________________________
00202	simulated event PostBeginPlay()
00203	{
00204	    // Convert TraceDist from meters to Unreal Engine Units
00205	    TraceDist = TraceDist * 200.0 / 2.54;
00206	    AltTraceDist = AltTraceDist * 200.0 / 2.54;
00207	//    Log("PostBeginPlay for"@self@"TraceDist="$TraceDist@"altTraceDist="$AltTraceDist);
00208	    Super.PostBeginPlay();
00209	    // Optimize using dynamicload (the real dynamicload should have happened in the mutator at the map init)
00210	    if ( (Mesh == none) && (MeshName != "") )
00211	    {
00212	      Mesh = Skeletalmesh(dynamicloadobject(MeshName, class'mesh')); // ParseDynMade
00213	      default.mesh = mesh;
00214	    }
00215	    if ( (AttachmentClass != none) && (AttachmentClass.default.StaticMeshName != "") )
00216	      DynamicLoadObject(AttachmentClass.default.StaticMeshName, class'StaticMesh'); // ParseDynLoad Made
00217	    iAltZoomLevel = 0; // Initialize because default is used for max zoom level
00218	    bRendered = false;
00219	    bHidden = true;
00220	    Refreshdisplaying();
00221	    if ( MySlave != none )
00222	    {
00223	      MySlave.bRendered = false;
00224	      MySlave.bHidden = true;
00225	      MySlave.RefreshDisplaying();
00226	    }
00227	}
00228	
00229	//_____________________________________________________________________________
00230	simulated event PostNetBeginPlay()
00231	{
00232	    if ( Role == ROLE_Authority )
00233	      return;
00234	    if ( (Instigator == None) || (Instigator.Controller == None) )
00235	      SetHand(0);
00236	    else
00237	      SetHand(Instigator.Controller.Handedness);
00238	}
00239	
00240	//_____________________________________________________________________________
00241	simulated function string GetAmmoText(out int bDrawbulletIcon);
00242	
00243	//_____________________________________________________________________________
00244	// Used to handle unsynchronized behaviour of slaves.
00245	// not simulated because should not be used in multiplayer
00246	event Timer2()
00247	{
00248	    switch (NextSlaveState)
00249	    {
00250	      Case 'BringUp':
00251	        bRendered = true;
00252	//        bHidden = false;
00253	//        RefreshDisplaying();
00254	        BringUp();
00255	        break;
00256	      Case 'Fire':
00257	        Fire(0.0);
00258	        break;
00259	    }
00260	}
00261	
00262	//_____________________________________________________________________________
00263	//Tell WeaponAttachment to cause client side weapon firing effects
00264	simulated function IncrementReloadClientCount()
00265	{
00266	    ReloadClientCount++;
00267	    if ( WeaponAttachment(ThirdPersonActor) != None )
00268	    {
00269	      WeaponAttachment(ThirdPersonActor).ReloadClientCount = ReloadClientCount;
00270	      WeaponAttachment(ThirdPersonActor).ThirdPersonReload();
00271	    }
00272	}
00273	
00274	//_____________________________________________________________________________
00275	//Tell WeaponAttachment to cause client side weapon firing effects
00276	// 473 µs
00277	simulated function IncrementFlashCount()
00278	{
00279	    FlashCount++;
00280	    if ( WeaponAttachment(ThirdPersonActor) != None )
00281	    {
00282	      WeaponAttachment(ThirdPersonActor).FlashCount = FlashCount;
00283	      WeaponAttachment(ThirdPersonActor).ThirdPersonEffects(); // 420 µs
00284	    }
00285	    RumbleFX();
00286	}
00287	
00288	//_____________________________________________________________________________
00289	//Tell WeaponAttachment to cause client side weapon firing effects
00290	simulated function IncrementAltFlashCount()
00291	{
00292	    AltFlashCount++;
00293	    if ( WeaponAttachment(ThirdPersonActor) != None )
00294	    {
00295	      WeaponAttachment(ThirdPersonActor).AltFlashCount = AltFlashCount;
00296	      WeaponAttachment(ThirdPersonActor).ThirdPersonAltEffects();
00297	    }
00298	    RumbleFX();
00299	}
00300	
00301	//_____________________________________________________________________________
00302	simulated function SetupMuzzleFlash();
00303	
00304	//_____________________________________________________________________________
00305	// Prototype
00306	simulated function RumbleFX();
00307	
00308	/* Force reloading even though clip isn't empty.  Called by player controller exec function,
00309	and implemented in idle state */
00310	simulated function ForceReload();
00311	
00312	function ServerForceReload()
00313	{
00314		bForceReload = true;
00315	}
00316	
00317	function ClientForceReload()
00318	{
00319		bForceReload = true;
00320	}
00321	
00322	//_____________________________________________________________________________
00323	// list important controller attributes on canvas
00324	simulated function DisplayDebug(Canvas Canvas, out float YL, out float YPos)
00325	{
00326	    local string T;
00327	    local name Anim;
00328	    local float frame,rate;
00329	
00330	//    Super.DisplayDebug(Canvas, YL, YPos);
00331	
00332	    Canvas.SetDrawColor(0,255,0);
00333	    Canvas.DrawText("WEAPON "$GetItemName(string(self)));
00334	    YPos += YL;
00335	    Canvas.SetPos(4,YPos);
00336	    Canvas.DrawText("     STATE: "$GetStateName()$" Timer: "$TimerCounter@"bChangeWeapon: "$bChangeWeapon, false);
00337	    YPos += YL;
00338	    Canvas.SetPos(4,YPos);
00339	
00340	    if ( Default.ReloadCount > 0 )
00341	    {
00342	      Canvas.DrawText("Reload Count: "$ReloadCount);
00343	      YPos += YL;
00344	      Canvas.SetPos(4,YPos);
00345	    }
00346	
00347	    if ( DrawType == DT_StaticMesh )
00348	      Canvas.DrawText("     StaticMesh "$StaticMesh$" AmbientSound "$AmbientSound, false);
00349	    else
00350	      Canvas.DrawText("     Mesh "$Mesh$" AmbientSound "$AmbientSound, false);
00351	    YPos += YL;
00352	    Canvas.SetPos(4,YPos);
00353	    if ( Mesh != None )
00354	    {
00355	      // mesh animation
00356	      GetAnimParams(0,Anim,frame,rate);
00357	      T = "     AnimSequence "$Anim$" Frame "$frame$" Rate "$rate;
00358	      if ( bAnimByOwner )
00359	        T= T$" Anim by Owner";
00360	      Canvas.DrawText(T, false);
00361	      YPos += YL;
00362	      Canvas.SetPos(4,YPos);
00363	    }
00364	
00365	    if ( AmmoType == None )
00366	    {
00367	      Canvas.DrawText("ERROR - NO AMMUNITION");
00368	      YPos += YL;
00369	      Canvas.SetPos(4,YPos);
00370	    }
00371	    else
00372	      AmmoType.DisplayDebug(Canvas,YL,YPos);
00373	}
00374	
00375	//_____________________________________________________________________________
00376	// Inventory travelling across servers.
00377	event TravelPostAccept()
00378	{
00379	    if ( Pawn(Owner) == None )
00380	    if ( Pawn(Owner).IsPlayerPawn() )
00381	    {
00382	      DebugLog(self@"TravelPostAccept");
00383	    }
00384	    Super.TravelPostAccept();
00385	      return;
00386	    if ( AmmoType == none )
00387	      GiveAmmo(Pawn(Owner));
00388	    if ( self == Pawn(Owner).Weapon )
00389	      BringUp();
00390	    else
00391	      GotoState('');
00392	    if ( Pawn(Owner).IsPlayerPawn() )
00393	    {
00394	      DebugLog("    after TravelPostAccept AmmoAmount="$AmmoType.AmmoAmount);
00395	    }
00396	}
00397	
00398	//_____________________________________________________________________________
00399	simulated event Destroyed()
00400	{
00401	    Super.Destroyed();
00402	    if( (Pawn(Owner)!=None) && (Pawn(Owner).Weapon == self) )
00403	      Pawn(Owner).Weapon = None;
00404	    else if( (Instigator!=None) && (Instigator.Weapon == self) )
00405	      Pawn(Owner).Weapon = None;
00406	
00407	    if ( bTossedOut )
00408	      return; // to avoid destroying our 'inventory' in a loop that would have memorized it (thus breaking the destruction loop)
00409	
00410	    if ( AmmoType != none )
00411	      AmmoType.Destroy();
00412	    if ( AltAmmoType != none )
00413	      AltAmmoType.Destroy();
00414	    if ( Silencer != None )
00415	      Silencer.Destroy();
00416	}
00417	
00418	//_____________________________________________________________________________
00419	function SetUpDual(Weapon Dual, Pawn other);
00420	
00421	//_____________________________________________________________________________
00422	function GiveTo(Pawn Other)
00423	{
00424	    Local Weapon Dual;
00425	
00426	    if ( Other.IsPlayerPawn() )
00427	    {
00428	      DebugLog("GIVETO (weapon)"@self@"to"@Other@"InventorySetUp ? "$Level.Game.bInventorySetUp);
00429	    }
00430	
00431	    // convert class if needed
00432	    if ( (PlayerTransferClass == none) && (PlayerTransferClassName != "") )
00433	      PlayerTransferClass = class<Inventory>(DynamicLoadObject(PlayerTransferClassName, class'class'));
00434	
00435	    if ( (PlayerTransferClass != none) && Other.IsHumanControlled() && !Other.Controller.bIsBot )
00436	    {
00437	      Dual = Weapon(Spawn(PlayerTransferClass,,,Other.Location));
00438	      Dual.GiveTo(Other);
00439	      Destroy();
00440	      return;
00441	    }
00442	    // convert class if needed
00443	    if ( (NonPlayerTransferClass == none) && (NonPlayerTransferClassName != "") )
00444	      NonPlayerTransferClass = class<Inventory>(DynamicLoadObject(NonPlayerTransferClassName, class'class'));
00445	
00446	    if ( (NonPlayerTransferClass != none) && (!Other.IsHumanControlled() || Other.Controller.bIsBot) )
00447	    {
00448	      Dual = Weapon(Spawn(NonPlayerTransferClass,,,Other.Location));
00449	      Dual.GiveTo(Other);
00450	      Destroy();
00451	      return;
00452	    }
00453	
00454	    Dual = Weapon(Other.FindInventoryType(class));
00455	    if ( Dual == none )
00456	    { // currently not owning weapon of this class, Std giveTo
00457	      NewWeaponNotify(Other);
00458	      Super.GiveTo(Other);
00459	      bTossedOut = false;
00460	      GiveAmmo(Other); // include GiveAltAmmo(Other);
00461	      if ( Default.ReloadCount > 0 )
00462	      {
00463	        if ( !Other.IsPlayerPawn() || !Level.bLonePlayer || Level.Game.bInventorySetUp || bMeleeWeapon )
00464	        {
00465	          if ( Other.IsPlayerPawn() )
00466	          {
00467	            DebugLog("       after GiveAmmo, Ammo Addin ReloadCount "$ReloadCount@"for"@self);
00468	          }
00469	          AmmoType.AddAmmo(ReloadCount);
00470	        }
00471	        else // don't add anything as we just received inventory from save/last map
00472	          if ( Other.IsPlayerPawn() )
00473	          {
00474	            DebugLog("       don't add ammo as we just travelled");
00475	          }
00476	      }
00477	      else
00478	      {
00479	        if ( !Other.IsPlayerPawn() || !Level.bLonePlayer || Level.Game.bInventorySetUp || bMeleeWeapon  )
00480	        {
00481	          if ( Other.IsPlayerPawn() )
00482	          {
00483	            DebugLog("       after GiveAmmo, Ammo Addin PickUpAmmoCount "$PickUpAmmoCount@"for"@self);
00484	          }
00485	          AmmoType.AddAmmo(PickUpAmmoCount);
00486	        }
00487	        else if ( Other.IsPlayerPawn() )// don't add anything as we just received inventory from save/last map
00488	        {
00489	          DebugLog("       don't add ammo as we just travelled");
00490	        }
00491	      }
00492	      ClientWeaponSet(true);
00493	      bRendered = false;
00494	      bHidden = true;
00495	      RefreshDisplaying();
00496	    }
00497	    else if (Dual == self)
00498	    { // can happen when loading a game w/ two weapons in inventory
00499	      if ( Other.IsPlayerPawn() )
00500	      {
00501	        DebugLog("END GIVETO (weapon) Cancel because Dual == self");
00502	      }
00503	      return;
00504	    }
00505	    else if ( Dual.bCanHaveSlave && !Dual.bHaveSlave && (Other.CanHoldDualWeapons() || !Level.Game.bInventorySetUp ) )
00506	    {
00507	      if ( Other.IsPlayerPawn() )
00508	      {
00509	        DebugLog("       Setting Up Dual for"@Dual@"&"@self);
00510	      }
00511	      SetUpDual(Dual, Other);
00512	    }
00513	    else if ( Dual == SlaveOf )
00514	    { // can happen when loading a game w/ two weapons in inventory
00515	      if ( Other.IsPlayerPawn() )
00516	      {
00517	        DebugLog("END GIVETO (weapon) Cancel because Dual == SlaveOf");
00518	      }
00519	      return;
00520	    }
00521	    else
00522	    {
00523	      if ( Other.IsPlayerPawn() )
00524	      {
00525	        DebugLog("       Already Owned"@dual@".bCanHaveSlave="$Dual.bCanHaveSlave@"., Take ammo then Destroy");
00526	      }
00527	      if ( ReloadCount != 0 )
00528	        Dual.AmmoType.AddAmmo(ReloadCount);
00529	      else
00530	        Dual.AmmoType.AddAmmo(PickupAmmoCount);
00531	      Destroy();
00532	    }
00533	    if ( Other.IsPlayerPawn() )
00534	    {
00535	      DebugLog("END GIVETO (Weapon)"@self@"(Owner="$Owner$") Ammo="@AmmoType@"(Owner="$AmmoType.Owner$")");
00536	    }
00537	}
00538	
00539	//_____________________________________________________________________________
00540	function Transfer(Pawn Other)
00541	{
00542	    Local Weapon Dual;
00543	
00544	    if ( Other.IsPlayerPawn() )
00545	    {
00546	      DebugLog("TRANSFER (weapon)"@self@"to"@Other);
00547	    }
00548	
00549	    // detach from old owner
00550	    if ( Instigator != none )
00551	    {
00552	  		DetachFromPawn(Instigator);
00553	      Instigator.DeleteInventory(self);
00554	    }
00555	
00556	    // Don't care about transfering ammo before weapon because GiveAmmo will reinsert them after weapon
00557	    if ( AmmoType != none )
00558	    {
00559	      if ( (AmmoType.AmmoAmount > 0) && (AmmoType.PickupClass != none) && (class<Ammo>(AmmoType.PickupClass) != none) ) // last test to avoid double message for ammos that have weapon as pickup (knives, grenads)
00560	      {
00561	        Other.PlaySound(AmmoType.PickupClass.default.PickupSound);
00562	        Other.ReceiveLocalizedMessage( AmmoType.PickupClass.default.MessageClass, 0, None, None, AmmoType.PickupClass );
00563	      }
00564	      if ( Other.IsHumanControlled() )
00565	      {
00566	        if ( default.ReloadCount != 0 )
00567	          AmmoType.AmmoAmount = 0; // for weapons w/ reload count, don't transfer more than reload count
00568	        // when transfering cap the amount of ammo pickable
00569	        else if ( (AmmoType.PickupClass != none) &&  (class<Ammo>(AmmoType.PickupClass) != none) )
00570	          AmmoType.AmmoAmount = class<Ammo>(AmmoType.PickupClass).default.AmmoAmount;
00571	        else
00572	          AmmoType.AmmoAmount = PickupAmmoCount;
00573	      }
00574	
00575	      AmmoType.Transfer(Other);
00576	      AmmoType = none;
00577	    }
00578	    if ( AltAmmoType != none )
00579	    {
00580	/* not done w/ alt ammo
00581	      // when transfering cap the amount of ammo pickable
00582	      if ( AltAmmoType.PickupClass != none )
00583	        AltAmmoType.AmmoAmount = class<Ammo>(AltAmmoType.PickupClass).default.AmmoAmount;
00584	      else
00585	        AltAmmoType.AmmoAmount = AltPickupAmmoCount;
00586	*/
00587	      if ( (AltAmmoType.AmmoAmount > 0) && (AltAmmoType.PickupClass != none) && (class<Ammo>(AltAmmoType.PickupClass) != none) ) // last test to avoid double message for ammos that have weapon as pickup (knives, grenads)
00588	      {
00589	        Other.PlaySound(AltAmmoType.PickupClass.default.PickupSound);
00590	        Other.ReceiveLocalizedMessage( AltAmmoType.PickupClass.default.MessageClass, 0, None, None, AltAmmoType.PickupClass );
00591	      }
00592	      AltAmmoType.Transfer(Other);
00593	      AltAmmoType = none;
00594	    }
00595	
00596	    // convert class if needed
00597	    if ( (PlayerTransferClass == none) && (PlayerTransferClassName != "") )
00598	      PlayerTransferClass = class<Inventory>(DynamicLoadObject(PlayerTransferClassName, class'class'));
00599	
00600	    if ( (PlayerTransferClass != none) && Other.IsHumanControlled() )
00601	    {
00602	      Dual = Weapon(Spawn(PlayerTransferClass,,,Other.Location));
00603	      if ( Default.ReloadCount != 0 )
00604	        Dual.ReloadCount = ReloadCount;
00605	      Dual.Transfer(Other);
00606	      Destroy();
00607	      return;
00608	    }
00609	    // convert class if needed
00610	    if ( (NonPlayerTransferClass == none) && (NonPlayerTransferClassName != "") )
00611	      NonPlayerTransferClass = class<Inventory>(DynamicLoadObject(NonPlayerTransferClassName, class'class'));
00612	
00613	    if ( (NonPlayerTransferClass != none) && !Other.IsHumanControlled() )
00614	    {
00615	      Dual = Weapon(Spawn(NonPlayerTransferClass,,,Other.Location));
00616	      if ( Default.ReloadCount != 0 )
00617	        Dual.ReloadCount = ReloadCount;
00618	      Dual.Transfer(Other);
00619	      Destroy();
00620	      return;
00621	    }
00622	
00623	    Dual = Weapon(Other.FindInventoryType(class));
00624	    if ( Dual == none )
00625	    { // currently not owning weapon of this class
00626	      NewWeaponNotify(Other);
00627	      Other.PlaySound(PickupClass.default.PickupSound);
00628	      Other.ReceiveLocalizedMessage( PickupClass.default.MessageClass, 0, None, None, PickupClass );
00629	//      GiveTo(Other);
00630	      Super.GiveTo(Other);
00631	      bTossedOut = false;
00632	      GiveAmmo(Other); // include GiveAltAmmo(Other);
00633	      ClientWeaponSet(true);
00634	      bRendered = false;
00635	      bHidden = true;
00636	      RefreshDisplaying();
00637	      if ( Other.IsPlayerPawn() )
00638	      {
00639	        DebugLog("         (weapon)"@self@"to"@Other@"GiveTo because not owned, AmmoAmount="$AmmoType.AmmoAmount);
00640	      }
00641	      if ( default.ReLoadCount != 0 )
00642	        AmmoType.AddAmmo(ReLoadCount);
00643	    }
00644	    else if ( Dual.bCanHaveSlave && !Dual.bHaveSlave && Other.CanHoldDualWeapons() )
00645	    {
00646	      if ( Other.IsPlayerPawn() )
00647	      {
00648	        DebugLog("         (weapon)"@self@"to"@Other@"GiveTo because Dual allowed");
00649	      }
00650	      Other.PlaySound(PickupClass.default.PickupSound);
00651	      Other.ReceiveLocalizedMessage( PickupClass.default.MessageClass, 0, None, None, PickupClass );
00652	      SetUpDual(Dual, Other);
00653	    }
00654	    else
00655	    {
00656	      if ( Other.IsPlayerPawn() )
00657	      {
00658	        DebugLog("         (weapon)"@self@"to"@Other@" Add ReloadCount then Destroy because owned");
00659	      }
00660	      if ( Default.ReloadCount > 0 )
00661	        Dual.AmmoType.AddAmmo(ReloadCount);
00662	      if ( Default.AltReloadCount > 0 )
00663	        Dual.AmmoType.AddAmmo(ReloadCount);
00664	      if ( class<Ammo>(Dual.AmmoType.PickupClass) == none )
00665	      { // Send message because picking weapon w/out ammo pickup
00666	        Other.PlaySound(PickupClass.default.PickupSound);
00667	        Other.ReceiveLocalizedMessage( PickupClass.default.MessageClass, 0, None, None, PickupClass );
00668	      }
00669	//      else // else do nothing as ammo should have been transfered w/ the ammotype
00670	//        Dual.AmmoType.AddAmmo(PickupAmmoCount);
00671	      Destroy();
00672	    }
00673	}
00674	
00675	//_____________________________________________________________________________
00676	function NewWeaponNotify(Pawn Other);
00677	
00678	/*
00679	//_____________________________________________________________________________
00680	// Weapon rendering
00681	// Draw first person view of inventory
00682	simulated event RenderOverlays( canvas Canvas )
00683	{
00684	    local rotator NewRot;
00685	    local bool bPlayerOwner;
00686	    local int Hand;
00687	    local PlayerController PlayerOwner;
00688	    local float ScaledFlash;
00689	
00690	    if ( Instigator == None )
00691	      return;
00692	
00693	    PlayerOwner = PlayerController(Instigator.Controller);
00694	
00695	    if ( PlayerOwner != None )
00696	    {
00697	      bPlayerOwner = true;
00698	      Hand = PlayerOwner.Handedness;
00699	      if (  Hand == 2 )
00700	        return;
00701	    }
00702	
00703	    if ( bMuzzleFlash && bDrawMuzzleFlash && (MFTexture != None) )
00704	    {
00705	      if ( !bSetFlashTime )
00706	      {
00707	        bSetFlashTime = true;
00708	        FlashTime = Level.TimeSeconds + FlashLength;
00709	      }
00710	      else if ( FlashTime < Level.TimeSeconds )
00711	        bMuzzleFlash = false;
00712	      if ( bMuzzleFlash )
00713	      {
00714	        ScaledFlash = 0.5 * MuzzleFlashSize * MuzzleScale * Canvas.ClipX/640.0;
00715	        Canvas.SetPos(0.5*Canvas.ClipX - ScaledFlash + Canvas.ClipX * Hand * FlashOffsetX, 0.5*Canvas.ClipY - ScaledFlash + Canvas.ClipY * FlashOffsetY);
00716	      //			DrawMuzzleFlash(Canvas);
00717	      }
00718	    }
00719	    else
00720	      bSetFlashTime = false;
00721	
00722	    SetLocation( Instigator.Location + Instigator.CalcDrawOffset(self) );
00723	    NewRot = Instigator.GetViewRotation();
00724	
00725	    if ( Hand == 0 )
00726	      newRot.Roll = 2 * Default.Rotation.Roll;
00727	    else
00728	      newRot.Roll = Default.Rotation.Roll * Hand;
00729	
00730	    setRotation(newRot);
00731	    Canvas.DrawActor(self, false, false);
00732	}
00733	*/
00734	
00735	//_____________________________________________________________________________
00736	// If this is called then just setup pos & render because primary weapon is already rendered
00737	simulated function RenderSlaveOverlays( canvas Canvas );
00738	
00739	//_____________________________________________________________________________
00740	simulated function bool ShouldDrawCrosshair(optional Canvas C)
00741	{
00742	    return ( !bZoomed && (Pawn(Owner).IsPlayerPawn() && !PlayerController(Pawn(Owner).Controller).bZooming) );
00743	}
00744	
00745	//_____________________________________________________________________________
00746	//return percent of full ammo (0 to 1 range)
00747	function float AmmoStatus()
00748	{
00749	    return float(AmmoType.AmmoAmount)/AmmoType.MaxAmmo;
00750	}
00751	
00752	//_____________________________________________________________________________
00753	native function bool HasAmmo();
00754	/*
00755	simulated function bool HasAmmo()
00756	{
00757	// should be useless
00758	  if ( AmmoType == none )
00759	    AmmoType = Ammunition(Pawn(Owner).FindInventoryType(AmmoName));
00760	
00761	  if ( MySlave != none )
00762	    return ( (AmmoType.AmmoAmount - MySlave.ReloadCount) > 0);
00763	  else if ( SlaveOf != none )
00764	    return ( (AmmoType.AmmoAmount - SlaveOf.ReloadCount) > 0);
00765	  else
00766	    return AmmoType.HasAmmo();
00767	}
00768	*/
00769	
00770	//_____________________________________________________________________________
00771	simulated function bool HasAltAmmo()
00772	{
00773	    if ( AltAmmoType == none )
00774	      return false;
00775	    return AltAmmoType.HasAmmo();
00776	}
00777	
00778	//_____________________________________________________________________________
00779	simulated function bool HasSilencer();
00780	
00781	//_____________________________________________________________________________
00782	// sets appropriate weapon configuration, and returns rating based on that configuration
00783	function float RateSelf()
00784	{
00785	    if ( !HasAmmo() )
00786	      return -2;
00787	    return (AIRating + FRand() * 0.05);
00788	}
00789	
00790	//_____________________________________________________________________________
00791	// If picking up another weapon of the same class, add its ammo.
00792	// If ammo count was at zero, check if should auto-switch to this weapon.
00793	function bool HandlePickupQuery( Pickup Item )
00794	{
00795	    local int OldAmmo, NewAmmo;
00796	    local Pawn P;
00797	
00798	//    if ( DBDual )
00799	    if ( Pawn(Owner).IsPlayerPawn() )
00800	    {
00801	      DebugLog(">> HandlePickupQuery for "$self);
00802	    }
00803	    if (Item.InventoryType == Class)
00804	    {
00805	      if ( Level.bLonePlayer && bCanHaveSlave && !bHaveSlave )
00806	      {
00807	        if ( DBDual ) Log(" > we are accepting picking up a weapon to be used for dual wielding");
00808	        return false;
00809	      }
00810	    }
00811	    if (Item.InventoryType == Class)
00812	    {
00813	      if ( (WeaponPickup(item) != none) && WeaponPickup(item).bWeaponStay && ((item.inventory == None) || item.inventory.bTossedOut) )
00814	        return true;
00815	      P = Pawn(Owner);
00816	      if ( AmmoType != None )
00817	      {
00818	        OldAmmo = AmmoType.AmmoAmount;
00819	        if ( Item.Inventory != None )
00820	          NewAmmo = Weapon(Item.Inventory).PickupAmmoCount;
00821	        else
00822	          NewAmmo = class<Weapon>(Item.InventoryType).Default.PickupAmmoCount;
00823	        if ( AmmoType.AddAmmo(NewAmmo) && (OldAmmo == 0)
00824	          && (P.Weapon.class != item.InventoryType) )
00825	          ClientWeaponSet(true);
00826	      }
00827	      Item.AnnouncePickup(Pawn(Owner));
00828	      return true;
00829	    }
00830	    if ( Inventory == None )
00831	      return false;
00832	    return Inventory.HandlePickupQuery(Item);
00833	}
00834	
00835	//_____________________________________________________________________________
00836	// set which hand is holding weapon
00837	simulated function SetHand(float Hand)
00838	{
00839	    Hand = 1;
00840	/*
00841	    if ( Hand == 2 )
00842	    {
00843	      PlayerViewOffset.Y = 0;
00844	      FireOffset.Y = 0;
00845	      return;
00846	    }
00847	
00848	    Mesh = Default.Mesh;
00849	    if ( Hand == 0 )
00850	    {
00851	      PlayerViewOffset.X = Default.PlayerViewOffset.X * 0.88;
00852	      PlayerViewOffset.Y = -0.2 * Default.PlayerViewOffset.Y;
00853	      PlayerViewOffset.Z = Default.PlayerViewOffset.Z * 1.12;
00854	    }
00855	    else
00856	    {
00857	      PlayerViewOffset.X = Default.PlayerViewOffset.X;
00858	      PlayerViewOffset.Y = Default.PlayerViewOffset.Y * Hand;
00859	      PlayerViewOffset.Z = Default.PlayerViewOffset.Z;
00860	    }
00861	    FireOffset.Y = Default.FireOffset.Y * Hand;
00862	*/
00863	}
00864	
00865	//_____________________________________________________________________________
00866	// Change weapon to that specificed by F matching inventory weapon's Inventory Group.
00867	simulated function Weapon WeaponChange( byte F )
00868	{
00869	    local Weapon newWeapon;
00870	
00871	    if ( InventoryGroup == F )
00872	    {
00873	      if ( !HasAmmo() )
00874	      {
00875	        if ( Inventory == None )
00876	          newWeapon = None;
00877	        else
00878	          newWeapon = Inventory.WeaponChange(F);
00879	        return newWeapon;
00880	      }
00881	      else
00882	        return self;
00883	    }
00884	    else if ( Inventory == None )
00885	      return None;
00886	    else
00887	      return Inventory.WeaponChange(F);
00888	}
00889	
00890	//_____________________________________________________________________________
00891	// ELR New function from WeaponChange to avoid potential bugs (this is to be used for SelectWeapon bind)
00892	simulated function Weapon WeaponSelect( byte F )
00893	{
00894	    local Weapon newWeapon;
00895	
00896	    if ( InventoryGroup == F )
00897	    {
00898	      if (!( (HasAmmo() || (bHaveAltFire && HasAltAmmo()) || (bHaveSlave && (MySlave.ReloadCount > 0)))
00899	        && !bIsSlave && !(Pawn(Owner).bHaveOnlyOneHandFree && (WHand == WHA_2HShot)) ))
00900	      {
00901	        if ( Inventory == None )
00902	          newWeapon = None;
00903	        else
00904	          newWeapon = Inventory.WeaponSelect(F);
00905	        return newWeapon;
00906	      }
00907	      else
00908	        return self;
00909	    }
00910	    else if ( Inventory == None )
00911	      return None;
00912	    else
00913	      return Inventory.WeaponSelect(F);
00914	}
00915	
00916	//_____________________________________________________________________________
00917	// Find the previous weapon (using the Inventory group)
00918	simulated function Weapon PrevWeapon(Weapon CurrentChoice, Weapon CurrentWeapon)
00919	{
00920	//	if ( AmmoType.HasAmmo() )
00921	    if ( (HasAmmo() || (bHaveAltFire && HasAltAmmo()) || (bHaveSlave && (MySlave.ReloadCount > 0)))
00922	      && !bIsSlave && !(Pawn(Owner).bHaveOnlyOneHandFree && (WHand == WHA_2HShot)) )
00923	    {
00924	      if ( (CurrentChoice == None) )
00925	      {
00926	        if ( CurrentWeapon != self )
00927	          CurrentChoice = self;
00928	      }
00929	      else if ( InventoryGroup == CurrentChoice.InventoryGroup )
00930	      {
00931	        if ( InventoryGroup == CurrentWeapon.InventoryGroup )
00932	        {
00933	          if ( (GroupOffset < CurrentWeapon.GroupOffset)
00934	            && (GroupOffset > CurrentChoice.GroupOffset) )
00935	            CurrentChoice = self;
00936	        }
00937	        else if ( GroupOffset > CurrentChoice.GroupOffset )
00938	          CurrentChoice = self;
00939	      }
00940	      else if ( InventoryGroup > CurrentChoice.InventoryGroup )
00941	      {
00942	        if ( (InventoryGroup < CurrentWeapon.InventoryGroup)
00943	          || (CurrentChoice.InventoryGroup > CurrentWeapon.InventoryGroup) )
00944	        CurrentChoice = self;
00945	      }
00946	      else if ( (CurrentChoice.InventoryGroup > CurrentWeapon.InventoryGroup)
00947	        && (InventoryGroup < CurrentWeapon.InventoryGroup) )
00948	        CurrentChoice = self;
00949	    }
00950	    if ( Inventory == None )
00951	      return CurrentChoice;
00952	    else
00953	      return Inventory.PrevWeapon(CurrentChoice,CurrentWeapon);
00954	}
00955	
00956	//_____________________________________________________________________________
00957	simulated function Weapon NextWeapon(Weapon CurrentChoice, Weapon CurrentWeapon)
00958	{
00959	//	if ( AmmoType.HasAmmo() )
00960	    if ( (HasAmmo() || (bHaveAltFire && HasAltAmmo()) || (bHaveSlave && (MySlave.ReloadCount > 0)) )
00961	      && !bIsSlave && !(Pawn(Owner).bHaveOnlyOneHandFree && (WHand == WHA_2HShot)) )
00962	    {
00963	      if ( (CurrentChoice == None) )
00964	      {
00965	        if ( CurrentWeapon != self )
00966	          CurrentChoice = self;
00967	      }
00968	      else if ( InventoryGroup == CurrentChoice.InventoryGroup )
00969	      {
00970	        if ( InventoryGroup == CurrentWeapon.InventoryGroup )
00971	        {
00972	          if ( (GroupOffset > CurrentWeapon.GroupOffset)
00973	            && (GroupOffset < CurrentChoice.GroupOffset) )
00974	            CurrentChoice = self;
00975	        }
00976	        else if ( GroupOffset < CurrentChoice.GroupOffset )
00977	          CurrentChoice = self;
00978	      }
00979	      else if ( InventoryGroup < CurrentChoice.InventoryGroup )
00980	      {
00981	        if ( (InventoryGroup > CurrentWeapon.InventoryGroup)
00982	          || (CurrentChoice.InventoryGroup < CurrentWeapon.InventoryGroup) )
00983	          CurrentChoice = self;
00984	      }
00985	      else if ( (CurrentChoice.InventoryGroup < CurrentWeapon.InventoryGroup)
00986	        && (InventoryGroup > CurrentWeapon.InventoryGroup) )
00987	        CurrentChoice = self;
00988	    }
00989	    if ( Inventory == None )
00990	      return CurrentChoice;
00991	    else
00992	      return Inventory.NextWeapon(CurrentChoice,CurrentWeapon);
00993	}
00994	
00995	simulated function AnimEnd(int Channel)
00996	{
00997		if ( Level.NetMode == NM_Client )
00998			PlayIdleAnim();
00999	}
01000	
01001	//_____________________________________________________________________________
01002	function GiveAmmo( Pawn Other )
01003	{
01004	    if ( AmmoName == None )
01005	      return;
01006	
01007	    if ( Default.ReloadCount != 0 )
01008	      ReLoadCount = min(ReLoadCount, PickUpAmmoCount);
01009	    else
01010	      ReLoadCount = PickUpAmmoCount;
01011	
01012	    AmmoType = Ammunition(Other.FindInventoryType(AmmoName));
01013	    if ( AmmoType == none )
01014	    {
01015	      if ( Other.IsPlayerPawn() )
01016	      {
01017	        DebugLog("GiveAmmo to"@other@", Ammo NOT Already owned, reseting to AmmoAmount = 0");
01018	      }
01019	      AmmoType = Spawn(AmmoName);	// Create ammo type required
01020	      Other.AddInventory(AmmoType);		// and add to player's inventory
01021	      AmmoType.AmmoAmount = 0;
01022	    }
01023	    else
01024	    { // AmmoType must be after self in inventory, can happen when grabing some ammo before weapon
01025	      if ( Other.IsPlayerPawn() )
01026	      {
01027	        DebugLog("GiveAmmo to"@other@", Ammo Already owned, not adding any ammo");
01028	      }
01029	
01030	      if ( Level.NetMode == NM_StandAlone )
01031	        Other.InsertInventory(AmmoType, self);
01032	/*
01033	      if ( Default.ReloadCount > 0 )
01034	      {
01035	        Log("GiveAmmo to"@other@", Ammo Already owned, Addin ReloadCount "$ReloadCount);
01036	        AmmoType.AddAmmo(ReloadCount);
01037	      }
01038	      else
01039	      {
01040	        Log("GiveAmmo to"@other@", Ammo Already owned, Addin PickUpAmmoCount "$PickUpAmmoCount);
01041	        AmmoType.AddAmmo(PickUpAmmoCount);
01042	      }
01043	*/
01044	    }
01045	    if ( bHaveAltFire )
01046	      GiveAltAmmo(other);
01047	}
01048	
01049	//_____________________________________________________________________________
01050	// ELR ADD Possibility that PickUpAmmoCount < ReLoadCount (else Bug)
01051	simulated function GiveAltAmmo( Pawn Other )
01052	{
01053	    if ( AltAmmoName == None )
01054	      return;
01055	    AltAmmoType = Ammunition(Other.FindInventoryType(AltAmmoName));
01056	    if ( AltAmmoType == none )
01057	    {
01058	      AltAmmoType = Spawn(AltAmmoName);	// Create ammo type required
01059	      Other.AddInventory(AltAmmoType);		// and add to player's inventory
01060	      AltAmmoType.AmmoAmount = AltPickUpAmmoCount;
01061	      if ( default.AltReloadCount != 0 )
01062	        AltReLoadCount = min(AltReLoadCount, AltPickUpAmmoCount);
01063	      else
01064	        AltReLoadCount = AltPickUpAmmoCount;
01065	    }
01066	    else
01067	    { // AmmoType must be after self in inventory, can happen when grabing some ammo before weapon
01068	      if ( Level.NetMode == NM_StandAlone )
01069	        Other.InsertInventory(AltAmmoType, self);
01070	      AltAmmoType.AddAmmo(AltPickUpAmmoCount);
01071	    }
01072	}
01073	
01074	// Return the switch priority of the weapon (normally AutoSwitchPriority, but may be
01075	// modified by environment (or by other factors for bots)
01076	simulated function float SwitchPriority()
01077	{
01078		local float temp;
01079	
01080		if ( !Instigator.IsHumanControlled() )
01081			return RateSelf();
01082		else if ( !AmmoType.HasAmmo() )
01083		{
01084			if ( Pawn(Owner).Weapon == self )
01085				return -0.5;
01086			else
01087				return -1;
01088		}
01089		else
01090	    	return 1;
01091	}
01092	
01093	//_____________________________________________________________________________
01094	// Compare self to current weapon.  If better than current weapon, then switch
01095	simulated function ClientWeaponSet(bool bOptionalSet)
01096	{
01097		local weapon W;
01098	
01099		Instigator = Pawn(Owner); //weapon's instigator isn't replicated to client
01100		if ( Instigator == None )
01101		{
01102			GotoState('PendingClientWeaponSet');
01103			return;
01104		}
01105		else if ( IsInState('PendingClientWeaponSet') )
01106			GotoState('');
01107		if ( Instigator.Weapon == self )
01108			return;
01109	
01110		if ( Instigator.Weapon == None )
01111		{
01112			Instigator.PendingWeapon = self;
01113			Instigator.ChangedWeapon();
01114			return;
01115		}
01116	
01117	    if ( bOptionalSet && Instigator.IsHumanControlled() )
01118			return;
01119	/* ELR XIIIUNUSED no auto switch
01120		if ( Instigator.Weapon.SwitchPriority() < SwitchPriority() )
01121		{
01122			W = Instigator.PendingWeapon;
01123			Instigator.PendingWeapon = self;
01124			GotoState('');
01125	
01126			if ( !Instigator.Weapon.PutDown() )
01127				Instigator.PendingWeapon = W;
01128			return;
01129		}
01130	*/
01131		GotoState('');
01132	}
01133	
01134	simulated function Weapon RecommendWeapon( out float rating )
01135	{
01136		local Weapon Recommended;
01137		local float oldRating, oldFiring;
01138		local int oldMode;
01139	
01140		if (Instigator.bisdead || Instigator.Controller.bIsBot || Instigator.Controller.Enemy == None)   //fouille sur cadavre,  bot ou basesoldier sans enemmi
01141	   {
01142	       if( HasAmmo() )
01143	           rating = AIRating;
01144	       else
01145	           rating=-1;
01146	   }
01147	   else if ( Instigator.IsHumanControlled() )   //XIII
01148	    	rating = SwitchPriority();
01149		else //basesoldier avec ennemi
01150		{
01151			rating = RateSelf();
01152			if (self == Instigator.Weapon && AmmoType.HasAmmo())
01153				rating += 0.05; // tend to stick with same weapon
01154			//rating += Instigator.Controller.WeaponPreference(self);
01155		}
01156		if ( inventory != None )
01157		{
01158			Recommended = inventory.RecommendWeapon(oldRating);
01159			if ( (Recommended != None) && (oldRating > rating) )
01160			{
01161				rating = oldRating;
01162				return Recommended;
01163			}
01164		}
01165		return self;
01166	}
01167	
01168	//_____________________________________________________________________________
01169	// Toss this weapon out
01170	function DropFrom(vector StartLocation)
01171	{
01172	    AIRating = Default.AIRating;
01173	    bMuzzleFlash = false;
01174	    if ( AmmoType != None )
01175	    {
01176	      PickupAmmoCount = AmmoType.AmmoAmount;
01177	      AmmoType.AmmoAmount = 0;
01178	    }
01179	    else if ( default.ReloadCount != 0 )
01180	    {
01181	      PickupAmmoCount = reloadCount;
01182	    }
01183	    GotoState('');
01184	    Super.DropFrom(StartLocation);
01185	}
01186	
01187	//_____________________________________________________________________________
01188	simulated function BringUp()
01189	{
01190	    if ( DBWeap )
01191	      Log(self@"BringUp");
01192	    if ( Instigator.IsHumanControlled() )
01193	    {
01194	      if( ! Instigator.Controller.bIsBot )
01195	      {
01196	        SetHand(PlayerController(Instigator.Controller).Handedness);
01197	        PlayerController(Instigator.Controller).EndZoom();
01198	      }
01199	    }
01200	    PlaySelect();
01201	    bRendered = true;
01202	//    bHidden = false;
01203	//    RefreshDisplaying();
01204	    GotoState('Active');
01205	    if ( (MySlave != none) && bEnableSlave )
01206	      MySlave.SlaveBringUp();
01207	}
01208	
01209	//_____________________________________________________________________________
01210	simulated function BringUpNoSlave()
01211	{
01212	//    Log("BringUp Call for"@self);
01213	
01214	    if ( Instigator.IsHumanControlled() )
01215	    {
01216	      SetHand(PlayerController(Instigator.Controller).Handedness);
01217	      PlayerController(Instigator.Controller).EndZoom();
01218	    }
01219	    PlaySelect();
01220	    GotoState('Active');
01221	}
01222	
01223	//_____________________________________________________________________________
01224	simulated function SlaveBringUp()
01225	{
01226	    NextSlaveState = 'BringUp';
01227	    SetTimer2(0.2 + fRand()*0.2, false);
01228	}
01229	
01230	//_____________________________________________________________________________
01231	// Need this to force the server to reload.
01232	function ServerReLoad()
01233	{
01234	//    Log(" ServerReLoad called");
01235	    GotoState('ReLoading');
01236	}
01237	
01238	//_____________________________________________________________________________
01239	// Need this to force the server to reload.
01240	function ClientReLoad()
01241	{
01242	//    Log(" ClientReLoad called");
01243	    GotoState('ReLoading');
01244	}
01245	
01246	//**************************************************************************************
01247	//
01248	// Firing functions and states
01249	//
01250	simulated function bool RepeatFire()
01251	{
01252		return bRapidFire;
01253	}
01254	
01255	function ServerStopFiring()
01256	{
01257		StopFiringTime = Level.TimeSeconds;
01258	}
01259	
01260	function ServerRapidFire()
01261	{
01262		ServerFire();
01263		if ( IsInState('NormalFire') )
01264			StopFiringTime = Level.TimeSeconds + 0.6;
01265	}
01266	
01267	function ServerFire()
01268	{
01269		if ( AmmoType == None )
01270		{
01271			// ammocheck
01272			log("WARNING "$self$" HAS NO AMMO!!!");
01273			GiveAmmo(Pawn(Owner));
01274		}
01275		if ( AmmoType.HasAmmo() )
01276		{
01277			GotoState('NormalFire');
01278			if ( default.ReloadCount > 0 )
01279	  		ReloadCount--;
01280			LocalFire();
01281			if ( AmmoType.bInstantHit )
01282				TraceFire(TraceAccuracy,0,0);
01283			else
01284				ProjectileFire();
01285		}
01286	}
01287	
01288	simulated function Fire( float Value )
01289	{
01290		if ( !AmmoType.HasAmmo() )
01291			return;
01292	
01293		if ( !RepeatFire() )
01294			ServerFire();
01295		else if ( StopFiringTime < Level.TimeSeconds + 0.3 )
01296		{
01297			StopFiringTime = Level.TimeSeconds + 0.6;
01298			ServerRapidFire();
01299		}
01300		if ( Role < ROLE_Authority )
01301		{
01302		  if ( default.ReloadCount > 0 )
01303	  		ReloadCount--;
01304			LocalFire();
01305			GotoState('ClientFiring');
01306		}
01307	}
01308	
01309	//_____________________________________________________________________________
01310	simulated function SlaveFire()
01311	{
01312	    NextSlaveState = 'Fire';
01313	    SetTimer2(0.1+fRand()*0.10, false);
01314	}
01315	
01316	simulated function LocalFire()
01317	{
01318		local PlayerController P;
01319	
01320	//	bPointing = true;
01321	
01322		if ( (Instigator != None) && Instigator.IsLocallyControlled() )
01323		{
01324			P = PlayerController(Instigator.Controller);
01325			if (P!=None)
01326			{
01327	//			if ( InstFlash != 0.0 )
01328	//				P.ClientInstantFlash( InstFlash, InstFog);
01329	
01330				P.ShakeView(ShakeTime, ShakeMag, ShakeVert, 120000, ShakeSpeed, 1);
01331			}
01332		}
01333	//	if ( Affector != None )
01334	//		Affector.FireEffect();
01335		PlayFiring();
01336	}
01337	
01338	function ServerAltFire()
01339	{
01340		if ( !IsInState('Idle') )
01341			GotoState('Idle');
01342	}
01343	
01344	/* AltFire()
01345	Weapon mode change.
01346	*/
01347	simulated function AltFire( float Value )
01348	{
01349		if ( !IsInState('Idle') )
01350			GotoState('Idle');
01351		ServerAltFire();
01352	}
01353	
01354	/*
01355	simulated function vector GetFireStart(vector X, vector Y, vector Z)
01356	{
01357		return (Instigator.Location + Instigator.EyePosition() + FireOffset.X * X + FireOffset.Y * Y + FireOffset.Z * Z);
01358	}
01359	*/
01360	native function vector GetFireStart(vector X, vector Y, vector Z);
01361	/*
01362	//_____________________________________________________________________________
01363	simulated function vector GetFireStart(vector X, vector Y, vector Z)
01364	{
01365	    if ( bZoomed )
01366	      return (Instigator.Location + Instigator.EyePosition() + FireOffset.X * X);
01367	    else
01368	      return (Instigator.Location + Instigator.EyePosition() + FireOffset.X * X + FireOffset.Y * Y + FireOffset.Z * Z);
01369	}
01370	*/
01371	
01372	function ProjectileFire()
01373	{
01374		local Vector Start, X,Y,Z;
01375	
01376		Owner.MakeNoise(1.0);
01377		GetAxes(Instigator.GetViewRotation(),X,Y,Z);
01378		Start = GetFireStart(X,Y,Z);
01379		AdjustedAim = Instigator.AdjustAim(AmmoType, Start, 0);
01380		AmmoType.SpawnProjectile(Start,AdjustedAim);
01381	}
01382	
01383	function TraceFire( float Accuracy, float YOffset, float ZOffset )
01384	{
01385		local vector HitLocation, HitNormal, StartTrace, EndTrace, X,Y,Z;
01386		local actor Other;
01387	
01388		Owner.MakeNoise(1.0);
01389		GetAxes(Instigator.GetViewRotation(),X,Y,Z);
01390		StartTrace = GetFireStart(X,Y,Z);
01391		AdjustedAim = Instigator.AdjustAim(AmmoType, StartTrace, 0);
01392		EndTrace = StartTrace + (YOffset + Accuracy * (FRand() - 0.5 ) ) * Y * 1000
01393			+ (ZOffset + Accuracy * (FRand() - 0.5 )) * Z * 1000;
01394		X = vector(AdjustedAim);
01395		EndTrace += (TraceDist * X);
01396		Other = Trace(HitLocation,HitNormal,EndTrace,StartTrace,True);
01397		AmmoType.ProcessTraceHit(self, Other, HitLocation, HitNormal, X,Y,Z);
01398	}
01399	
01400	simulated function bool NeedsToReload()
01401	{
01402		return ( bForceReload || (Default.ReloadCount > 0) && (ReloadCount == 0) );
01403	}
01404	
01405	// Finish a sequence
01406	function Finish()
01407	{
01408		local bool bForce, bForceAlt;
01409	
01410		if ( NeedsToReload() && AmmoType.HasAmmo() )
01411		{
01412			GotoState('Reloading');
01413			return;
01414		}
01415	
01416		bForce = bForceFire;
01417		bForceAlt = bForceAltFire;
01418		bForceFire = false;
01419		bForceAltFire = false;
01420	
01421		if ( bChangeWeapon )
01422		{
01423			GotoState('DownWeapon');
01424			return;
01425		}
01426	
01427		if ( (Instigator == None) || (Instigator.Controller == None) )
01428		{
01429			GotoState('');
01430			return;
01431		}
01432	
01433		if ( !Instigator.IsHumanControlled() )
01434		{
01435			if ( !AmmoType.HasAmmo() )
01436			{
01437				Instigator.Controller.SwitchToBestWeapon();
01438				if ( bChangeWeapon )
01439					GotoState('DownWeapon');
01440				else
01441					GotoState('Idle');
01442			}
01443			if ( Instigator.PressingFire() )
01444				Global.ServerFire();
01445			else if ( Instigator.PressingAltFire() )
01446				CauseAltFire();
01447			else
01448			{
01449				Instigator.Controller.StopFiring();
01450				GotoState('Idle');
01451			}
01452			return;
01453		}
01454		if ( !AmmoType.HasAmmo() && Instigator.IsLocallyControlled() )
01455		{
01456			// if local player, switch weapon
01457			Instigator.Controller.SwitchToBestWeapon();
01458			if ( bChangeWeapon )
01459			{
01460				GotoState('DownWeapon');
01461				return;
01462			}
01463			else
01464				GotoState('Idle');
01465		}
01466		if ( Instigator.Weapon != self )
01467			GotoState('Idle');
01468		else if ( (StopFiringTime > Level.TimeSeconds) || bForce || Instigator.PressingFire() )
01469			Global.ServerFire();
01470		else if ( bForceAlt || Instigator.PressingAltFire() )
01471			CauseAltFire();
01472		else
01473			GotoState('Idle');
01474	}
01475	
01476	function CauseAltFire()
01477	{
01478		Global.ServerAltFire();
01479	}
01480	
01481	simulated function ClientFinish()
01482	{
01483		if ( (Instigator == None) || (Instigator.Controller == None) )
01484		{
01485			GotoState('');
01486			return;
01487		}
01488		if ( NeedsToReload() && AmmoType.HasAmmo() )
01489		{
01490			GotoState('Reloading');
01491			return;
01492		}
01493		if ( !AmmoType.HasAmmo() )
01494		{
01495			Instigator.Controller.SwitchToBestWeapon();
01496			if ( !bChangeWeapon )
01497			{
01498				PlayIdleAnim();
01499				GotoState('Idle');
01500				return;
01501			}
01502		}
01503		if ( bChangeWeapon )
01504			GotoState('DownWeapon');
01505		else if ( Instigator.PressingFire() )
01506			Global.Fire(0);
01507		else
01508		{
01509			if ( Instigator.PressingAltFire() )
01510				Global.AltFire(0);
01511			else
01512			{
01513				PlayIdleAnim();
01514				GotoState('Idle');
01515			}
01516		}
01517	}
01518	
01519	//_____________________________________________________________________________
01520	state NormalFire
01521	{
01522	    function ServerFire()
01523	    {
01524	      bForceFire = true;
01525	    }
01526	
01527	    function ServerAltFire()
01528	    {
01529	      bForceAltFire = true;
01530	    }
01531	
01532	    function Fire(float F) {}
01533	    function AltFire(float F) {}
01534	
01535	    function AnimEnd(int Channel)
01536	    {
01537	      Finish();
01538	    }
01539	
01540	    function EndState()
01541	    {
01542	      StopFiringTime = Level.TimeSeconds;
01543	    }
01544	Begin:
01545	  Sleep(0.0);
01546	}
01547	
01548	//_____________________________________________________________________________
01549	state NormalAltFire
01550	{
01551	    function ServerFire()
01552	    {
01553	      bForceFire = true;
01554	    }
01555	
01556	    function ServerAltFire()
01557	    {
01558	      bForceAltFire = true;
01559	    }
01560	
01561	    function Fire(float F) {}
01562	    function AltFire(float F) {}
01563	
01564	    function AnimEnd(int Channel)
01565	    {
01566	      Finish();
01567	    }
01568	
01569	    function EndState()
01570	    {
01571	      StopFiringTime = Level.TimeSeconds;
01572	    }
01573	Begin:
01574	  Sleep(0.0);
01575	}
01576	
01577	/*
01578	Weapon is up and ready to fire, but not firing.
01579	*/
01580	state Idle
01581	{
01582		simulated function ForceReload()
01583		{
01584			ServerForceReload();
01585		}
01586	
01587		function ServerForceReload()
01588		{
01589			if ( AmmoType.HasAmmo() )
01590				GotoState('Reloading');
01591		}
01592	
01593		simulated function AnimEnd(int Channel)
01594		{
01595			PlayIdleAnim();
01596		}
01597	
01598		simulated function bool PutDown()
01599		{
01600			GotoState('DownWeapon');
01601			return True;
01602		}
01603	
01604	Begin:
01605	//	bPointing=False;
01606		if ( NeedsToReload() && AmmoType.HasAmmo() )
01607			GotoState('Reloading');
01608		if ( !AmmoType.HasAmmo() )
01609			Instigator.Controller.SwitchToBestWeapon();  //Goto Weapon that has Ammo
01610		if ( Instigator.PressingFire() ) Fire(0.0);
01611		if ( Instigator.PressingAltFire() ) AltFire(0.0);
01612		PlayIdleAnim();
01613	}
01614	
01615	state Reloading
01616	{
01617		function ServerForceReload() {}
01618		function ClientForceReload() {}
01619		function Fire( float Value ) {}
01620		function AltFire( float Value ) {}
01621	
01622		function ServerFire()
01623		{
01624			bForceFire = true;
01625		}
01626	
01627		function ServerAltFire()
01628		{
01629			bForceAltFire = true;
01630		}
01631	
01632		simulated function bool PutDown()
01633		{
01634			bChangeWeapon = true;
01635			return True;
01636		}
01637	
01638		simulated function BeginState()
01639		{
01640			if ( !bForceReload )
01641			{
01642				if ( Role < ROLE_Authority )
01643					ServerForceReload();
01644				else
01645					ClientForceReload();
01646			}
01647			bForceReload = false;
01648			PlayReloading();
01649		}
01650	
01651		simulated function AnimEnd(int Channel)
01652		{
01653			ReloadCount = Default.ReloadCount;
01654			if ( Role < ROLE_Authority )
01655				ClientFinish();
01656			else
01657				Finish();
01658		}
01659	}
01660	
01661	
01662	/* Active
01663	Bring newly active weapon up.
01664	The weapon will remain in this state while its selection animation is being played (as well as any postselect animation).
01665	While in this state, the weapon cannot be fired.
01666	*/
01667	state Active
01668	{
01669	  simulated function BringUp() { bRendered = true; }
01670		function Fire( float Value ) {}
01671		function AltFire( float Value ) {}
01672	
01673		function ServerFire()
01674		{
01675			bForceFire = true;
01676		}
01677	
01678		function ServerAltFire()
01679		{
01680			bForceAltFire = true;
01681		}
01682	
01683		simulated function bool PutDown()
01684		{
01685			local name anim;
01686			local float frame,rate;
01687			GetAnimParams(0,anim,frame,rate);
01688	  	bChangeWeapon = true;
01689			return True;
01690		}
01691	
01692		simulated function BeginState()
01693		{
01694			Instigator = Pawn(Owner);
01695			bForceFire = false;
01696			bForceAltFire = false;
01697			bChangeWeapon = false;
01698		}
01699	
01700		simulated function EndState()
01701		{
01702			bForceFire = false;
01703			bForceAltFire = false;
01704		}
01705	
01706		simulated function AnimEnd(int Channel)
01707		{
01708			if ( bChangeWeapon )
01709				GotoState('DownWeapon');
01710			if ( Owner == None )
01711			{
01712				log(self$" no owner");
01713				Global.AnimEnd(0);
01714				GotoState('');
01715			}
01716			else
01717			{
01718				if ( Role == ROLE_Authority )
01719					Finish();
01720				else
01721					ClientFinish();
01722			}
01723		}
01724	}
01725	
01726	/* DownWeapon
01727	Putting down weapon in favor of a new one.  No firing in this state
01728	*/
01729	State DownWeapon
01730	{
01731		function Fire( float Value ) {}
01732		function AltFire( float Value ) {}
01733	
01734		function ServerFire() {}
01735		function ServerAltFire() {}
01736	
01737		simulated function bool PutDown()
01738		{
01739			return true; //just keep putting it down
01740		}
01741	
01742		simulated function AnimEnd(int Channel)
01743		{
01744			Pawn(Owner).ChangedWeapon();
01745		}
01746	
01747		simulated function BeginState()
01748		{
01749			bChangeWeapon = false;
01750			bMuzzleFlash = false;
01751			TweenDown();
01752		}
01753	}
01754	
01755	//_____________________________________________________________________________
01756	//Fire on the client side. This state is only entered on the network client of the player that is firing this weapon.
01757	state ClientFiring
01758	{
01759	    function Fire( float Value ) {}
01760	    function AltFire( float Value ) {}
01761	
01762	    simulated function AnimEnd(int Channel)
01763	    {
01764	      ClientFinish();
01765	    }
01766	
01767	    simulated function EndState()
01768	    {
01769	      AmbientSound = None;
01770	      if ( RepeatFire() && !bPendingDelete )
01771	        ServerStopFiring();
01772	    }
01773	}
01774	
01775	/* PendingClientWeaponSet
01776	Weapon on network client side may be set here by the replicated function ClientWeaponSet(), to wait,
01777	if needed properties have not yet been replicated.  ClientWeaponSet() is called by the server to
01778	tell the client about potential weapon changes after the player runs over a weapon (the client
01779	decides whether to actually switch weapons or not.
01780	*/
01781	State PendingClientWeaponSet
01782	{
01783		simulated function Timer()
01784		{
01785			if ( Pawn(Owner) != None )
01786				ClientWeaponSet(false);
01787		}
01788	
01789		simulated function BeginState()
01790		{
01791			SetTimer(0.05, true);
01792		}
01793	
01794		simulated function EndState()
01795		{
01796			SetTimer(0.0, false);
01797		}
01798	}
01799	
01800	simulated function bool PutDown()
01801	{
01802		bChangeWeapon = true;
01803		return true;
01804	}
01805	
01806	simulated function zoom();
01807	
01808	//_____________________________________________________________________________
01809	simulated function PlayIdleAnim()
01810	{
01811	    if ( bHaveBoredSfx && (Instigator != none) && Instigator.IsPlayerPawn() && (iBoredCount > BOREDSFXTHRESHOLD) )
01812	    {
01813	      iBoredCount = 0;
01814	      if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone) )
01815	        Instigator.PlayRolloffSound(hActWaitSound, self, 0, int(Instigator.IsPlayerPawn()), 0 );
01816	      PlayAnim('WaitAct', 1.0, 0.3);
01817	    }
01818	    else
01819	      PlayAnim('Wait', 1.0, 0.3);
01820	}
01821	
01822	//_____________________________________________________________________________
01823	// 738 µs
01824	simulated function PlayFiring()
01825	{
01826	//    Log("PlayFiring call for"@self@"w/FiringMode="$FiringMode);
01827	    if ( HasAmmo() )
01828	      PlayAnim(LoadedFiringAnim, 1.0);
01829	    else
01830	      PlayAnim(EmptyFiringAnim, 1.0);
01831	
01832	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone) )
01833	      PlayFiringSound(HasSilencer()); // 184µs
01834	
01835	    if ( !HasAmmo() )
01836	      return;
01837	
01838	    IncrementFlashCount(); // 473 µs
01839	    if ( bDrawMuzzleflash )
01840	      SetUpMuzzleFlash();
01841	}
01842	
01843	//_____________________________________________________________________________
01844	simulated function PlayAltFiring()
01845	{
01846	//    Log("PlayAltFiring call for"@self@"w/FiringMode="$FiringMode);
01847	    if ( HasAltAmmo() )
01848	      PlayAnim(LoadedAltFiringAnim, 1.0);
01849	    else
01850	      PlayAnim(EmptyAltFiringAnim, 1.0);
01851	
01852	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01853	      PlayAltFiringSound();
01854	
01855	    if ( !HasAltAmmo() )
01856	      return;
01857	
01858	    IncrementAltFlashCount();
01859	    if ( bDrawAltMuzzleflash )
01860	      SetUpMuzzleFlash();
01861	}
01862	
01863	native function PlayFiringSound(optional bool bHasSilencer);
01864	/*
01865	//_____________________________________________________________________________
01866	simulated function PlayFiringSound()
01867	{
01868	    if ( bEmptyShot )
01869	      Instigator.PlayRolloffSound(hNoAmmoSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 0 );
01870	    else
01871	    {
01872	      if ( HasSilencer() )
01873	        Instigator.PlayRolloffSound(hFireSound, self, 1, int(Pawn(Owner).IsPlayerPawn()), 0 );
01874	      else
01875	        Instigator.PlayRolloffSound(hFireSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 0 );
01876	    }
01877	}
01878	*/
01879	
01880	//_____________________________________________________________________________
01881	simulated function PlayAltFiringSound()
01882	{
01883	    if ( bAltEmptyShot )
01884	      Instigator.PlayRolloffSound(hNoAmmoSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 0 );
01885	    else
01886	    {
01887	      if ( HasSilencer() )
01888	        Instigator.PlayRolloffSound(hAltFireSound, self, 1, int(Pawn(Owner).IsPlayerPawn()), 0 );
01889	      else
01890	        Instigator.PlayRolloffSound(hAltFireSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 0 );
01891	    }
01892	}
01893	
01894	//_____________________________________________________________________________
01895	simulated function TweenDown()
01896	{
01897	//    log("TweenDown call for"@self);
01898	    PlayAnim('Down', 1.0);
01899	}
01900	
01901	//_____________________________________________________________________________
01902	simulated function PlaySelect()
01903	{
01904	    if ( DBWeap )
01905	      log("PlaySelect call for"@self@"w/ mesh="$Mesh);
01906	    bForceFire = false;
01907	    bForceAltFire = false;
01908	    PlayAnim('Select',1.0);
01909	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01910	      Instigator.PlayRolloffSound(hSelectWeaponSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 0 );
01911	}
01912	
01913	//_____________________________________________________________________________
01914	simulated function PlayReloading()
01915	{
01916	    PlayAnim('ReLoad',1.0);
01917	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01918	      Instigator.PlayRolloffSound(hReloadSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 0 );
01919	    MakeNoise(ReLoadNoise);
01920	}
01921	
01922	//_____________________________________________________________________________
01923	// Reload Notifies
01924	simulated function FPSRelNote1()
01925	{
01926	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01927	      Instigator.PlayRolloffSound(hReloadSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 1 );
01928	}
01929	simulated function FPSRelNote2()
01930	{
01931	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01932	      Instigator.PlayRolloffSound(hReloadSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 2 );
01933	}
01934	simulated function FPSRelNote3()
01935	{
01936	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01937	      Instigator.PlayRolloffSound(hReloadSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 3 );
01938	}
01939	
01940	//_____________________________________________________________________________
01941	// Select Notifies
01942	simulated function FPSSelWPNote1()
01943	{
01944	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01945	      Instigator.PlayRolloffSound(hSelectWeaponSound, self, 1, int(Pawn(Owner).IsPlayerPawn()), 1 );
01946	}
01947	simulated function FPSSelWPNote2()
01948	{
01949	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01950	      Instigator.PlayRolloffSound(hSelectWeaponSound, self, 2, int(Pawn(Owner).IsPlayerPawn()), 2 );
01951	}
01952	simulated function FPSSelWPNote3()
01953	{
01954	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01955	      Instigator.PlayRolloffSound(hSelectWeaponSound, self, 3, int(Pawn(Owner).IsPlayerPawn()), 3 );
01956	}
01957	
01958	//_____________________________________________________________________________
01959	// Dry Notifies
01960	simulated function FPSDryNote1()
01961	{
01962	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01963	      Instigator.PlayRolloffSound(hNoAmmoSound, self, 1, int(Pawn(Owner).IsPlayerPawn()), 1 );
01964	}
01965	simulated function FPSDryNote2()
01966	{
01967	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01968	      Instigator.PlayRolloffSound(hNoAmmoSound, self, 2, int(Pawn(Owner).IsPlayerPawn()), 2 );
01969	}
01970	simulated function FPSDryNote3()
01971	{
01972	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01973	      Instigator.PlayRolloffSound(hNoAmmoSound, self, 3, int(Pawn(Owner).IsPlayerPawn()), 3 );
01974	}
01975	
01976	//_____________________________________________________________________________
01977	// Firing Notifies
01978	simulated function FPSFireNote1()
01979	{
01980	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01981	    {
01982	      if ( HasSilencer() )
01983	        Instigator.PlayRolloffSound(hFireSound, self, 1, int(Pawn(Owner).IsPlayerPawn()), 1 );
01984	      else
01985	        Instigator.PlayRolloffSound(hFireSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 1 );
01986	    }
01987	}
01988	simulated function FPSFireNote2()
01989	{
01990	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
01991	    {
01992	      if ( HasSilencer() )
01993	        Instigator.PlayRolloffSound(hFireSound, self, 1, int(Pawn(Owner).IsPlayerPawn()), 2 );
01994	      else
01995	        Instigator.PlayRolloffSound(hFireSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 2 );
01996	    }
01997	}
01998	simulated function FPSFireNote3()
01999	{
02000	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
02001	    {
02002	      if ( HasSilencer() )
02003	        Instigator.PlayRolloffSound(hFireSound, self, 1, int(Pawn(Owner).IsPlayerPawn()), 3 );
02004	      else
02005	        Instigator.PlayRolloffSound(hFireSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 3 );
02006	    }
02007	}
02008	
02009	//_____________________________________________________________________________
02010	// AltFiring Notifies
02011	simulated function FPSFireAltNote1()
02012	{
02013	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
02014	      Instigator.PlayRolloffSound(hAltFireSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 1 );
02015	}
02016	simulated function FPSFireAltNote2()
02017	{
02018	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
02019	      Instigator.PlayRolloffSound(hAltFireSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 2 );
02020	}
02021	
02022	//_____________________________________________________________________________
02023	// Active waiting Notifies
02024	simulated function FPSFireWaitActNote1()
02025	{
02026	    if ( Instigator.IsLocallyControlled() || (Level.NetMode == NM_StandAlone)  )
02027	      Instigator.PlayRolloffSound(hActWaitSound, self, 0, int(Pawn(Owner).IsPlayerPawn()), 1 );
02028	}
02029	
02030	defaultproperties
02031	{
02032	     bCanThrow=True
02033	     LoadedFiringAnim="Fire"
02034	     EmptyFiringAnim="Firevide"
02035	     LoadedAltFiringAnim="Fire"
02036	     EmptyAltFiringAnim="Firevide"
02037	     iAltZoomLevel=2
02038	     fAltZoomValue(0)=0.700800
02039	     fAltZoomValue(1)=0.884800
02040	     fAltZoomValue(2)=0.942300
02041	     sWeaponModeAuto="Auto"
02042	     sWeaponModeSemiAuto="Single"
02043	     sWeaponModeBurst="Burst"
02044	     ShakeMag=300.000000
02045	     shaketime=5.000000
02046	     ShakeVert=(Z=5.000000)
02047	     ShakeSpeed=(X=300.000000,Y=300.000000,Z=300.000000)
02048	     ShakeCycles=1.000000
02049	     AIRating=0.500000
02050	     TraceDist=1.270000
02051	     AltTraceDist=1.270000
02052	     MessageNoAmmo=" has no ammo."
02053	     MuzzleScale=1.000000
02054	     FlashLength=0.100000
02055	     InventoryGroup=1
02056	     PlayerViewOffset=(X=30.000000,Z=-5.000000)
02057	     AttachmentClass=Class'Engine.WeaponAttachment'
02058	     Icon=Texture'Engine.S_Weapon'
02059	     ItemName="Weapon"
02060	     bReplicateInstigator=True
02061	     bIgnoreDynLight=False
02062	     DrawType=DT_Mesh
02063	     SaturationDistance=800.000000
02064	     StabilisationDistance=3000.000000
02065	     StabilisationVolume=-10.000000
02066	}

End Source Code