1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFWeap_Shotgun_S12.uc

717 lines
20 KiB
Ucode
Raw Permalink Normal View History

2023-05-11 15:55:04 +00:00
//=============================================================================
// KFWeap_Shotgun_S12
//=============================================================================
// AA12 Auto Shotgun Weapon Class
//=============================================================================
// Killing Floor 2
// Copyright (C) 2023 Tripwire Interactive LLC
//=============================================================================
class KFWeap_Shotgun_S12 extends KFWeap_ShotgunBase;
var (Positioning) vector SecondaryFireOffset;
const SecondaryFireAnim = 'Shoot_Secondary';
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
const SecondaryReloadAnim = 'Reload_Secondary';
const SecondaryReloadEliteAnim = 'Reload_Secondary_Elite';
2023-05-25 20:42:10 +00:00
var transient KFMuzzleFlash SecondaryMuzzleFlash;
2023-05-11 15:55:04 +00:00
var() KFMuzzleFlash SecondaryMuzzleFlashTemplate;
// Used on the server to keep track of grenades
var int ServerTotalAltAmmo;
var transient bool bCanceledAltAutoReload;
var GameExplosion ExplosionTemplate;
var transient ParticleSystemComponent ExplosionPSC;
var ParticleSystem ExplosionEffect;
var float ExplosionOriginalDamage;
simulated event PostBeginPlay()
{
super.PostBeginPlay();
ExplosionOriginalDamage = ExplosionTemplate.Damage;
}
/** Instead of switch fire mode use as immediate alt fire */
simulated function AltFireMode()
{
if ( !Instigator.IsLocallyControlled() )
{
return;
}
if (bCanceledAltAutoReload)
{
bCanceledAltAutoReload = false;
TryToAltReload();
return;
}
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 cuurent state of bCanceledAltAutoReload in case its not possible to do the reload
bStoredAutoReload = bCanceledAltAutoReload;
bCanceledAltAutoReload = false;
if(CanAltAutoReload())
{
TryToAltReload();
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 && Instigator != none && 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();
}
function SetOriginalValuesFromPickup( KFWeapon PickedUpWeapon )
{
local KFWeap_Shotgun_S12 Weap;
Super.SetOriginalValuesFromPickup(PickedUpWeapon);
if(Role == ROLE_Authority && !Instigator.IsLocallyControlled())
{
Weap = KFWeap_Shotgun_S12(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];
}
}
/*********************************************************************************************
* State GrenadeFiring
* Handles firing grenade launcher.
*********************************************************************************************/
simulated state FiringSecondaryState extends WeaponSingleFiring
{
// 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 throwing grenades
*/
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)
{
return bUsingSights ? SecondaryFireIronAnim : SecondaryFireAnim;
}
}
/**
* 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)
{
2023-05-25 20:42:10 +00:00
if (SecondaryMuzzleFlash == None)
2023-05-11 15:55:04 +00:00
{
2023-05-25 20:42:10 +00:00
AttachMuzzleFlash();
2023-05-11 15:55:04 +00:00
}
2023-05-25 20:42:10 +00:00
if (SecondaryMuzzleFlash != none)
{
SecondaryMuzzleFlash.CauseMuzzleFlash(FireModeNum);
}
2023-05-11 15:55:04 +00:00
2023-05-25 20:42:10 +00:00
if (SecondaryMuzzleFlash.bAutoActivateShellEject)
{
SecondaryMuzzleFlash.CauseShellEject();
SetShellEjectsToForeground();
}
2023-05-11 15:55:04 +00:00
}
else
{
Super.CauseMuzzleFlash(FireModeNum);
}
}
2023-05-25 20:42:10 +00:00
simulated function AttachMuzzleFlash()
2023-05-11 15:55:04 +00:00
{
2023-05-25 20:42:10 +00:00
super.AttachMuzzleFlash();
2023-05-11 15:55:04 +00:00
if ( MySkelMesh != none )
{
2023-05-25 20:42:10 +00:00
if (SecondaryMuzzleFlashTemplate != None)
2023-05-11 15:55:04 +00:00
{
2023-05-25 20:42:10 +00:00
SecondaryMuzzleFlash = new(self) Class'KFMuzzleFlash'(SecondaryMuzzleFlashTemplate);
SecondaryMuzzleFlash.AttachMuzzleFlash(MySkelMesh, 'MuzzleFlashAlt');
2023-05-11 15:55:04 +00:00
}
}
}
/*********************************************************************************************
* 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];
GotoState('AltReloading');
if ( Role < ROLE_Authority )
{
ServerSendToAltReload();
}
}
/** Called from client when reload starts */
reliable server function ServerSendToAltReload()
{
ReloadAmountLeft = MagazineCapacity[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));
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 )
{
return (bTacticalReload) ? SecondaryReloadEliteAnim : SecondaryReloadAnim;
}
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] = min(Amount, MagazineCapacity[1]);
}
/** 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();
}
}
/** Network: Local Player */
simulated function bool CanAltAutoReload()
{
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 (bCanceledAltAutoReload)
{
return false;
}
return true;
}
simulated function TryToAltReload()
{
if ((IsInState('Active') || IsInState('WeaponSprinting')) && CanAltAutoReload())
{
SendToAltReload();
}
}
simulated function TriggerAltExplosion()
{
local vector MuzzleLocation, HitLocation, HitNormal;
local KFExplosionActorReplicated ExploActor;
// TriggerExplosion
if (Role == ROLE_Authority)
{
MuzzleLocation = GetMuzzleLoc();
2023-09-21 19:31:11 +00:00
Trace( HitLocation, HitNormal, MuzzleLocation + vect(0, 0, -1) * 250000, MuzzleLocation,,,,TRACEFLAG_BULLET);
2023-05-11 15:55:04 +00:00
// Move a bit from hit location
HitLocation = HitLocation + (vect(0,0,1) * 128.f);
// Explode using the given template
ExploActor = Spawn(class'KFExplosionActorReplicated', self,, HitLocation, rotator(vect(0,0,1)),, true);
if (ExploActor != None)
{
ExploActor.InstigatorController = Instigator.Controller;
ExploActor.Instigator = Instigator;
ExploActor.bIgnoreInstigator = true;
ExplosionTemplate.Damage = ExplosionOriginalDamage * GetUpgradeDamageMod(ALTFIRE_FIREMODE);
ExploActor.Explode(ExplosionTemplate);
}
}
if (WorldInfo.NetMode != NM_DedicatedServer)
{
// Trigger VFX ?
if (HitLocation == vect(0,0,0))
{
MySkelMesh.GetSocketWorldLocationAndRotation('MuzzleFlashAlt', MuzzleLocation);
Trace( HitLocation, HitNormal, MuzzleLocation + vect(0, 0, -1) * 250000, MuzzleLocation);
// Move a bit from hit location
HitLocation = HitLocation + (vect(0,0,1) * 128.f);
}
if (ExplosionEffect != None)
{
ExplosionPSC = WorldInfo.MyEmitterPool.SpawnEmitter(ExplosionEffect, HitLocation, rotator(vect(0,0,1)));
ExplosionPSC.ActivateSystem();
}
}
}
simulated function CustomFire()
{
// Alt-fire blast only (server authoritative)
if ( CurrentFireMode != ALTFIRE_FIREMODE )
{
Super.CustomFire();
return;
}
TriggerAltExplosion();
IncrementFlashCount();
}
simulated event Tick(float DeltaTime)
{
local vector SocketLocation;
Super.Tick(DeltaTime);
// Client only
if (WorldInfo.NetMode != NM_DedicatedServer)
{
KFSkeletalMeshComponent(Mesh).GetSocketWorldLocationAndRotation('MuzzleFlashAlt', SocketLocation);
if (ExplosionPSC != None && ExplosionPSC.bIsActive)
{
ExplosionPSC.SetVectorParameter('WeaponEndpoint', SocketLocation);
}
}
}
defaultproperties
{
bCanRefillSecondaryAmmo = true;
// Shooting Animations
FireSightedAnims[0]=Shoot_Iron
FireSightedAnims[1]=Shoot_Iron2
FireSightedAnims[2]=Shoot_Iron3
// FOV
MeshFOV=86
MeshIronSightFOV=35
PlayerIronSightFOV=70
// Depth of field
DOF_FG_FocalRadius=85
DOF_FG_MaxNearBlurSize=3.5
// Content
PackageKey="Saiga12"
FirstPersonMeshName="Wep_1P_Saiga12_MESH.Wep_1stP_Saiga12_Rig"
FirstPersonAnimSetNames(0)="Wep_1P_Saiga12_ANIM.Wep_1stP_Saiga12_Anim_New"
PickupMeshName="WEP_3P_Saiga12_MESH.Wep_Saiga12_Pickup"
AttachmentArchetypeName="WEP_Saiga12_ARCH.Wep_Saiga12_3P"
MuzzleFlashTemplateName="WEP_Saiga12_ARCH.Wep_Saiga12_MuzzleFlash"
SecondaryMuzzleFlashTemplate=KFMuzzleFlash'WEP_Saiga12_ARCH.Wep_Saiga12_MuzzleFlashAlt'
// Zooming/Position
PlayerViewOffset=(X=0,Y=12.5,Z=-18)//
IronSightPosition=(X=12,Y=0,Z=-10.6)
// Pickup
AmmoPickupScale[0]=2.0
AmmoPickupScale[1]=1.0
// Ammo
MagazineCapacity[0]=10
SpareAmmoCapacity[0]=130
InitialSpareMags[0]=4
//grenades
MagazineCapacity[1]=1
SpareAmmoCapacity[1]=5
InitialSpareMags[1]=2
bCanBeReloaded=true
bReloadFromMagazine=true
// Recoil
maxRecoilPitch=250
minRecoilPitch=225
maxRecoilYaw=125
minRecoilYaw=-125
RecoilRate=0.075
RecoilBlendOutRatio=0.25
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=900
RecoilMinPitchLimit=64785
RecoilISMaxYawLimit=75
RecoilISMinYawLimit=65460
RecoilISMaxPitchLimit=375
RecoilISMinPitchLimit=65460
RecoilViewRotationScale=0.7
FallingRecoilModifier=1.5
HippedRecoilModifier=1.25
SecondaryAmmoTexture=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity'
bUseGrenadeAsSecondaryAmmo=true
// Inventory / Grouping
InventorySize=8
GroupPriority=100
WeaponSelectTexture=Texture2D'WEP_UI_Saiga12_TEX.UI_WeaponSelect_Saiga12'
AssociatedPerkClasses(0)=class'KFPerk_Support'
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_Pellet'
2023-05-25 20:42:10 +00:00
InstantHitDamage(DEFAULT_FIREMODE)=28.0 //25 //20
2023-05-11 15:55:04 +00:00
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_Shotgun_S12'
PenetrationPower(DEFAULT_FIREMODE)=2.0
FireInterval(DEFAULT_FIREMODE)=0.2 // 300 RPM
2023-05-25 20:42:10 +00:00
Spread(DEFAULT_FIREMODE)=0.12
2023-05-11 15:55:04 +00:00
FireOffset=(X=30,Y=5,Z=-4)
NumPellets(DEFAULT_FIREMODE)=7
// ALT_FIREMODE
FiringStatesArray(ALTFIRE_FIREMODE)=FiringSecondaryState
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Custom
AmmoCost(ALTFIRE_FIREMODE)=1
FireInterval(ALTFIRE_FIREMODE)=+0.25 // 300 RPM
SecondaryFireOffset=(X=20.f,Y=4.5,Z=-7.f)
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_Shotgun_S12'
InstantHitDamage(BASH_FIREMODE)=30
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Saiga12.Play_WEP_Saiga12_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_Saiga12.Play_WEP_Saiga12_Fire_1P')
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Saiga12.Play_WEP_Saiga12_Alt_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_Saiga12.Play_WEP_Saiga12_Alt_Fire_1P')
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_Saiga12.Play_WEP_Saiga12_Handling_DryFire'
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_Saiga12.Play_WEP_Saiga12_Handling_DryFire'
WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Heavy_Recoil'
// Attachments
bHasIronSights=true
bHasFlashlight=false
// Weapon Upgrade stat boosts
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
// Grenade explosion light
Begin Object Class=PointLightComponent Name=ExplosionPointLight
LightColor=(R=252,G=218,B=171,A=255)
Brightness=0.5f
Radius=400.f
FalloffExponent=10.f
CastShadows=False
CastStaticShadows=FALSE
CastDynamicShadows=False
bCastPerObjectShadows=false
bEnabled=FALSE
LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE)
End Object
// explosion
Begin Object Class=KFGameExplosion Name=ExploTemplate0
Damage=200
DamageRadius=800
DamageFalloffExponent=0.f
DamageDelay=0.f
MomentumTransferScale=10000
bAlwaysFullDamage=true
bDoCylinderCheck=true
// Damage Effects
MyDamageType=class'KFDT_Explosive_Shotgun_S12'
KnockDownStrength=150
FractureMeshRadius=200.0
FracturePartVel=500.0
ExplosionSound=AkEvent'WW_WEP_Saiga12.Play_WEP_Saiga12_Alt_Fire_3P'
ExplosionEffects=KFImpactEffectInfo'WEP_Saiga12_ARCH.WEP_Saiga12_Impacts'
// Dynamic Light
ExploLight=ExplosionPointLight
ExploLightStartFadeOutTime=0.0
ExploLightFadeOutTime=0.3
bIgnoreInstigator=true
ActorClassToIgnoreForDamage = class'KFPawn_Human'
// Camera Shake
CamShake=CameraShake'FX_CameraShake_Arch.Misc_Explosions.Light_Explosion_Rumble'
CamShakeInnerRadius=0
CamShakeOuterRadius=300
CamShakeFalloff=1.5f
bOrientCameraShakeTowardsEpicenter=true
End Object
ExplosionTemplate=ExploTemplate0
ExplosionEffect=ParticleSystem'WEP_1P_Saiga12_EMIT.FX_Saiga12_Explosion'
}