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

498 lines
13 KiB
Ucode

//=============================================================================
// KFWeap_HRG_BlastBrawlers
//=============================================================================
// Power gloves and shotgun, all in one.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeap_HRG_BlastBrawlers extends KFWeap_Blunt_PowerGloves;
var name ReloadAnimation;
var float ReloadAnimRateModifier;
var float ReloadAnimRateModifierElite;
var protected transient bool bWaitingForSecondShot;
var protected transient int NumAttacks;
/** A muzzle flash instance for left weapon */
var KFMuzzleFlash LeftMuzzleFlash;
simulated event PreBeginPlay()
{
super.PreBeginPlay();
}
simulated function Shoot()
{
// LocalPlayer Only
if ( !Instigator.IsLocallyControlled() )
{
return;
}
if( Role < Role_Authority )
{
// if we're a client, synchronize server
ServerShoot();
}
ProcessShoot();
}
/**
Each attack shoots twice, once with the right and left fists.
Ammo is decremented after the second shot.
*/
reliable server function bool ServerShoot()
{
return ProcessShoot();
}
simulated function bool ProcessShoot()
{
// Shooting only happens when default firing
if(CurrentFireMode != DEFAULT_FIREMODE)
return false;
CustomFire();
if (!bWaitingForSecondShot)
{
// AmmoCount[DEFAULT_FIREMODE] = Max(AmmoCount[DEFAULT_FIREMODE] - 1, 0);
DecrementAmmo();
}
bWaitingForSecondShot = !bWaitingForSecondShot;
return true;
}
simulated function DecrementAmmo()
{
AmmoCount[DEFAULT_FIREMODE] = Max(AmmoCount[DEFAULT_FIREMODE] - 1, 0);
}
simulated state Active
{
/**
* Called from Weapon:Active.BeginState when HasAnyAmmo (which is overridden above) returns false.
*/
simulated function WeaponEmpty()
{
local int i;
// Copied from Weapon:Active.BeginState where HasAnyAmmo returns true.
// Basically, pretend the weapon isn't empty in this case.
for (i=0; i<GetPendingFireLength(); i++)
{
if (PendingFire(i))
{
BeginFire(i);
break;
}
}
}
}
static simulated event bool UsesAmmo()
{
return true;
}
simulated function CustomFire()
{
local byte CachedFireMode;
CachedFireMode = CurrentFireMode;
CurrentFireMode = CUSTOM_FIREMODE;
ProjectileFire();
// Let the accuracy tracking system know that we fired
HandleWeaponShotTaken(CurrentFireMode);
NotifyWeaponFired(CurrentFireMode);
// Play fire effects now (don't wait for WeaponFired to replicate)
PlayFireEffects(CurrentFireMode, vect(0, 0, 0));
CurrentFireMode = CachedFireMode;
}
/** Overriden for the Tight Choke perk */
simulated function KFProjectile SpawnAllProjectiles(class<KFProjectile> KFProjClass, vector RealStartLoc, vector AimDir)
{
local KFPerk InstigatorPerk;
if (CurrentFireMode == CUSTOM_FIREMODE)
{
InstigatorPerk = GetPerk();
if (InstigatorPerk != none)
{
Spread[CurrentFireMode] = default.Spread[CurrentFireMode] * InstigatorPerk.GetTightChokeModifier();
}
}
return super.SpawnAllProjectiles(KFProjClass, RealStartLoc, AimDir);
}
/** Override for not playing animations (even if noanimation is set it interrupts the melee ones.) */
simulated function PlayFireEffects( byte FireModeNum, optional vector HitLocation )
{
// If we have stopped the looping fire sound to play single fire sounds for zed time
// start the looping sound back up again when the time is back above zed time speed
if( FireModeNum < bLoopingFireSnd.Length && bLoopingFireSnd[FireModeNum] && !bPlayingLoopingFireSnd )
{
StartLoopingFireSound(FireModeNum);
}
PlayFiringSound(CurrentFireMode);
if( Instigator != none )
{
if( Instigator.IsLocallyControlled() )
{
if( Instigator.IsFirstPerson() )
{
// Start muzzle flash effect
CauseMuzzleFlash(FireModeNum);
}
ShakeView();
}
}
}
/**
* @see Weapon::StartFire
*/
simulated function StartFire(byte FireModeNum)
{
// can't start fire because it's in an uninterruptible state
if (StartFireDisabled)
{
return;
}
if (FireModeNum == DEFAULT_FIREMODE)
{
if(AmmoCount[DEFAULT_FIREMODE] > 0)
{
StartMeleeFire(FireModeNum, DIR_FORWARD, ATK_Normal);
}
else
{
super.StartFire(RELOAD_FIREMODE);
// If not cleared, it will loop the animation.
ClearPendingFire(RELOAD_FIREMODE);
}
return;
}
super.StartFire(FireModeNum);
}
/** Avoiding reload anim to interrupt combo */
simulated state MeleeChainAttacking
{
simulated function BeginState(Name PrevStateName)
{
local KFPerk InstigatorPerk;
if( CurrentFireMode == DEFAULT_FIREMODE )
{
StartFireDisabled = true;
bWaitingForSecondShot = false;
NumAttacks = 0;
}
InstigatorPerk = GetPerk();
if (InstigatorPerk != none)
{
SetZedTimeResist( InstigatorPerk.GetZedTimeModifier(self) );
}
super.BeginState( PrevStateName );
}
simulated function EndState(Name NextStateName)
{
super.EndState(NextStateName);
if( CurrentFireMode == DEFAULT_FIREMODE )
{
StartFireDisabled = false;
}
ClearZedTimeResist();
}
simulated function bool ShouldContinueMelee(optional int ChainCount)
{
if ( CurrentFireMode == DEFAULT_FIREMODE )
{
return false;
}
return super.ShouldContinueMelee(ChainCount);
}
}
/**
* Called on a client, this function Attaches the WeaponAttachment
* to the Mesh.
*
* Overridden to attach LeftMuzzleFlash
*/
simulated function AttachMuzzleFlash()
{
super.AttachMuzzleFlash();
if ( MySkelMesh != none )
{
if (MuzzleFlashTemplate != None)
{
LeftMuzzleFlash = new(self) Class'KFMuzzleFlash'(MuzzleFlashTemplate);
LeftMuzzleFlash.AttachMuzzleFlash(MySkelMesh, 'MuzzleFlash_L');
}
}
}
/**
* Causes the muzzle flash to turn on and setup a time to
* turn it back off again.
*
* Overridden to cause left weapon flash
*/
simulated function CauseMuzzleFlash(byte FireModeNum)
{
if( MuzzleFlash == None || LeftMuzzleFlash == None )
{
AttachMuzzleFlash();
}
if( bWaitingForSecondShot )
{
if (MuzzleFlash != None )
{
// Not ejecting shells for this weapon.
MuzzleFlash.CauseMuzzleFlash(FireModeNum);
}
}
else
{
if( LeftMuzzleFlash != None )
{
// Not ejecting shells for this weapon.
LeftMuzzleFlash.CauseMuzzleFlash(FireModeNum);
}
}
}
/**
* Remove/Detach the muzzle flash components
*/
simulated function DetachMuzzleFlash()
{
super.DetachMuzzleFlash();
if (MySkelMesh != none && LeftMuzzleFlash != None)
{
LeftMuzzleFlash.DetachMuzzleFlash(MySkelMesh);
LeftMuzzleFlash = None;
}
}
/**
* Adjust the FOV for the first person weapon and arms.
*/
simulated event SetFOV( float NewFOV )
{
super.SetFOV( NewFOV );
if( LeftMuzzleFlash != none )
{
LeftMuzzleFlash.SetFOV( NewFOV );
}
}
simulated function StopFireEffects(byte FireModeNum)
{
super.StopFireEffects( FireModeNum );
if (LeftMuzzleFlash != None)
{
LeftMuzzleFlash.StopMuzzleFlash();
}
}
/** Returns true if weapon can potentially be reloaded */
simulated function bool CanReload(optional byte FireModeNum)
{
if ( FiringStatesArray[RELOAD_FIREMODE] == 'WeaponUpkeep' )
{
return true;
}
if ( FireModeNum == CUSTOM_FIREMODE)
{
FireModeNum = DEFAULT_FIREMODE;
}
return Super.CanReload(FireModeNum);
}
simulated function name GetReloadAnimName( bool bTacticalReload )
{
return ReloadAnimation;
}
/** No diferent states */
simulated function EReloadStatus GetNextReloadStatus(optional byte FireModeNum)
{
switch ( ReloadStatus )
{
case RS_None: //drop
case RS_Reloading:
if ( HasSpareAmmo(FiremodeNum) && ReloadAmountLeft > 0 )
{
return RS_Reloading;
}
}
return RS_Complete;
}
/** Returns an anim rate scale for reloading */
simulated function float GetReloadRateScale()
{
local float Modifier;
Modifier = UseTacticalReload() ? ReloadAnimRateModifierElite : ReloadAnimRateModifier;
return super.GetReloadRateScale() * Modifier;
}
simulated function bool HasAnyAmmo()
{
return AmmoCount[0] > 0 || SpareAmmoCount[0] > 0;
}
simulated function int GetMeleeDamage(byte FireModeNum, optional vector RayDir)
{
local int Damage;
Damage = GetModifiedDamage(FireModeNum, RayDir);
// decode damage scale (see GetDamageScaleByAngle) from the RayDir
if ( !IsZero(RayDir) )
{
Damage = Round(float(Damage) * FMin(VSize(RayDir), 1.f));
}
return Damage;
}
defaultproperties
{
// Content
PackageKey="HRG_BlastBrawlers"
FirstPersonMeshName="WEP_1P_HRG_BlastBrawlers_MESH.WEP_1stP_HRG_Blast_Brawlers_Rig"
FirstPersonAnimSetNames(0)="WEP_1P_HRG_BlastBrawlers_ANIM.WEP_1P_HRG_BlastBrawlers_ANIM"
PickupMeshName="WEP_3P_HRG_BlastBrawlers_MESH.Wep_HRG_Blast_Brawlers_Pickup"
AttachmentArchetypeName="WEP_HRG_BlastBrawlers_ARCH.Wep_HRG_BlastBrawlers_3P"
MuzzleFlashTemplateName="WEP_HRG_BlastBrawlers_ARCH.Wep_HRG_BlastBrawler_MuzzleFlash"
Begin Object Class=KFMeleeHelperWeaponBlastBrawlers Name=MeleeHelper_0
MaxHitRange=230 //150 //190
// Override automatic hitbox creation (advanced)
HitboxChain.Add((BoneOffset=(Y=+3,Z=150)))
HitboxChain.Add((BoneOffset=(Y=-3,Z=130)))
HitboxChain.Add((BoneOffset=(Y=+3,Z=110)))
HitboxChain.Add((BoneOffset=(Y=-3,Z=90)))
HitboxChain.Add((BoneOffset=(Y=+3,Z=70)))
HitboxChain.Add((BoneOffset=(Y=-3,Z=50)))
HitboxChain.Add((BoneOffset=(Y=+3,Z=30)))
HitboxChain.Add((BoneOffset=(Z=10)))
HitboxChain.Add((BoneOffset=(Z=-10)))
WorldImpactEffects=KFImpactEffectInfo'FX_Impacts_ARCH.Blunted_melee_impact'
// modified combo sequences
bAllowMeleeToFracture=false
bUseDirectionalMelee=true
bHasChainAttacks=false
MeleeImpactCamShakeScale=0.035f //0.4
ChainSequence_F=()
ChainSequence_B=()
ChainSequence_L=()
ChainSequence_R=()
End Object
MeleeAttackHelper=MeleeHelper_0
// FOV
//MeshFOV=95
// Shotgun Ammo
MagazineCapacity[0]=4 //3
SpareAmmoCapacity[0]=40 //36 //28
InitialSpareMags[0]=2
AmmoPickupScale[0]=1.5 //2.0
bCanBeReloaded=true
bReloadFromMagazine=true
bNoMagazine=false
// Zooming/Position
PlayerViewOffset=(X=20,Y=0,Z=0)
// Inventory
GroupPriority=110
InventorySize=9 //7
WeaponSelectTexture=Texture2D'WEP_UI_HRG_BlastBrawlers_TEX.UI_WeaponSelect_HRG_BlastBrawlers'
FireModeIconPaths(CUSTOM_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
FiringStatesArray(CUSTOM_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(CUSTOM_FIREMODE)=EWFT_Projectile
WeaponProjectiles(CUSTOM_FIREMODE)=class'KFProj_Bullet_BlastBrawlers'
FireInterval(CUSTOM_FIREMODE)=0.1f
InstantHitDamageTypes(CUSTOM_FIREMODE)=class'KFDT_Ballistic_BlastBrawlersShotgun'
InstantHitDamage(CUSTOM_FIREMODE)=39.0 //36.0 //30.0
AmmoCost(CUSTOM_FIREMODE)=0
NumPellets(CUSTOM_FIREMODE)=5
Spread(CUSTOM_FIREMODE)=0.12 //0.1 //0.15
WeaponFireSnd(CUSTOM_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_HRG_BlastBrawlers.Play_WEP_HRG_BlastBrawlers_Shoot_3P', FirstPersonCue=AkEvent'WW_WEP_HRG_BlastBrawlers.Play_WEP_HRG_BlastBrawlers_Shoot_1P')
InstantHitMomentum(CUSTOM_FIREMODE)=1.0
PenetrationPower(CUSTOM_FIREMODE)=2.0
PenetrationDamageReductionCurve(CUSTOM_FIREMODE)=(Points=((InVal=0.f,OutVal=0.f),(InVal=1.f, OutVal=1.f)))
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
InstantHitDamage(DEFAULT_FIREMODE)=50
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Bludgeon_BlastBrawlers'
FireModeIconPaths(HEAVY_ATK_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BluntMelee'
InstantHitDamage(HEAVY_ATK_FIREMODE)=200 //175
InstantHitDamageTypes(HEAVY_ATK_FIREMODE)=class'KFDT_Bludgeon_BlastBrawlersHeavy'
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_BlastBrawlersBash'
InstantHitDamage(BASH_FIREMODE)=100
FiringStatesArray(RELOAD_FIREMODE)=Reloading
AssociatedPerkClasses(0)=class'KFPerk_Support'
// Block Sounds
BlockSound=AkEvent'WW_WEP_Bullet_Impacts.Play_Block_MEL_Crovel'
ParrySound=AkEvent'WW_WEP_Bullet_Impacts.Play_Parry_Metal'
ParryStrength=5
ParryDamageMitigationPercent=0.40
BlockDamageMitigation=0.50 //0.40
bWaitingForSecondShot = false
NumAttacks = 0
bAllowClientAmmoTracking=false
ReloadAnimation = "Atk_B"
ReloadAnimRateModifier = 1.6f
ReloadAnimRateModifierElite = 1.0f; //0.5f;
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.125f), (Stat=EWUS_Damage1, Scale=1.125f), (Stat=EWUS_Damage2, Scale=1.125f), (Stat=EWUS_Weight, Add=1)))
}