class KFWeapon extends BaseKFWeapon abstract; #exec OBJ LOAD FILE=KF_9MMSnd.uax var() vector FirstPersonFlashlightOffset; var config enum KFScopeDetailSettings { KF_ModelScope, KF_TextureScope, KF_ModelScopeHigh, KF_None } KFScopeDetail; // Which detail setting for the scope var bool bHasScope; // true for any sniper weapons, aka they'll have scopes var(Zooming) float ZoomedDisplayFOVHigh; // What is the DisplayFOV when zoomed in on high scope detail setting var float ForceZoomOutTime; // When set the weapon will zoom out at this time var bool bForceLeaveIronsights; // Force the weapon out of ironsights on the next tick var(Zooming) float ForceZoomOutOnFireTime; // How long to wait after firing to force zoom out. If zero don't force zoom out on fire var(Zooming) float ForceZoomOutOnAltFireTime; // How long to wait after alt firing to force zoom out. If zero don't force zoom out on alt fire var() int MagCapacity; // How Much ammo this weapon can hold in its magazine var() float ReloadRate; var float ReloadTimer; var int MagAmmoRemaining;// How many bullets are left in the weapon's magazine var bool bSpeedMeUp; var bool bHasSecondaryAmmo; // This weapon has secondary ammo that we need to show on the hud var bool bReduceMagAmmoOnSecondaryFire; // Some weapons (like the M4 with M203 launcher) don't want to have primary ammo decrement when secondary fire occurs, so set this to false in that case var() sound ToggleSound; var() name ReloadAnim; var() float ReloadAnimRate; var() bool bHoldToReload; var bool bDoSingleReload; // The reload key has been released, but no rounds were added yet var int NumLoadedThisReload; // Tracks number or rounds reloaded this reload cycle var name FlashBoneName; var name WeaponReloadAnim; var() int MinimumFireRange; // Minimum distance to fire ...for avoiding LAW / Flamethrower casualties specifically. var() name ModeSwitchAnim; var() material HudImage; // What to display on the HUD, when this weapon isn't selected. var() material SelectedHudImage; // What to display on the HUD, when this weapon is selected. var bool bSteadyAim; // If Flicked, this weapon's accuracy is not affected by Movement. //var() float HealRate; //var transient float HealAccum; var bool bIsReloading, bReloadEffectDone; var() float Weight; // how much does it weigh var bool bKFNeverThrow; var bool bAmmoHUDAsBar; var bool bUseCombos; // Disable combos for the time being...Too iffy var bool bNoHit; // Hack for Syringe / Welder. var() bool bTorchEnabled; // just a hook for the pawn, and his light. Dualies and Single have this set to true. the other weapons dont. var bool bDualWeapon; // This weapon is a weapon where we are holding two of the same type of gun var int StoppingPower; // How much each fire of the gun slows you down. Always in negative numbers. // Iron sights aimin var bool bAimingRifle; // If the weapon is in ironsights var(Zooming) bool bHasAimingMode; // Whether or not this weapon can go into iron sights var() name IdleAimAnim; // Idle anim when aiming var(Zooming) sound AimInSound; // sound to play when going into aiming mode var(Zooming) sound AimOutSound; // sound to play when going into aiming mode var() class TacShineClass; var Actor TacShine; var Effect_TacLightProjector FlashLight; var float NextAmmoCheckTime,LastAmmoResult,LastHasGunMsgTime; // Keep track of what this weapon is doing on the client while we are throwing a grenade var() enum EClientGrenadeState { GN_None, GN_TempDown, GN_BringUp, } ClientGrenadeState; // this will always be none on the server // Used for putting down/bringing up the weapon when throwing a grenade var float QuickPutDownTime; var float QuickBringUpTime; var bool bConsumesPhysicalAmmo; var bool bShowPullOutHint; var float StandardDisplayFOV; // Stores the original nonadjusted display FOV (because we need to change the default, and want to know what the original default was) var bool bPendingFlashlight; var int NumClicks; // How many times the player has dry fired thier weapon var bool bModeZeroCanDryFire; // FireMode zero can dry fire/cause a reload // Added so we can do team specific sleeves, and later role specific - Ramm var() byte SleeveNum; // Which skin is the sleeve? var texture TraderInfoTexture; // Image for the trader menu var Vector EndBeamEffect; // Used by weapons with laser sites to designate the end of the laser beam var int SellValue; // Achievement Helpers var bool bPreviouslyDropped; var bool bIsTier2Weapon; var bool bIsTier3Weapon; var PlayerController Tier3WeaponGiver; // Dynamic Loading var string MeshRef; var array SkinRefs; var string SelectSoundRef; var string HudImageRef; var string SelectedHudImageRef; var int ReferenceCount; // Weapon DLC var int AppID; var int UnlockedByAchievement; replication { reliable if(Role == ROLE_Authority) MagAmmoRemaining, bForceLeaveIronsights; reliable if( bNetDirty && bNetOwner && (Role==ROLE_Authority) ) MagCapacity, SellValue; // TODO - which of these ACTUALLY need sending? reliable if(Role < ROLE_Authority) ReloadMeNow, ServerSetAiming, ServerSpawnLight, ServerRequestAutoReload, ServerInterruptReload; reliable if(Role == ROLE_Authority) ClientReload, ClientFinishReloading, ClientReloadEffects, FlashLight, ClientInterruptReload, ClientForceKFAmmoUpdate; reliable if(Role < ROLE_Authority) ServerChangeFireMode; } static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount) { local int i; if ( !bSkipRefCount ) { default.ReferenceCount++; } UpdateDefaultMesh(SkeletalMesh(DynamicLoadObject(default.MeshRef, class'SkeletalMesh'))); default.HudImage = texture(DynamicLoadObject(default.HudImageRef, class'texture')); default.SelectedHudImage = texture(DynamicLoadObject(default.SelectedHudImageRef, class'texture')); default.SelectSound = sound(DynamicLoadObject(default.SelectSoundRef, class'sound')); for ( i = 0; i < default.SkinRefs.Length; i++ ) { default.Skins[i] = Material(DynamicLoadObject(default.SkinRefs[i], class'Material')); } if ( KFWeapon(Inv) != none ) { Inv.LinkMesh(default.Mesh); KFWeapon(Inv).HudImage = default.HudImage; KFWeapon(Inv).SelectedHudImage = default.SelectedHudImage; KFWeapon(Inv).SelectSound = default.SelectSound; for ( i = 0; i < default.SkinRefs.Length; i++ ) { Inv.Skins[i] = default.Skins[i]; } } } static function bool UnloadAssets() { local int i; default.ReferenceCount--; log("UnloadAssets RefCount after: " @ default.ReferenceCount); UpdateDefaultMesh(none); default.HudImage = none; default.SelectedHudImage = none; for ( i = 0; i < default.SkinRefs.Length; i++ ) { default.Skins[i] = none; } return default.ReferenceCount == 0; } simulated function PreTravelCleanUp(){} simulated function AdjustIngameScope(){} simulated function bool ShouldDrawPortal(){return false;} simulated function DisplayDebug(Canvas Canvas, out float YL, out float YPos) { if ( FlashLight != none ) FlashLight.DisplayDebug(Canvas, YL, YPos); super.DisplayDebug(Canvas, YL, YPos); } simulated function PostBeginPlay() { if ( default.mesh == none ) { PreloadAssets(self, true); } // Weapon will handle FireMode instantiation Super.PostBeginPlay(); if ( Level.NetMode == NM_DedicatedServer ) return; if( !bHasScope ) { KFScopeDetail = KF_None; } InitFOV(); } // Set up the widescreen FOV values for this weapon simulated final function InitFOV() { local KFPlayerController KFPC; local float ResX, ResY; local float AspectRatio; KFPC = KFPlayerController(Level.GetLocalPlayerController()); if( KFPC == none ) { return; } ResX = float(GUIController(KFPC.Player.GUIController).ResX); ResY = float(GUIController(KFPC.Player.GUIController).ResY); AspectRatio = ResX / ResY; if ( KFPC.bUseTrueWideScreenFOV && AspectRatio >= 1.60 ) //1.6 = 16/10 which is 16:10 ratio and 16:9 comes to 1.77 { PlayerIronSightFOV = CalcFOVForAspectRatio(default.PlayerIronSightFOV); ZoomedDisplayFOV = CalcFOVForAspectRatio(default.ZoomedDisplayFOV); ZoomedDisplayFOVHigh = CalcFOVForAspectRatio(default.ZoomedDisplayFOVHigh); DisplayFOV = CalcFOVForAspectRatio(StandardDisplayFOV); default.DisplayFOV = DisplayFOV; AdjustIngameScope(); } else { PlayerIronSightFOV = default.PlayerIronSightFOV; ZoomedDisplayFOV = default.ZoomedDisplayFOV; ZoomedDisplayFOVHigh = default.ZoomedDisplayFOVHigh; DisplayFOV = StandardDisplayFOV; default.DisplayFOV = DisplayFOV; AdjustIngameScope(); } } // For a given 4/3 based FOV, give the proper FOV for the current // aspect ratio simulated final function float CalcFOVForAspectRatio(float OriginalFOV) { local float ResX, ResY; local float AspectRatio; local float OriginalAspectRatio; local float NewFOV; local KFPlayerController KFPC; KFPC = KFPlayerController(Level.GetLocalPlayerController()); if( KFPC != none && KFPC.bUseTrueWideScreenFOV ) { ResX = float(GUIController(KFPC.Player.GUIController).ResX); ResY = float(GUIController(KFPC.Player.GUIController).ResY); AspectRatio = ResX / ResY; OriginalAspectRatio = 4/3; NewFOV = (ATan((Tan((OriginalFOV*Pi)/360.0)*(AspectRatio/OriginalAspectRatio)),1)*360.0)/Pi; return NewFOV; } return OriginalFOV; } // The empty sound if your out of ammo simulated function Fire(float F) { if( bModeZeroCanDryFire && MagAmmoRemaining < 1 && !bIsReloading && FireMode[0].NextFireTime <= Level.TimeSeconds ) { // We're dry, ask the server to autoreload ServerRequestAutoReload(); PlayOwnedSound(FireMode[0].NoAmmoSound,SLOT_None,2.0,,,,false); } super.Fire(F); } // request an auto reload on the server - happens when the player dry fires function ServerRequestAutoReload() { if( /*NumClicks > 0 &&*/ AllowReload() ) { ReloadMeNow(); return; } NumClicks++; } simulated exec function ToggleIronSights() { if( bHasAimingMode ) { if( bAimingRifle ) { PerformZoom(false); } else { if( Owner != none && Owner.Physics == PHYS_Falling && Owner.PhysicsVolume.Gravity.Z <= class'PhysicsVolume'.default.Gravity.Z ) { return; } InterruptReload(); if( bIsReloading || !CanZoomNow() ) return; PerformZoom(True); } } } simulated exec function IronSightZoomIn() { if( bHasAimingMode ) { if( Owner != none && Owner.Physics == PHYS_Falling && Owner.PhysicsVolume.Gravity.Z <= class'PhysicsVolume'.default.Gravity.Z ) { return; } InterruptReload(); if( bIsReloading || !CanZoomNow() ) return; PerformZoom(True); } } simulated exec function IronSightZoomOut() { if( bHasAimingMode ) { if( bAimingRifle ) PerformZoom(false); if( Role < ROLE_Authority) ServerZoomOut(false); } } /** * Handles all the functionality for zooming in including * setting the parameters for the weapon, pawn, and playercontroller * * @param bAnimateTransition whether or not to animate this zoom transition */ simulated function ZoomIn(bool bAnimateTransition) { if ( ClientState != WS_PutDown && ClientState != WS_BringUp ) { super.ZoomIn(bAnimateTransition); bAimingRifle = True; if( KFHumanPawn(Instigator)!=None ) KFHumanPawn(Instigator).SetAiming(True); if( Level.NetMode != NM_DedicatedServer && KFPlayerController(Instigator.Controller) != none ) { if( AimInSound != none ) { PlayOwnedSound(AimInSound, SLOT_Misc,,,,, false); } KFPlayerController(Instigator.Controller).TransitionFOV(PlayerIronSightFOV,ZoomTime); } } } /** * Handles all the functionality for zooming out including * setting the parameters for the weapon, pawn, and playercontroller * * @param bAnimateTransition whether or not to animate this zoom transition */ simulated function ZoomOut(bool bAnimateTransition) { super.ZoomOut(bAnimateTransition); bAimingRifle = False; if( KFHumanPawn(Instigator)!=None ) KFHumanPawn(Instigator).SetAiming(False); if( Level.NetMode != NM_DedicatedServer && KFPlayerController(Instigator.Controller) != none ) { if( AimOutSound != none ) { PlayOwnedSound(AimOutSound, SLOT_Misc,,,,, false); } KFPlayerController(Instigator.Controller).TransitionFOV(KFPlayerController(Instigator.Controller).DefaultFOV,ZoomTime); } } /** * Called by the native code when the interpolation of the first person weapon to the zoomed position finishes */ simulated event OnZoomInFinished() { local name anim; local float frame, rate; GetAnimParams(0, anim, frame, rate); if (ClientState == WS_ReadyToFire) { // Play the iron idle anim when we're finished zooming in if (anim == IdleAnim) { PlayIdle(); } } } /** * Called by the native code when the interpolation of the first person weapon from the zoomed position finishes */ simulated event OnZoomOutFinished() { local name anim; local float frame, rate; GetAnimParams(0, anim, frame, rate); if (ClientState == WS_ReadyToFire) { // Play the regular idle anim when we're finished zooming out if (anim == IdleAimAnim) { PlayIdle(); } } } simulated function PlayIdle() { if( bAimingRifle ) { LoopAnim(IdleAimAnim, IdleAnimRate, 0.2); } else { LoopAnim(IdleAnim, IdleAnimRate, 0.2); } } simulated function vector GetEffectStart() { local Vector FlashLoc; // jjs - this function should actually never be called in third person views // any effect that needs a 3rdp weapon offset should figure it out itself // 1st person if (Instigator.IsFirstPerson()) { if ( WeaponCentered() ) return CenteredEffectStart(); FlashLoc = GetBoneCoords(default.FlashBoneName).Origin; return FlashLoc; } // 3rd person else { return (Instigator.Location + Instigator.EyeHeight*Vect(0,0,0.5) + Vector(Instigator.Rotation) * 40.0); } } function bool HandlePickupQuery( pickup Item ) { local int i; local class< KFWeaponPickup > KFWP, VariantPickupClass; local bool bInInventory; // check if Item and Self are the same weapon if( Item.InventoryType==Class ) { bInInventory = true; } // check if Item is a variant of Self KFWP = class< KFWeaponPickup >( PickupClass ); for( i = 0; i < KFWP.default.VariantClasses.Length && !bInInventory; ++i ) { VariantPickupClass = class(KFWP.default.VariantClasses[i]); if( Item.Class == VariantPickupClass ) { bInInventory = true; } } // check if Self is a variant of Item KFWP = class< KFWeaponPickup >( Item.Class ); if( KFWP != none ) { for( i = 0; i < KFWP.default.VariantClasses.Length && !bInInventory; ++i ) { VariantPickupClass = class(KFWP.default.VariantClasses[i]); if( PickupClass == VariantPickupClass ) { bInInventory = true; } } } if( bInInventory ) { if( LastHasGunMsgTime= 1 && pawn(Owner).Health > 0 ) { FlashLight=spawn(class'Effect_TacLightProjector',Instigator); PlaySound(sound'KF_9MMSnd.NineMM_AltFire1',SLOT_Misc,100); PlayAnim(ModeSwitchAnim,FireMode[0].FireAnimRate,FireMode[0].TweenTime); FlashLight.bHasLight=!FlashLight.bHasLight; } else if( FlashLight!=None ) { FlashLight.bHasLight=!FlashLight.bHasLight; PlayAnim(ModeSwitchAnim,FireMode[0].FireAnimRate,FireMode[0].TweenTime); //PlaySound(sound'KF_9MMSnd.NineMM_AltFire2 ',SLOT_Misc,100); } } } // Overridden to take out some UT stuff simulated event RenderOverlays( Canvas Canvas ) { local int m; if (Instigator == None) return; if ( Instigator.Controller != None ) Hand = Instigator.Controller.Handedness; if ((Hand < -1.0) || (Hand > 1.0)) return; // draw muzzleflashes/smoke for all fire modes so idle state won't // cause emitters to just disappear for (m = 0; m < NUM_FIRE_MODES; m++) { if (FireMode[m] != None) { FireMode[m].DrawMuzzleFlash(Canvas); } } SetLocation( Instigator.Location + Instigator.CalcDrawOffset(self) ); SetRotation( Instigator.GetViewRotation() + ZoomRotInterp); //PreDrawFPWeapon(); // Laurent -- Hook to override things before render (like rotation if using a staticmesh) bDrawingFirstPerson = true; Canvas.DrawActor(self, false, false, DisplayFOV); bDrawingFirstPerson = false; } exec function ReloadMeNow() { local float ReloadMulti; if(!AllowReload()) return; if ( bHasAimingMode && bAimingRifle ) { FireMode[1].bIsFiring = False; ZoomOut(false); if( Role < ROLE_Authority) ServerZoomOut(false); } if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) { ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self); } else { ReloadMulti = 1.0; } bIsReloading = true; ReloadTimer = Level.TimeSeconds; ReloadRate = Default.ReloadRate / ReloadMulti; if( bHoldToReload ) { NumLoadedThisReload = 0; } ClientReload(); Instigator.SetAnimAction(WeaponReloadAnim); // Reload message commented out for now - Ramm if ( Level.Game.NumPlayers > 1 && KFGameType(Level.Game).bWaveInProgress && KFPlayerController(Instigator.Controller) != none && Level.TimeSeconds - KFPlayerController(Instigator.Controller).LastReloadMessageTime > KFPlayerController(Instigator.Controller).ReloadMessageDelay ) { KFPlayerController(Instigator.Controller).Speech('AUTO', 2, ""); KFPlayerController(Instigator.Controller).LastReloadMessageTime = Level.TimeSeconds; } } simulated function ClientReload() { local float ReloadMulti; if ( bHasAimingMode && bAimingRifle ) { FireMode[1].bIsFiring = False; ZoomOut(false); if( Role < ROLE_Authority) ServerZoomOut(false); } if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) { ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self); } else { ReloadMulti = 1.0; } bIsReloading = true; PlayAnim(ReloadAnim, ReloadAnimRate*ReloadMulti, 0.1); } simulated function ClientReloadEffects(){} //// client & server //// // Overriden to support interrupting reloads simulated function bool StartFire(int Mode) { local bool RetVal; RetVal = super.StartFire(Mode); if( RetVal ) { if( Mode == 0 && ForceZoomOutOnFireTime > 0 ) { ForceZoomOutTime = Level.TimeSeconds + ForceZoomOutOnFireTime; } else if( Mode == 1 && ForceZoomOutOnAltFireTime > 0 ) { ForceZoomOutTime = Level.TimeSeconds + ForceZoomOutOnAltFireTime; } NumClicks=0; InterruptReload(); } return RetVal; } // Interrupt the reload for single bullet insert weapons simulated function bool InterruptReload() { if( bHoldToReload && bIsReloading ) { ServerInterruptReload(); if ( Level.NetMode != NM_StandAlone && (Level.NetMode != NM_ListenServer || !Instigator.IsLocallyControlled()) ) { ClientInterruptReload(); } return true; } return false; } simulated function ServerInterruptReload() { bDoSingleReload = false; bIsReloading = false; bReloadEffectDone = false; PlayIdle(); } // Server forces the reload to be cancelled simulated function ClientInterruptReload() { bIsReloading = false; PlayIdle(); } //We shouldn't allow finishreloading to finish reloading unless //the weapon works like that. simulated function ActuallyFinishReloading() { bDoSingleReload=false; ClientFinishReloading(); bIsReloading = false; bReloadEffectDone = false; } simulated function ClientFinishReloading() { bIsReloading = false; PlayIdle(); if(Instigator.PendingWeapon != none && Instigator.PendingWeapon != self) Instigator.Controller.ClientSwitchToBestWeapon(); } function ServerSetAiming(bool IsAiming) { if( KFHumanPawn(Instigator)!=None ) KFHumanPawn(Instigator).SetAiming(IsAiming); bAimingRifle = IsAiming; } simulated function bool AllowReload() { UpdateMagCapacity(Instigator.PlayerReplicationInfo); if(KFInvasionBot(Instigator.Controller) != none && !bIsReloading && MagAmmoRemaining < MagCapacity && AmmoAmount(0) > MagAmmoRemaining) return true; if(KFFriendlyAI(Instigator.Controller) != none && !bIsReloading && MagAmmoRemaining < MagCapacity && AmmoAmount(0) > MagAmmoRemaining) return true; if(FireMode[0].IsFiring() || FireMode[1].IsFiring() || bIsReloading || MagAmmoRemaining >= MagCapacity || ClientState == WS_BringUp || AmmoAmount(0) <= MagAmmoRemaining || (FireMode[0].NextFireTime - Level.TimeSeconds) > 0.1 ) return false; return true; } simulated function PostNetReceive() { //This function changes the weapon in netplay if it has no ammo //we WANT to be able to select guns without ammo. Therefore this //function has to be overridden do it does.....nothing. } function ServerStopFire(byte Mode) { //TODO: This works, but could be better timing wise // Still, at least the DBShottie/XBow don't have wierd // negative clip sizes now super.ServerStopFire(Mode); if(MagCapacity==1) MagAmmoRemaining=1; } // TODO: Play spot the difference // cut n pasted to change putdown behaviours simulated function Timer() { local int Mode; local float OldDownDelay; OldDownDelay = DownDelay; DownDelay = 0; if ( ClientState == WS_BringUp ) { for( Mode = 0; Mode < NUM_FIRE_MODES; Mode++ ) FireMode[Mode].InitEffects(); PlayIdle(); ClientState = WS_ReadyToFire; if ( bPendingFlashlight && bTorchEnabled ) { if ( Level.NetMode != NM_Client ) { LightFire(); } else { ClientStartFire(1); } bPendingFlashlight = false; } } else if ( ClientState == WS_PutDown ) { if ( OldDownDelay > 0 ) { if ( HasAnim(PutDownAnim) ) PlayAnim(PutDownAnim, PutDownAnimRate, 0.0); SetTimer(PutDownTime, false); return; } if ( Instigator.PendingWeapon == None ) { if( ClientGrenadeState == GN_TempDown ) { if(KFPawn(Instigator)!=none) { KFPawn(Instigator).WeaponDown(); } } else { PlayIdle(); } ClientState = WS_ReadyToFire; } else { if( FlashLight!=none ) Tacshine.Destroy(); ClientState = WS_Hidden; Instigator.ChangedWeapon(); if ( Instigator.Weapon == self ) { PlayIdle(); ClientState = WS_ReadyToFire; } else { for( Mode = 0; Mode < NUM_FIRE_MODES; Mode++ ) FireMode[Mode].DestroyEffects(); } } } } // Kludge to prevent destroyed weapons destroying the ammo if other guns // are still using the same ammo simulated function Destroyed() { local byte m; local Inventory InvIt; local byte bSaveAmmo[NUM_FIRE_MODES]; // byte, because bool arrays aren't allowed :( local Actor TempOwner; AmbientSound = None; if ( FlashLight != none ) FlashLight.Destroy(); if ( TacShine != none ) TacShine.Destroy(); if ( Owner == none ) { TempOwner = Instigator; } else { TempOwner = Owner; } if ( TempOwner != none) { for(InvIt = TempOwner.Inventory; InvIt!=none; InvIt=InvIt.Inventory) { if(Weapon(InvIt)!=none && InvIt!=self) { for(m=0; m < NUM_FIRE_MODES; m++) { if( Weapon(InvIt).Ammo[m]==Ammo[m] ) bSaveAmmo[m] = 1; } } } for (m = 0; m < NUM_FIRE_MODES; m++) { if ( FireMode[m] != None ) FireMode[m].DestroyEffects(); if( Ammo[m] != none && bSaveAmmo[m]==0 ) { Ammo[m].Destroy(); Ammo[m] = None; } } if ( Pawn(TempOwner) != none ) { Pawn(TempOwner).DeleteInventory(self); } } if ( ThirdPersonActor != None ) ThirdPersonActor.Destroy(); } simulated function Weapon PrevWeapon(Weapon CurrentChoice, Weapon CurrentWeapon) { //allow selection of empty guns, so that we can select them //in order to chuck them away if ( (CurrentChoice == None) ) { if ( CurrentWeapon != self ) CurrentChoice = self; } else if ( InventoryGroup == CurrentWeapon.InventoryGroup ) { if ( (GroupOffset < CurrentWeapon.GroupOffset) && ((CurrentChoice.InventoryGroup != InventoryGroup) || (GroupOffset > CurrentChoice.GroupOffset)) ) CurrentChoice = self; } else if ( InventoryGroup == CurrentChoice.InventoryGroup ) { if ( GroupOffset > CurrentChoice.GroupOffset ) CurrentChoice = self; } else if ( InventoryGroup > CurrentChoice.InventoryGroup ) { if ( (InventoryGroup < CurrentWeapon.InventoryGroup) || (CurrentChoice.InventoryGroup > CurrentWeapon.InventoryGroup) || ( (CurrentChoice.InventoryGroup == CurrentWeapon.InventoryGroup) && (CurrentChoice.GroupOffset>CurrentWeapon.GroupOffset) ) ) CurrentChoice = self; } else if ( (CurrentChoice.InventoryGroup > CurrentWeapon.InventoryGroup || ( (CurrentChoice.InventoryGroup == CurrentWeapon.InventoryGroup) && (CurrentChoice.GroupOffset>CurrentWeapon.GroupOffset) )) && (InventoryGroup < CurrentWeapon.InventoryGroup) ) CurrentChoice = self; if ( Inventory == None ) return CurrentChoice; else return Inventory.PrevWeapon(CurrentChoice,CurrentWeapon); } simulated function Weapon NextWeapon(Weapon CurrentChoice, Weapon CurrentWeapon) { if ( (CurrentChoice == None) ) { if ( CurrentWeapon != self ) CurrentChoice = self; } else if ( InventoryGroup == CurrentWeapon.InventoryGroup ) { if ( (GroupOffset > CurrentWeapon.GroupOffset) && ((CurrentChoice.InventoryGroup != InventoryGroup) || (GroupOffset < CurrentChoice.GroupOffset)) ) CurrentChoice = self; } else if ( InventoryGroup == CurrentChoice.InventoryGroup ) { if ( GroupOffset < CurrentChoice.GroupOffset ) CurrentChoice = self; } else if ( InventoryGroup < CurrentChoice.InventoryGroup ) { if ( (InventoryGroup > CurrentWeapon.InventoryGroup) || (CurrentChoice.InventoryGroup < CurrentWeapon.InventoryGroup) || ( (CurrentChoice.InventoryGroup == CurrentWeapon.InventoryGroup) && (CurrentChoice.GroupOffset CurrentWeapon.InventoryGroup) ) CurrentChoice = self; if ( Inventory == None ) return CurrentChoice; else return Inventory.NextWeapon(CurrentChoice,CurrentWeapon); } simulated function Weapon WeaponChange( byte F, bool bSilent ) { if ( InventoryGroup == F ) return self; else if ( Inventory == None ) return None; else return Inventory.WeaponChange(F,bSilent); } simulated function bool PutDown() { local int Mode; InterruptReload(); if ( bIsReloading ) return false; if( bAimingRifle ) { ZoomOut(False); } // From Weapon.uc if (ClientState == WS_BringUp || ClientState == WS_ReadyToFire) { if ( (Instigator.PendingWeapon != None) && !Instigator.PendingWeapon.bForceSwitch ) { for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { // if _RO_ if( FireMode[Mode] == none ) continue; // End _RO_ if ( FireMode[Mode].bFireOnRelease && FireMode[Mode].bIsFiring ) return false; if ( FireMode[Mode].NextFireTime > Level.TimeSeconds + FireMode[Mode].FireRate*(1.f - MinReloadPct)) DownDelay = FMax(DownDelay, FireMode[Mode].NextFireTime - Level.TimeSeconds - FireMode[Mode].FireRate*(1.f - MinReloadPct)); } } if (Instigator.IsLocallyControlled()) { for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { // if _RO_ if( FireMode[Mode] == none ) continue; // End _RO_ if ( FireMode[Mode].bIsFiring ) ClientStopFire(Mode); } if ( DownDelay <= 0 || KFPawn(Instigator).bIsQuickHealing > 0) { if ( ClientState == WS_BringUp || KFPawn(Instigator).bIsQuickHealing > 0 ) TweenAnim(SelectAnim,PutDownTime); else if ( HasAnim(PutDownAnim) ) { if( ClientGrenadeState == GN_TempDown || KFPawn(Instigator).bIsQuickHealing > 0) { PlayAnim(PutDownAnim, PutDownAnimRate * (PutDownTime/QuickPutDownTime), 0.0); } else { PlayAnim(PutDownAnim, PutDownAnimRate, 0.0); } } } } ClientState = WS_PutDown; if ( Level.GRI.bFastWeaponSwitching ) DownDelay = 0; if ( DownDelay > 0 ) { SetTimer(DownDelay, false); } else { if( ClientGrenadeState == GN_TempDown ) { SetTimer(QuickPutDownTime, false); } else { SetTimer(PutDownTime, false); } } } for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { // if _RO_ if( FireMode[Mode] == none ) continue; // End _RO_ FireMode[Mode].bServerDelayStartFire = false; FireMode[Mode].bServerDelayStopFire = false; } Instigator.AmbientSound = None; OldWeapon = None; return true; // return false if preventing weapon switch } simulated function BringUp(optional Weapon PrevWeapon) { local int Mode; local KFPlayerController Player; HandleSleeveSwapping(); // Hint check Player = KFPlayerController(Instigator.Controller); if ( Player != none && ClientGrenadeState != GN_BringUp ) { if ( class == class'Single' ) { Player.CheckForHint(10); } else if ( class == class'Dualies' ) { Player.CheckForHint(11); } else if ( class == class'Deagle' ) { Player.CheckForHint(12); } else if ( class == class'Bullpup' ) { Player.CheckForHint(13); } else if ( class == class'Shotgun' ) { Player.CheckForHint(14); } else if ( class == class'Winchester' ) { Player.CheckForHint(15); } else if ( class == class'Crossbow' ) { Player.CheckForHint(16); } else if ( class == class'BoomStick' ) { Player.CheckForHint(17); Player.WeaponPulloutRemark(21); } else if ( class == class'FlameThrower' ) { Player.CheckForHint(18); } else if ( class == class'LAW' ) { Player.CheckForHint(19); Player.WeaponPulloutRemark(23); } else if ( class == class'Knife' && bShowPullOutHint ) { Player.CheckForHint(20); } else if ( class == class'Machete' ) { Player.CheckForHint(21); } else if ( class == class'Axe' ) { Player.CheckForHint(22); Player.WeaponPulloutRemark(24); } else if ( class == class'DualDeagle' || class == class'GoldenDualDeagle' ) { Player.WeaponPulloutRemark(22); } bShowPullOutHint = true; } if ( KFHumanPawn(Instigator) != none ) KFHumanPawn(Instigator).SetAiming(false); bAimingRifle = false; bIsReloading = false; IdleAnim = default.IdleAnim; //Super.BringUp(PrevWeapon); // From Weapon.uc if ( ClientState == WS_Hidden || ClientGrenadeState == GN_BringUp || KFPawn(Instigator).bIsQuickHealing > 0 ) { PlayOwnedSound(SelectSound, SLOT_Interact,,,,, false); ClientPlayForceFeedback(SelectForce); // jdf if ( Instigator.IsLocallyControlled() ) { if ( (Mesh!=None) && HasAnim(SelectAnim) ) { if( ClientGrenadeState == GN_BringUp || KFPawn(Instigator).bIsQuickHealing > 0 ) { PlayAnim(SelectAnim, SelectAnimRate * (BringUpTime/QuickBringUpTime), 0.0); } else { PlayAnim(SelectAnim, SelectAnimRate, 0.0); } } } ClientState = WS_BringUp; if( ClientGrenadeState == GN_BringUp || KFPawn(Instigator).bIsQuickHealing > 0 ) { ClientGrenadeState = GN_None; SetTimer(QuickBringUpTime, false); } else { SetTimer(BringUpTime, false); } } for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { FireMode[Mode].bIsFiring = false; FireMode[Mode].HoldTime = 0.0; FireMode[Mode].bServerDelayStartFire = false; FireMode[Mode].bServerDelayStopFire = false; FireMode[Mode].bInstantStop = false; } if ( (PrevWeapon != None) && PrevWeapon.HasAmmo() && !PrevWeapon.bNoVoluntarySwitch ) OldWeapon = PrevWeapon; else OldWeapon = None; } //------------------------------------------------------------------------------ // HandleSleeveSwapping() - This function will handle sleeve swapping for // weapons depending on which player the person who picked the weapon up is. //------------------------------------------------------------------------------ simulated function HandleSleeveSwapping() { local XPawn XP; local Material SleeveTexture; // don't bother with AI players if( !Instigator.IsHumanControlled() || !Instigator.IsLocallyControlled() ) return; XP = XPawn(Instigator); if( XP == none ) { return; } SleeveTexture = Class(XP.Species).static.GetSleeveTexture(); if( SleeveTexture != none ) Skins[SleeveNum] = SleeveTexture; } simulated function bool ConsumeAmmo( int Mode, float Load, optional bool bAmountNeededIsMax ) { local Inventory Inv; local bool bOutOfAmmo; local KFWeapon KFWeap; if ( Super.ConsumeAmmo(Mode, Load, bAmountNeededIsMax) ) { if ( Load > 0 && (Mode == 0 || bReduceMagAmmoOnSecondaryFire) ) MagAmmoRemaining--; NetUpdateTime = Level.TimeSeconds - 1; if ( FireMode[Mode].AmmoPerFire > 0 && InventoryGroup > 0 && !bMeleeWeapon && bConsumesPhysicalAmmo && (Ammo[0] == none || FireMode[0] == none || FireMode[0].AmmoPerFire <= 0 || Ammo[0].AmmoAmount < FireMode[0].AmmoPerFire) && (Ammo[1] == none || FireMode[1] == none || FireMode[1].AmmoPerFire <= 0 || Ammo[1].AmmoAmount < FireMode[1].AmmoPerFire) ) { bOutOfAmmo = true; for ( Inv = Instigator.Inventory; Inv != none; Inv = Inv.Inventory ) { KFWeap = KFWeapon(Inv); if ( Inv.InventoryGroup > 0 && KFWeap != none && !KFWeap.bMeleeWeapon && KFWeap.bConsumesPhysicalAmmo && ((KFWeap.Ammo[0] != none && KFWeap.FireMode[0] != none && KFWeap.FireMode[0].AmmoPerFire > 0 &&KFWeap.Ammo[0].AmmoAmount >= KFWeap.FireMode[0].AmmoPerFire) || (KFWeap.Ammo[1] != none && KFWeap.FireMode[1] != none && KFWeap.FireMode[1].AmmoPerFire > 0 && KFWeap.Ammo[1].AmmoAmount >= KFWeap.FireMode[1].AmmoPerFire)) ) { bOutOfAmmo = false; break; } } if ( bOutOfAmmo ) { PlayerController(Instigator.Controller).Speech('AUTO', 3, ""); } } return true; } return false; } //TODO - this should, in theory, let us buy/carry more ammo. // is this intended, or should this side-effect be squashed? function ClipUpgrade() { MagCapacity += (0.25 * default.MagCapacity); } function OwnerEvent(name EventName) { if( EventName=='ChangedWeapon' ) { if( TacShine!=None ) TacShine.Destroy(); if( FlashLight!=None && FlashLight.bHasLight ) ServerSpawnLight(); } Super.OwnerEvent(EventName); } simulated function WeaponTick(float dt) { local float LastSeenSeconds,ReloadMulti; if( bHasAimingMode ) { if( bForceLeaveIronsights ) { if( bAimingRifle ) { ZoomOut(true); if( Role < ROLE_Authority) ServerZoomOut(false); } bForceLeaveIronsights = false; } if( ForceZoomOutTime > 0 ) { if( bAimingRifle ) { if( Level.TimeSeconds - ForceZoomOutTime > 0 ) { ForceZoomOutTime = 0; ZoomOut(true); if( Role < ROLE_Authority) ServerZoomOut(false); } } else { ForceZoomOutTime = 0; } } } if ( (Level.NetMode == NM_Client) || Instigator == None || KFFriendlyAI(Instigator.Controller) == none && Instigator.PlayerReplicationInfo == None) return; // Turn it off on death / battery expenditure if (FlashLight != none) { // Keep the 1Pweapon client beam up to date. AdjustLightGraphic(); if (FlashLight.bHasLight) { if (Instigator.Health <= 0 || KFHumanPawn(Instigator).TorchBatteryLife <= 0 || Instigator.PendingWeapon != none ) { //Log("Killing Light...you're out of batteries, or switched / dropped weapons"); KFHumanPawn(Instigator).bTorchOn = false; ServerSpawnLight(); } } } UpdateMagCapacity(Instigator.PlayerReplicationInfo); if(!bIsReloading) { if(!Instigator.IsHumanControlled()) { LastSeenSeconds = Level.TimeSeconds - Instigator.Controller.LastSeenTime; if(MagAmmoRemaining == 0 || ((LastSeenSeconds >= 5 || LastSeenSeconds > MagAmmoRemaining) && MagAmmoRemaining < MagCapacity)) ReloadMeNow(); } } else { if((Level.TimeSeconds - ReloadTimer) >= ReloadRate) { if(AmmoAmount(0) <= MagCapacity && !bHoldToReload) { MagAmmoRemaining = AmmoAmount(0); ActuallyFinishReloading(); } else { if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) { ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self); } else { ReloadMulti = 1.0; } AddReloadedAmmo(); if( bHoldToReload ) { NumLoadedThisReload++; } if(MagAmmoRemaining < MagCapacity && MagAmmoRemaining < AmmoAmount(0) && bHoldToReload) ReloadTimer = Level.TimeSeconds; if(MagAmmoRemaining >= MagCapacity || MagAmmoRemaining >= AmmoAmount(0) || !bHoldToReload || bDoSingleReload) ActuallyFinishReloading(); else if( Level.NetMode!=NM_Client ) Instigator.SetAnimAction(WeaponReloadAnim); } } else if(bIsReloading && !bReloadEffectDone && Level.TimeSeconds - ReloadTimer >= ReloadRate / 2) { bReloadEffectDone = true; ClientReloadEffects(); } } } // Add the ammo for this reload function AddReloadedAmmo() { UpdateMagCapacity(Instigator.PlayerReplicationInfo); if(AmmoAmount(0) >= MagCapacity) MagAmmoRemaining = MagCapacity; else MagAmmoRemaining = AmmoAmount(0) ; // Don't do this on a "Hold to reload" weapon, as it can update too quick actually and cause issues maybe - Ramm if( !bHoldToReload ) { ClientForceKFAmmoUpdate(MagAmmoRemaining,AmmoAmount(0)); } if ( PlayerController(Instigator.Controller) != none && KFSteamStatsAndAchievements(PlayerController(Instigator.Controller).SteamStatsAndAchievements) != none ) { KFSteamStatsAndAchievements(PlayerController(Instigator.Controller).SteamStatsAndAchievements).OnWeaponReloaded(); } } simulated function ClientForceKFAmmoUpdate(int NewMagAmmoRemaining, int TotalAmmoRemaining) { //log(self$" ClientForceKFAmmoUpdate NewMagAmmoRemaining "$NewMagAmmoRemaining$" TotalAmmoRemaining "$TotalAmmoRemaining); ClientForceAmmoUpdate(0, TotalAmmoRemaining); } simulated function DoToggle () { local PlayerController Player; if( IsFiring() ) { return; } Player = Level.GetLocalPlayerController(); if ( Player!=None ) { //PlayOwnedSound(sound'Inf_Weapons_Foley.stg44_firemodeswitch01',SLOT_None,2.0,,,,false); FireMode[0].bWaitForRelease = !FireMode[0].bWaitForRelease; if ( FireMode[0].bWaitForRelease ) Player.ReceiveLocalizedMessage(class'KFmod.BullpupSwitchMessage',0); else Player.ReceiveLocalizedMessage(class'KFmod.BullpupSwitchMessage',1); } PlayOwnedSound(ToggleSound,SLOT_None,2.0,,,,false); ServerChangeFireMode(FireMode[0].bWaitForRelease); } // Set the new fire mode on the server function ServerChangeFireMode(bool bNewWaitForRelease) { FireMode[0].bWaitForRelease = bNewWaitForRelease; } // TODO - Decode the purpose of this mangled mess simulated function float ChargeBar() { Return 0; } function byte BestMode() { return 0; } // complete cut n' paste job needed, so that it can be modified // to stop this function giving ammo to empty guns that have been // thrown out function GiveAmmo(int m, WeaponPickup WP, bool bJustSpawned) { local bool bJustSpawnedAmmo; local int addAmount, InitialAmount; local KFPawn KFP; local KFPlayerReplicationInfo KFPRI; KFP = KFPawn(Instigator); if( KFP != none ) { KFPRI = KFPlayerReplicationInfo(KFP.PlayerReplicationInfo); } UpdateMagCapacity(Instigator.PlayerReplicationInfo); if ( FireMode[m] != None && FireMode[m].AmmoClass != None ) { Ammo[m] = Ammunition(Instigator.FindInventoryType(FireMode[m].AmmoClass)); bJustSpawnedAmmo = false; if ( bNoAmmoInstances ) { if ( (FireMode[m].AmmoClass == None) || ((m != 0) && (FireMode[m].AmmoClass == FireMode[0].AmmoClass)) ) return; InitialAmount = FireMode[m].AmmoClass.Default.InitialAmount; if(WP!=none && WP.bThrown==true) InitialAmount = WP.AmmoAmount[m]; else { // Other change - if not thrown, give the gun a full clip MagAmmoRemaining = MagCapacity; } if ( Ammo[m] != None ) { addamount = InitialAmount + Ammo[m].AmmoAmount; Ammo[m].Destroy(); } else addAmount = InitialAmount; AddAmmo(addAmount,m); } else { if ( (Ammo[m] == None) && (FireMode[m].AmmoClass != None) ) { Ammo[m] = Spawn(FireMode[m].AmmoClass, Instigator); Instigator.AddInventory(Ammo[m]); bJustSpawnedAmmo = true; } else if ( (m == 0) || (FireMode[m].AmmoClass != FireMode[0].AmmoClass) ) bJustSpawnedAmmo = ( bJustSpawned || ((WP != None) && !WP.bWeaponStay) ); // and here is the modification for instanced ammo actors if(WP!=none && WP.bThrown==true) { addAmount = WP.AmmoAmount[m]; } else if ( bJustSpawnedAmmo ) { if (default.MagCapacity == 0) addAmount = 0; // prevent division by zero. else addAmount = Ammo[m].InitialAmount * (float(MagCapacity) / float(default.MagCapacity)); } // Don't double add ammo if primary and secondary fire modes share the same ammo class if ( WP != none && m > 0 && (FireMode[m].AmmoClass == FireMode[0].AmmoClass) ) { return; } // AddAmmo caps at MaxAmmo, but veterancy might allow for more than max, // so take that into account if( KFPRI != none && KFPRI.ClientVeteranSkill != none ) { Ammo[m].MaxAmmo = float(Ammo[m].MaxAmmo) * KFPRI.ClientVeteranSkill.Static.AddExtraAmmoFor(KFPRI, Ammo[m].Class); } Ammo[m].AddAmmo(addAmount); Ammo[m].GotoState(''); } } } //this is a terribly ugly hack allowing us to silently add weapons //in the case of buy menu consumables //This does NOT work online and has been replaced. function SilentGiveTo(Pawn Other, optional Pickup Pickup) { local int m; local weapon w; local bool bJustSpawned; Instigator = Other; W = Weapon(Instigator.FindInventoryType(class)); if ( W == None || W.Class != Class ) // added class check because somebody made FindInventoryType() return subclasses for some reason { bJustSpawned = true; GiveTo(Other); W = self; } for (m = 0; m < NUM_FIRE_MODES; m++) { if ( FireMode[m] != None ) { FireMode[m].Instigator = Instigator; W.GiveAmmo(m,WeaponPickup(Pickup),bJustSpawned); } } if ( !bJustSpawned ) { for (m = 0; m < NUM_FIRE_MODES; m++) Ammo[m] = None; Destroy(); } } function GiveTo( pawn Other, optional Pickup Pickup ) { UpdateMagCapacity(Other.PlayerReplicationInfo); if ( KFWeaponPickup(Pickup)!=None && Pickup.bDropped ) { MagAmmoRemaining = Clamp(KFWeaponPickup(Pickup).MagAmmoRemaining, 0, MagCapacity); } else MagAmmoRemaining = MagCapacity; Super.GiveTo(Other,Pickup); } // Modded to allow for throwing even when out of ammo. (also added : You cannot throw while reloading) simulated function bool CanThrow() { local int Mode; if(bKFNeverThrow) return false; for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { if ( FireMode[Mode].bFireOnRelease && FireMode[Mode].bIsFiring ) return false; if ( FireMode[Mode].NextFireTime > Level.TimeSeconds) return false; } return (bCanThrow && !bIsReloading && (ClientState == WS_ReadyToFire || (Level.NetMode == NM_DedicatedServer) || (Level.NetMode == NM_ListenServer))); } simulated function ClientWeaponThrown() { local int m; local Inventory InvIt; local byte bSaveAmmo[NUM_FIRE_MODES]; AmbientSound = None; Instigator.AmbientSound = None; if( Level.NetMode != NM_Client ) return; for ( InvIt = Instigator.Inventory; InvIt != none; InvIt = InvIt.Inventory ) { if ( Weapon(InvIt) != none && InvIt != self) { for ( m = 0; m < NUM_FIRE_MODES; m++ ) { if ( Weapon(InvIt).Ammo[m] == Ammo[m] ) { bSaveAmmo[m] = 1; } } } } Instigator.DeleteInventory(self); for (m = 0; m < NUM_FIRE_MODES; m++) { if (Ammo[m] != none && bSaveAmmo[m] == 0 ) Instigator.DeleteInventory(Ammo[m]); } } function DropFrom(vector StartLocation) { local int m; local Pickup Pickup; local vector Direction; if (!bCanThrow) return; ClientWeaponThrown(); for (m = 0; m < NUM_FIRE_MODES; m++) { if (FireMode[m].bIsFiring) StopFire(m); } if ( Instigator != None ) { DetachFromPawn(Instigator); Direction = vector(Instigator.Rotation); } else if ( Owner != none ) { Direction = vector(Owner.Rotation); } Pickup = Spawn(PickupClass,,, StartLocation); if ( Pickup != None ) { Pickup.InitDroppedPickupFor(self); Pickup.Velocity = Velocity + (Direction * 100); if (Instigator.Health > 0) WeaponPickup(Pickup).bThrown = true; } Destroyed(); Destroy(); } // Only fill to initial the FIRST time we come across this weapon. simulated function FillToInitialAmmo() { if ( bNoAmmoInstances ) { if ( AmmoClass[0] != None ) AmmoCharge[0] = Max(AmmoCharge[0], AmmoClass[0].Default.InitialAmount); if ( (AmmoClass[1] != None) && (AmmoClass[0] != AmmoClass[1]) ) AmmoCharge[1] = Max(AmmoCharge[1], AmmoClass[1].Default.InitialAmount); return; } if ( Ammo[0] != None ) Ammo[0].AmmoAmount = /*Max(*/Ammo[0].AmmoAmount;//,Ammo[0].InitialAmount * (float(MagCapacity) / float(default.MagCapacity))); if ( Ammo[1] != None ) Ammo[1].AmmoAmount = Max(Ammo[1].AmmoAmount,Ammo[1].InitialAmount * (float(MagCapacity) / float(default.MagCapacity))); } // Change the Accuracy based on player movement simulated function AccuracyUpdate(float Velocity) { if (Owner != none) { if (KFFire(FireMode[0])!= none) KFFire(FireMode[0]).AccuracyUpdate(Velocity); else if (KFShotgunFire(FireMode[0]) !=none) KFShotgunFire(FireMode[0]).AccuracyUpdate(Velocity); } } function AdjustLightGraphic() { if ( TacShine==none ) { TacShine = Spawn(TacShineClass,,,,); AttachToBone(TacShine,'LightBone'); } if( FlashLight!=none ) Tacshine.bHidden = !FlashLight.bHasLight; } simulated function PlayAnimZoom( bool bZoomNow ); // Called from KFZoom whenever start or end the zooming. simulated function bool CanZoomNow() { return true; } simulated function float GetAmmoMulti() { if ( NextAmmoCheckTime > Level.TimeSeconds ) { return LastAmmoResult; } NextAmmoCheckTime = Level.TimeSeconds + 1; if ( FireMode[0] != none && FireMode[0].AmmoClass != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) { LastAmmoResult = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.static.AddExtraAmmoFor(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), FireMode[0].AmmoClass); } else { LastAmmoResult = 1; } return LastAmmoResult; } simulated function int MaxAmmo(int mode) { if ( AmmoClass[mode] != None ) return AmmoClass[mode].Default.MaxAmmo*GetAmmoMulti(); return 0; } simulated function bool AmmoMaxed(int mode) { if ( AmmoClass[mode] == None ) return false; if ( bNoAmmoInstances ) { if ( AmmoClass[0] == AmmoClass[mode] ) mode = 0; return AmmoCharge[mode] >= MaxAmmo(mode); } if ( Ammo[mode] == None ) return false; return (Ammo[mode].AmmoAmount >= MaxAmmo(mode)); } simulated function float AmmoStatus(optional int Mode) // returns float value for ammo amount { if ( bNoAmmoInstances ) { if ( AmmoClass[Mode] == None ) return 0; if ( AmmoClass[0] == AmmoClass[mode] ) mode = 0; return float(AmmoCharge[Mode])/float(MaxAmmo(Mode)); } if (Ammo[Mode] == None) return 0.0; else return float(Ammo[Mode].AmmoAmount) / float(Ammo[Mode].MaxAmmo)*GetAmmoMulti(); } // Avoid potential suicides... function bool CanAttack(Actor Other) { local float Dist, CheckDist; local vector HitLocation, HitNormal,X,Y,Z, projStart; local actor HitActor; local int m; local bool bInstantHit; if ( (Instigator == None) || (Instigator.Controller == None) ) return false; // check that target is within range Dist = VSize(Instigator.Location - Other.Location); if ( (Dist > FireMode[0].MaxRange()) && (Dist > FireMode[1].MaxRange()) || Dist < MinimumFireRange) return false; // check that can see target if ( !Instigator.Controller.LineOfSightTo(Other) ) return false; for (m = 0; m < NUM_FIRE_MODES; m++) { if ( FireMode[m].bInstantHit ) bInstantHit = true; else { CheckDist = FMax(CheckDist, 0.5 * FireMode[m].ProjectileClass.Default.Speed); CheckDist = FMax(CheckDist, 300); CheckDist = FMin(CheckDist, VSize(Other.Location - Location)); } } // check that would hit target, and not a friendly GetAxes(Instigator.Controller.Rotation, X,Y,Z); projStart = GetFireStart(X,Y,Z); if ( bInstantHit ) HitActor = Trace(HitLocation, HitNormal, Other.Location + Other.CollisionHeight * vect(0,0,0.8), projStart, true); else { // for non-instant hit, only check partial path (since others may move out of the way) HitActor = Trace(HitLocation, HitNormal, projStart + CheckDist * Normal(Other.Location + Other.CollisionHeight * vect(0,0,0.8) - Location), projStart, true); } if ( (HitActor == None) || (HitActor == Other) ) return true; if ( Pawn(HitActor) == None ) return !HitActor.BlocksShotAt(Other); if ( (Pawn(HitActor).Controller == None) || !Instigator.Controller.SameTeamAs(Pawn(HitActor).Controller) ) return true; return false; } simulated function GetAmmoCount(out float MaxAmmoPrimary, out float CurAmmoPrimary) { if ( Instigator == None || Instigator.Controller == None ) { return; } if ( AmmoClass[0] == None ) { return; } if ( bNoAmmoInstances ) { MaxAmmoPrimary = MaxAmmo(0); CurAmmoPrimary = AmmoCharge[0]; if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) { MaxAmmoPrimary *= KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.static.AddExtraAmmoFor(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), AmmoClass[0]); MaxAmmoPrimary = int(MaxAmmoPrimary); } return; } if ( Ammo[0] == None ) { return; } MaxAmmoPrimary = Ammo[0].default.MaxAmmo; CurAmmoPrimary = Ammo[0].AmmoAmount; if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) { MaxAmmoPrimary *= KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.static.AddExtraAmmoFor(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), Ammo[0].class); MaxAmmoPrimary = int(MaxAmmoPrimary); } } simulated function GetSecondaryAmmoCount(out float MaxAmmoSecondary, out float CurAmmoSecondary) { if ( Instigator == none || Instigator.Controller == none || !bHasSecondaryAmmo || AmmoClass[1] == none ) { MaxAmmoSecondary = 0; CurAmmoSecondary = 0; return; } if ( bNoAmmoInstances ) { MaxAmmoSecondary = MaxAmmo(1); CurAmmoSecondary = AmmoCharge[1]; if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) { MaxAmmoSecondary *= KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.static.AddExtraAmmoFor(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), AmmoClass[1]); MaxAmmoSecondary = int(MaxAmmoSecondary); } return; } if ( Ammo[1] == None ) { return; } MaxAmmoSecondary = Ammo[1].default.MaxAmmo; CurAmmoSecondary = Ammo[1].AmmoAmount; if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) { MaxAmmoSecondary *= KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.static.AddExtraAmmoFor(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), Ammo[1].class); MaxAmmoSecondary = int(MaxAmmoSecondary); } } simulated function UpdateMagCapacity(PlayerReplicationInfo PRI) { if ( KFPlayerReplicationInfo(PRI) != none && KFPlayerReplicationInfo(PRI).ClientVeteranSkill != none ) { MagCapacity = default.MagCapacity * KFPlayerReplicationInfo(PRI).ClientVeteranSkill.Static.GetMagCapacityMod(KFPlayerReplicationInfo(PRI), self); } else { MagCapacity = default.MagCapacity; } } defaultproperties { FlashBoneName="tip" WeaponReloadAnim = "Reload1" bReloadEffectDone=True Weight=10.000000 bNoAmmoInstances=False Description="This is a very generic weapon." LightType=LT_Steady LightEffect=LE_NonIncidence LightHue=30 LightSaturation=150 LightBrightness=255.000000 LightRadius=10.000000 LightPeriod=3 //PrePivot=(X=0.250000,Y=3.300000,Z=2.000000) TransientSoundVolume=100.000000 StoppingPower = -1000 HudImage = none AmbientGlow = 0 ModeSwitchAnim = 'AltFire' TacShineClass = class 'TacLightShineAttachment' bSniping=True QuickPutDownTime=0.15 QuickBringUpTime=0.15 bHasAimingMode=false bConsumesPhysicalAmmo=true bReduceMagAmmoOnSecondaryFire=true // Failsafe defaults, should be plugged in for each weapon StandardDisplayFOV=90.0 SleeveNum=1 SellValue=-1 AppID=0 UnlockedByAchievement = -1 }