1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFWeap_AssaultRifle_FAMAS.uc
2021-09-03 00:46:08 +03:00

707 lines
20 KiB
Ucode

//=============================================================================
// KFWeap_AssaultRifle_FAMAS
//=============================================================================
// FAMAS assault rifle with an extra of shotgun. Better than in MGS!
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeap_AssaultRifle_FAMAS extends KFWeap_ScopedBase;
var (Positioning) vector SecondaryFireOffset;
const SecondaryFireAnim = 'Shoot_Secondary';
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
const SecondaryFireAnimLast = 'Shoot_Secondary_Last';
const SecondaryFireIronAnimLast = 'Shoot_Secondary_Iron_Last';
const SecondaryReloadAnimEmpty = 'Reload_Secondary_Empty';
const SecondaryReloadAnimHalf = 'Reload_Secondary_Half';
const SecondaryReloadAnimEliteEmpty = 'Reload_Secondary_Elite_Empty';
const SecondaryReloadAnimEliteHalf = 'Reload_Secondary_Elite_Half';
const ShotgunMuzzleSocket = 'ShotgunMuzzleFlash';
/** Animation to play when the weapon is fired in burst mode with 2 rounds left */
var(Animations) const editconst name BurstFire2RdAnim;
var(Animations) const editconst name BurstFire2RdSightedAnim;
/** Animation to play when the weapon is fired in burst fire mode for 3 rounds*/
var(Animations) const editconst name BurstFire3RdAnim;
var(Animations) const editconst name BurstFire3RdSightedAnim;
var transient KFMuzzleFlash ShotgunMuzzleFlash;
var() KFMuzzleFlash ShotgunMuzzleFlashTemplate;
// Used on the server to keep track of grenades
var int ServerTotalAltAmmo;
var transient bool bCanceledAltAutoReload;
var transient int BurstAmountBegin;
var protected const float AltFireRecoilScale;
static simulated event EFilterTypeUI GetTraderFilter()
{
return FT_Assault;
}
static simulated event EFilterTypeUI GetAltTraderFilter()
{
return FT_Explosive;
}
/** Instead of switch fire mode use as immediate alt fire */
simulated function AltFireMode()
{
if ( !Instigator.IsLocallyControlled() )
{
return;
}
if (bCanceledAltAutoReload)
{
bCanceledAltAutoReload = false;
TryToAltReload(true);
return;
}
// StartFire - StopFire called from KFPlayerInput
StartFire(ALTFIRE_FIREMODE);
}
simulated function BeginFire( Byte FireModeNum )
{
local bool bStoredAutoReload;
// We are trying to reload the weapon but the primary ammo in already at full capacity
if ( FireModeNum == RELOAD_FIREMODE && !CanReload() )
{
// Store the current state of bCanceledAltAutoReload in case its not possible to do the reload
bStoredAutoReload = bCanceledAltAutoReload;
bCanceledAltAutoReload = false;
if(CanAltAutoReload(false))
{
TryToAltReload(false);
return;
}
bCanceledAltAutoReload = bStoredAutoReload;
}
super.BeginFire( FireModeNum );
}
/**
* Initializes ammo counts, when weapon is spawned.
*/
function InitializeAmmo()
{
Super.InitializeAmmo();
// Add Secondary ammo to our secondary spare ammo count both of these are important, in order to allow dropping the weapon to function properly.
SpareAmmoCount[1] = Min(SpareAmmoCount[1] + InitialSpareMags[1] * default.MagazineCapacity[1], GetMaxAmmoAmount(1) - AmmoCount[1]);
ServerTotalAltAmmo += SpareAmmoCount[1];
// Make sure the server doesn't get extra shots on listen servers.
if(Role == ROLE_Authority && !Instigator.IsLocallyControlled())
{
ServerTotalAltAmmo += AmmoCount[1];
}
}
/**
* @see Weapon::ConsumeAmmo
*/
simulated function ConsumeAmmo( byte FireModeNum )
{
local byte AmmoType;
local bool bNoInfiniteAmmo;
local int OldAmmoCount;
if(UsesSecondaryAmmo() && FireModeNum == ALTFIRE_FIREMODE && Role == ROLE_Authority && !Instigator.IsLocallyControlled())
{
AmmoType = GetAmmoType(FireModeNum);
OldAmmoCount = AmmoCount[AmmoType];
Super.ConsumeAmmo(FireModeNum);
bNoInfiniteAmmo = (OldAmmoCount - AmmoCount[AmmoType]) > 0 || AmmoCount[AmmoType] == 0;
if ( bNoInfiniteAmmo )
{
ServerTotalAltAmmo--;
}
}
else
{
Super.ConsumeAmmo(FireModeNum);
}
}
/** Make sure user can't fire infinitely if they cheat to get infinite ammo locally. */
simulated event bool HasAmmo( byte FireModeNum, optional int Amount=1 )
{
local byte AmmoType;
AmmoType = GetAmmoType(FireModeNum);
if(AmmoType == 1 && Role == ROLE_Authority && UsesSecondaryAmmo() && !Instigator.IsLocallyControlled())
{
if(ServerTotalAltAmmo <= 0)
{
return false;
}
}
return Super.HasAmmo(FireModeNum, Amount );
}
/**
* Overridden so any grenades added will go to the spare ammo and no the clip.
*/
function int AddSecondaryAmmo(int Amount)
{
local int OldAmmo;
// If we can't accept spare ammo, then abort
if( !CanRefillSecondaryAmmo() )
{
return 0;
}
if(Role == ROLE_Authority && !Instigator.IsLocallyControlled())
{
OldAmmo = ServerTotalAltAmmo;
ServerTotalAltAmmo = Min(ServerTotalAltAmmo + Amount, GetMaxAmmoAmount(1));
ClientGiveSecondaryAmmo(Amount);
return ServerTotalAltAmmo - OldAmmo;
}
else
{
OldAmmo = SpareAmmoCount[1];
ClientGiveSecondaryAmmo(Amount);
return SpareAmmoCount[1] - OldAmmo;
}
}
/** Give client specified amount of ammo (used player picks up ammo on the server) */
reliable client function ClientGiveSecondaryAmmo(byte Amount)
{
SpareAmmoCount[1] = Min(SpareAmmoCount[1] + Amount, GetMaxAmmoAmount(1) - AmmoCount[1]);
TryToAltReload(true);
}
function SetOriginalValuesFromPickup( KFWeapon PickedUpWeapon )
{
local KFWeap_AssaultRifle_FAMAS Weap;
Super.SetOriginalValuesFromPickup(PickedUpWeapon);
if(Role == ROLE_Authority && !Instigator.IsLocallyControlled())
{
Weap = KFWeap_AssaultRifle_FAMAS(PickedUpWeapon);
ServerTotalAltAmmo = Weap.ServerTotalAltAmmo;
SpareAmmoCount[1] = ServerTotalAltAmmo - AmmoCount[1];
}
else
{
// If we're locally controlled, don't bother using ServerTotalAltAmmo.
SpareAmmoCount[1] = PickedUpWeapon.SpareAmmoCount[1];
}
}
simulated state WeaponBurstFiring
{
simulated event BeginState(Name PreviousStateName)
{
BurstAmountBegin = GetBurstAmount();
Super.BeginState(PreviousStateName);
}
simulated function name GetWeaponFireAnim(byte FireModeNum)
{
// only do one burst animation instead of a burst animation per shot
// since burst amount gets reduced after each shot, this will only play the one animation based on the number of shots in the burst fire
if (BurstAmount == BurstAmountBegin)
{
if (BurstAmount == 3)
{
if (bUsingSights)
{
return BurstFire3RdSightedAnim;
}
return BurstFire3RdAnim;
}
else if (BurstAmount == 2)
{
if (bUsingSights)
{
return BurstFire2RdSightedAnim;
}
return BurstFire2RdAnim;
}
else
{
return super.GetWeaponFireAnim(FireModeNum);
}
}
// will not play any animation
return '';
}
}
simulated state FiringSecondaryState extends WeaponFiring
{
// Overriden to not call FireAmmunition right at the start of the state
simulated event BeginState( Name PreviousStateName )
{
Super.BeginState(PreviousStateName);
NotifyBeginState();
}
simulated function EndState(Name NextStateName)
{
Super.EndState(NextStateName);
NotifyEndState();
}
/**
* This function returns the world location for spawning the visual effects
* Overridden to use a special offset for using the shotgun
*/
simulated event vector GetMuzzleLoc()
{
local vector MuzzleLocation;
// swap fireoffset temporarily
FireOffset = SecondaryFireOffset;
MuzzleLocation = Global.GetMuzzleLoc();
FireOffset = default.FireOffset;
return MuzzleLocation;
}
/** Get whether we should play the reload anim as well or not */
simulated function name GetWeaponFireAnim(byte FireModeNum)
{
if (AmmoCount[FireModeNum] > 0)
{
return bUsingSights ? SecondaryFireIronAnim : SecondaryFireAnim;
}
return bUsingSights ? SecondaryFireIronAnimLast : SecondaryFireAnimLast;
}
}
/**
* Don't allow secondary fire to make a primary fire shell particle come out of the gun.
*/
simulated function CauseMuzzleFlash(byte FireModeNum)
{
if(FireModeNum == ALTFIRE_FIREMODE)
{
if (ShotgunMuzzleFlash == None)
{
AttachMuzzleFlash();
}
if (ShotgunMuzzleFlash != none)
{
ShotgunMuzzleFlash.CauseMuzzleFlash(FireModeNum);
}
if ( ShotgunMuzzleFlash.bAutoActivateShellEject )
{
ShotgunMuzzleFlash.CauseShellEject();
SetShellEjectsToForeground();
}
}
else
{
Super.CauseMuzzleFlash(FireModeNum);
}
}
simulated function AttachMuzzleFlash()
{
super.AttachMuzzleFlash();
if ( MySkelMesh != none )
{
if (ShotgunMuzzleFlashTemplate != None)
{
ShotgunMuzzleFlash = new(self) Class'KFMuzzleFlash'(ShotgunMuzzleFlashTemplate);
ShotgunMuzzleFlash.AttachMuzzleFlash(MySkelMesh, ShotgunMuzzleSocket,);
}
}
}
/*********************************************************************************************
* State Reloading
* This is the default Reloading State. It's performed on both the client and the server.
*********************************************************************************************/
/** Do not allow alternate fire to tell the weapon to reload. Alt reload occurs in a separate codepath */
simulated function bool ShouldAutoReload(byte FireModeNum)
{
if(FireModeNum == ALTFIRE_FIREMODE)
{
return false;
}
return Super.ShouldAutoReload(FireModeNum);
}
/** Called on local player when reload starts and replicated to server */
simulated function SendToAltReload()
{
ReloadAmountLeft = MagazineCapacity[1] - AmmoCount[1];
GotoState('AltReloading');
if ( Role < ROLE_Authority )
{
ServerSendToAltReload();
}
}
/** Called from client when reload starts */
reliable server function ServerSendToAltReload()
{
ReloadAmountLeft = MagazineCapacity[1] - AmmoCount[1];
GotoState('AltReloading');
}
/**
* State Reloading
* State the weapon is in when it is being reloaded (current magazine replaced with a new one, related animations and effects played).
*/
simulated state AltReloading extends Reloading
{
ignores ForceReload, ShouldAutoReload, AllowSprinting;
simulated function byte GetWeaponStateId()
{
local KFPerk Perk;
local bool bTacticalReload;
Perk = GetPerk();
bTacticalReload = (Perk != None && Perk.GetUsingTactialReload(self));
if (AmmoCount[ALTFIRE_FIREMODE] == 0)
{
return (bTacticalReload ? WEP_ReloadSecondaryEmpty_Elite : WEP_ReloadSecondaryEmpty);
}
else
{
return (bTacticalReload ? WEP_ReloadSecondary_Elite : WEP_ReloadSecondary);
}
}
simulated event BeginState(Name PreviousStateName)
{
super.BeginState(PreviousStateName);
bCanceledAltAutoReload = true;
}
// Overridding super so we don't call functions we don't want to call.
simulated function EndState(Name NextStateName)
{
ClearZedTimeResist();
ClearTimer(nameof(ReloadStatusTimer));
ClearTimer(nameof(ReloadAmmoTimer));
CheckBoltLockPostReload();
NotifyEndState();
`DialogManager.PlayAmmoDialog( KFPawn(Instigator), float(SpareAmmoCount[1]) / float(GetMaxAmmoAmount(1)) );
}
// Overridding super so when this reload is called directly after normal reload state there
// are not complications resulting from back to back reloads.
simulated event ReplicatedEvent(name VarName)
{
Global.ReplicatedEvent(Varname);
}
/** Make sure we can inturrupt secondary reload with anything. */
simulated function bool CanOverrideMagReload(byte FireModeNum)
{
return true;
}
/** Returns animation to play based on reload type and status */
simulated function name GetReloadAnimName( bool bTacticalReload )
{
// magazine relaod
if ( AmmoCount[1] > 0 )
{
return (bTacticalReload) ? SecondaryReloadAnimEliteHalf : SecondaryReloadAnimHalf;
}
else
{
return (bTacticalReload) ? SecondaryReloadAnimEliteEmpty : SecondaryReloadAnimEmpty;
}
}
simulated function PerformReload(optional byte FireModeNum)
{
Global.PerformReload(ALTFIRE_FIREMODE);
if(Instigator.IsLocallyControlled() && Role < ROLE_Authority)
{
ServerSetAltAmmoCount(AmmoCount[1]);
}
bCanceledAltAutoReload = false;
}
simulated function EReloadStatus GetNextReloadStatus(optional byte FireModeNum)
{
return Global.GetNextReloadStatus(ALTFIRE_FIREMODE);
}
}
reliable server function ServerSetAltAmmoCount(byte Amount)
{
AmmoCount[1] = Amount;
}
/** Allow reloads for primary weapon to be interupted by firing secondary weapon. */
simulated function bool CanOverrideMagReload(byte FireModeNum)
{
if(FireModeNum == ALTFIRE_FIREMODE)
{
return true;
}
return Super.CanOverrideMagReload(FireModeNum);
}
/*********************************************************************************************
* State Active
* Try to get weapon to automatically reload secondary fire types when it can.
*********************************************************************************************/
simulated state Active
{
/** Initialize the weapon as being active and ready to go. */
simulated event BeginState(Name PreviousStateName)
{
// do this last so the above code happens before any state changes
Super.BeginState(PreviousStateName);
// If nothing happened, try to reload
TryToAltReload(true);
}
}
/** Network: Local Player */
simulated function bool CanAltAutoReload(bool bIsAuto)
{
if ( !Instigator.IsLocallyControlled() )
{
return false;
}
if(!UsesSecondaryAmmo())
{
return false;
}
// If the weapon wants to fire its primary weapon, and it can fire, do not allow weapon to automatically alt reload
if(PendingFire(DEFAULT_FIREMODE) && HasAmmo(DEFAULT_FIREMODE))
{
return false;
}
if(!CanReload(ALTFIRE_FIREMODE))
{
return false;
}
if (bIsAuto && AmmoCount[1] > 0)
{
return false;
}
if (bCanceledAltAutoReload)
{
return false;
}
return true;
}
simulated function TryToAltReload(bool bIsAuto)
{
if ((IsInState('Active') || IsInState('WeaponSprinting')) && CanAltAutoReload(bIsAuto))
{
SendToAltReload();
}
}
simulated function int GetSecondaryAmmoForHUD()
{
return AmmoCount[1];
}
simulated function int GetSecondarySpareAmmoForHUD()
{
return SpareAmmoCount[1];
}
simulated function ModifyRecoil( out float CurrentRecoilModifier )
{
if( CurrentFireMode == ALTFIRE_FIREMODE )
{
CurrentRecoilModifier *= AltFireRecoilScale;
}
super.ModifyRecoil( CurrentRecoilModifier );
}
/** Spawn projectile is called once for each shot pellet fired */
simulated function KFProjectile SpawnAllProjectiles(class<KFProjectile> KFProjClass, vector RealStartLoc, vector AimDir)
{
local KFPerk InstigatorPerk;
if (CurrentFireMode == ALTFIRE_FIREMODE)
{
InstigatorPerk = GetPerk();
if (InstigatorPerk != none)
{
Spread[CurrentFireMode] = default.Spread[CurrentFireMode] * InstigatorPerk.GetTightChokeModifier();
}
}
return super.SpawnAllProjectiles(KFProjClass, RealStartLoc, AimDir);
}
defaultproperties
{
bCanRefillSecondaryAmmo = true;
// Content
PackageKey="Famas"
FirstPersonMeshName="wep_1p_famas_mesh.Wep_1stP_Famas_Rig"
FirstPersonAnimSetNames(0)="wep_1p_famas_anim.Wep_1stP_Famas_Anim"
PickupMeshName="WEP_3P_Famas_MESH.WEP_Famas_Pickup"
AttachmentArchetypeName="Wep_Famas_ARCH.Wep_Famas_3P"
MuzzleFlashTemplateName="wep_famas_arch.Wep_Famas_MuzzleFlash"
ShotgunMuzzleFlashTemplate=KFMuzzleFlash'wep_famas_arch.Wep_Famas_Shotgun_MuzzleFlash'
// Scope Render
// 2D scene capture
Begin Object Name=SceneCapture2DComponent0
TextureTarget=TextureRenderTarget2D'Wep_Mat_Lib.WEP_ScopeLense_Target'
FieldOfView=12.5 // "2.0X" = 25.0(our real world FOV determinant)/2.0
End Object
ScopedSensitivityMod = 8.0
ScopeLenseMICTemplate = MaterialInstanceConstant'WEP_1P_FNFAL_MAT.WEP_1P_FNFAL_Scope_MAT'
ScopeMICIndex = 2
// FOV
MeshFov=65
MeshIronSightFOV=60 //45
PlayerIronSightFOV=70
// Depth of field
DOF_BlendInSpeed=3.0
DOF_FG_FocalRadius=0
DOF_FG_MaxNearBlurSize=3.5
// Zooming/Position
PlayerViewOffset=(X=22.0,Y=9.f,Z=-2.f)
IronSightPosition=(X=0,Y=0,Z=0)
// Ammo
MagazineCapacity[0]=30 //24
SpareAmmoCapacity[0]=240
InitialSpareMags[0]=3
bCanBeReloaded=true
bReloadFromMagazine=true
// Shotgun Ammo
MagazineCapacity[1]=6
SpareAmmoCapacity[1]=36 //42
InitialSpareMags[1]=1
// Recoil
maxRecoilPitch=100 //125 //200 //120
minRecoilPitch=75 //100 //150 //70
maxRecoilYaw=40 //80
minRecoilYaw=-40 //-80
RecoilRate=0.085
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=900
RecoilMinPitchLimit=65035
RecoilISMaxYawLimit=75
RecoilISMinYawLimit=65460
RecoilISMaxPitchLimit=375
RecoilISMinPitchLimit=65460
RecoilViewRotationScale=0.25
IronSightMeshFOVCompensationScale=1.7
HippedRecoilModifier=2.0 //1.5
// Inventory / Grouping
InventorySize=6
GroupPriority=80 //75
WeaponSelectTexture=Texture2D'WEP_UI_Famas_TEX.UI_WeaponSelect_Famas'
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletBurst'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponBurstFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_AssaultRifle'
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_FAMAS_Rifle'
PenetrationPower(DEFAULT_FIREMODE)=1.0
FireInterval(DEFAULT_FIREMODE)=+0.0667 // 900 RPM
InstantHitDamage(DEFAULT_FIREMODE)=35.0
Spread(DEFAULT_FIREMODE)=0.005 //0.0085
BurstAmount=3
BurstFire2RdAnim=Shoot_Burst2
BurstFire3RdAnim=Shoot_Burst
BurstFire2RdSightedAnim=Shoot_Burst2_Iron
BurstFire3RdSightedAnim=Shoot_Burst_Iron
FireOffset=(X=30,Y=4.5,Z=-5)
SecondaryFireOffset=(X=20.f,Y=4.5,Z=-7.f)
// ALT_FIREMODE
FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
FiringStatesArray(ALTFIRE_FIREMODE)=FiringSecondaryState
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_Pellet'
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_FAMAS_Shotgun'
InstantHitDamage(ALTFIRE_FIREMODE)=30.0 //25.0
PenetrationPower(ALTFIRE_FIREMODE)=2.0
FireInterval(ALTFIRE_FIREMODE)=+1.2 //50 RPM
NumPellets(ALTFIRE_FIREMODE)=7 //6
Spread(ALTFIRE_FIREMODE)=0.10 //0.12
SecondaryAmmoTexture=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_FAMAS'
InstantHitDamage(BASH_FIREMODE)=26
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_SA_AR15.Play_WEP_SA_AR15_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_SA_AR15.Play_WEP_SA_AR15_Fire_1P')
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_AR15.Play_WEP_SA_AR15_Handling_DryFire'
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_SA_AA12.Play_WEP_SA_AA12_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_SA_AA12.Play_WEP_SA_AA12_Fire_1P')
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_AA12.Play_WEP_SA_AA12_Handling_DryFire'
// Attachments
bHasIronSights=true
bHasFlashlight=false
AssociatedPerkClasses(0)=class'KFPerk_Commando'
AssociatedPerkClasses(1)=class'KFPerk_Support'
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.125f), (Stat=EWUS_Damage1, Scale=1.125f), (Stat=EWUS_Weight, Add=1)))
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.25f), (Stat=EWUS_Damage1, Scale=1.25f), (Stat=EWUS_Weight, Add=2)))
bUsesSecondaryAmmoAltHUD=true
AltFireRecoilScale = 4.5 //4.0 //2.5
}