//============================================================================= // KFWeap_Rifle_ParasiteImplanter //============================================================================= // Weapon code for parasite implanter. //============================================================================= // Killing Floor 2 // Copyright (C) 2021 Tripwire Interactive LLC //============================================================================= class KFWeap_Rifle_ParasiteImplanter extends KFWeap_ScopedBase; `define PARASITE_MIC_LED_INDEX 0 var float LastFireInterval; /** How many seed ammo to recharge per second */ var float SeedFullRechargeSeconds; /** How many ammo to recharge per second. */ var transient float SeedRechargePerSecond; var transient float SeedIncrement; var repnotify byte SeedAmmo; const SecondaryFireAnim = 'Shoot_Secondary'; const SecondaryFireIronAnim = 'Shoot_Secondary_Iron'; /** Material colors applied to different fire modes */ var LinearColor NoAmmoMaterialColor; var LinearColor AmmoReadyMaterialColor; /** How much recoil the altfire should do */ var protected const float AltFireRecoilScale; replication { if (bNetDirty && Role == ROLE_Authority) SeedAmmo; } simulated event ReplicatedEvent(name VarName) { if (VarName == nameof(SeedAmmo)) { if (AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE] && SeedAmmo >= AmmoCost[ALTFIRE_FIREMODE]) { UpdateMaterial(true); } else if (AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE] && SeedAmmo < AmmoCost[ALTFIRE_FIREMODE]) { UpdateMaterial(false); } AmmoCount[ALTFIRE_FIREMODE] = SeedAmmo; } else { Super.ReplicatedEvent(VarName); } } /********************************************************************************************* * @name Trader *********************************************************************************************/ /** Returns trader filter index based on weapon type */ static simulated event EFilterTypeUI GetTraderFilter() { if( default.FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponFiring' || default.FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponBurstFiring' ) { return FT_Assault; } else // if( FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponSingleFiring') { return FT_Rifle; } } simulated event PreBeginPlay() { super.PreBeginPlay(); StartSeedRecharge(); } function StartSeedRecharge() { // local KFPerk InstigatorPerk; local float UsedSeedRechargeTime; // begin ammo recharge on server if( Role == ROLE_Authority ) { UsedSeedRechargeTime = SeedFullRechargeSeconds; SeedRechargePerSecond = MagazineCapacity[ALTFIRE_FIREMODE] / UsedSeedRechargeTime; SeedIncrement = 0; } } function RechargeSeed(float DeltaTime) { if ( Role == ROLE_Authority ) { SeedIncrement += SeedRechargePerSecond * DeltaTime; if( SeedIncrement >= 1.0 && AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE] ) { AmmoCount[ALTFIRE_FIREMODE]++; SeedIncrement -= 1.0; SeedAmmo = AmmoCount[ALTFIRE_FIREMODE]; } } } /** Overridden to call StartHealRecharge on server */ function GivenTo( Pawn thisPawn, optional bool bDoNotActivate ) { super.GivenTo( thisPawn, bDoNotActivate ); if( Role == ROLE_Authority && !thisPawn.IsLocallyControlled() ) { StartSeedRecharge(); } } /********************************************************************************************* @name Actor ********************************************************************************************* */ simulated event Tick( FLOAT DeltaTime ) { local bool bWasLowAmmo; bWasLowAmmo = AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE]; if( AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE] ) { RechargeSeed(DeltaTime); } if (WorldInfo.NetMode != NM_DedicatedServer) { if (bWasLowAmmo && AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE]) { UpdateMaterial(true); } } else { if (bWasLowAmmo && AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE]) { NotifyAltAmmoReady(true); } } Super.Tick(DeltaTime); } /********************************************************************************************* * Trader ********************************************************************************************/ /** Allows weapon to set its own trader stats (can set number of stats, names and values of stats) */ static simulated event SetTraderWeaponStats( out array WeaponStats ) { super.SetTraderWeaponStats( WeaponStats ); WeaponStats.Length = WeaponStats.Length + 1; WeaponStats[WeaponStats.Length-1].StatType = TWS_RechargeTime; WeaponStats[WeaponStats.Length-1].StatValue = default.SeedFullRechargeSeconds; } /** Seeds doesn't count as ammo for purposes of inventory management (e.g. switching) */ simulated function bool HasAnyAmmo() { return HasSpareAmmo() || HasAmmo(DEFAULT_FIREMODE); } simulated function ConsumeAmmo( byte FireModeNum ) { local bool bWasHighAmmo; if( FireModeNum != ALTFIRE_FIREMODE ) { Super.ConsumeAmmo(FireModeNum); return; } `if(`notdefined(ShippingPC)) if( bInfiniteAmmo ) { return; } `endif bWasHighAmmo = AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE]; // If AmmoCount is being replicated, don't allow the client to modify it here if (Role == ROLE_Authority) { // Don't consume ammo if magazine size is 0 (infinite ammo with no reload) if (MagazineCapacity[1] > 0 && AmmoCount[1] > 0) { // Reduce ammo amount by heal ammo cost AmmoCount[1] = Max(AmmoCount[1] - AmmoCost[1], 0); } } if (WorldInfo.NetMode != NM_DedicatedServer) { if (bWasHighAmmo && AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE]) { UpdateMaterial(false); } } else if (bWasHighAmmo && AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE]) { NotifyAltAmmoReady(false); } } /** Instead of switch fire mode use as immediate alt fire */ simulated function AltFireMode() { if ( !Instigator.IsLocallyControlled() ) { return; } StartFire(ALTFIRE_FIREMODE); } simulated function float GetFireInterval(byte FireModeNum) { if (FireModeNum == DEFAULT_FIREMODE && AmmoCount[FireModeNum] == 0) { return LastFireInterval; } return super.GetFireInterval(FireModeNum); } simulated function name GetWeaponFireAnim(byte FireModeNum) { if (FireModeNum == ALTFIRE_FIREMODE) { return bUsingSights ? SecondaryFireIronAnim : SecondaryFireAnim; } return super.GetWeaponFireAnim(FireModeNum); } simulated function UpdateMaterial(bool HasEnoughAmmo) { local LinearColor MatColor; if (WorldInfo.NetMode != NM_DedicatedServer) { MatColor = HasEnoughAmmo ? AmmoReadyMaterialColor : NoAmmoMaterialColor; if( WeaponMICs.Length >= `PARASITE_MIC_LED_INDEX ) { WeaponMICs[`PARASITE_MIC_LED_INDEX].SetVectorParameterValue('Vector_GlowColor', MatColor); } } } /** Should replicate to 3P to show the alt fire ready */ simulated function NotifyAltAmmoReady(bool bActive) { local KFPawn KFP; if (WorldInfo.NetMode != NM_Client) { KFP = KFPawn(Instigator); KFP.OnWeaponSpecialAction(bActive ? 2 : 1); } } simulated function ModifyRecoil( out float CurrentRecoilModifier ) { if( CurrentFireMode == ALTFIRE_FIREMODE ) { CurrentRecoilModifier *= AltFireRecoilScale; } super.ModifyRecoil( CurrentRecoilModifier ); } simulated function bool ShouldAutoReload(byte FireModeNum) { if (FireModeNum == ALTFIRE_FIREMODE) return false; return super.ShouldAutoReload(FireModeNum); } /** Called during reload state */ simulated function bool CanOverrideMagReload(byte FireModeNum) { return super.CanOverrideMagReload(FireModeNum) || FireModeNum == ALTFIRE_FIREMODE; } defaultproperties { SeedFullRechargeSeconds=14 //10 // Inventory / Grouping InventorySize=7 GroupPriority=100 WeaponSelectTexture=Texture2D'wep_ui_parasiteimplanter_tex.UI_WeaponSelect_ParasiteImplanter' AssociatedPerkClasses(0)=class'KFPerk_FieldMedic' AssociatedPerkClasses(1)=class'KFPerk_SharpShooter' // FOV MeshFOV=70 //65 MeshIronSightFOV=27 //25 //45 PlayerIronSightFOV=70 //65 // Depth of field DOF_BlendInSpeed=3.0 DOF_FG_FocalRadius=0 //50 DOF_FG_MaxNearBlurSize=3.5 // Content PackageKey="ParasiteImplanter" FirstPersonMeshName="WEP_1P_ParasiteImplanter_MESH.Wep_1stP_ParasiteImplanter_Rig" FirstPersonAnimSetNames(0)="WEP_1P_ParasiteImplanter_ANIM.Wep_1stP_ParasiteImplanter_Anim" PickupMeshName="WEP_3P_ParasiteImplanter_MESH.Wep_3rdP_ParasiteImplanter_Pickup" AttachmentArchetypeName="WEP_ParasiteImplanter_ARCH.Wep_ParasiteImplanter_3P" MuzzleFlashTemplateName="WEP_ParasiteImplanter_ARCH.Wep_ParasiteImplanter_MuzzleFlash" // Ammo MagazineCapacity[0]=6 SpareAmmoCapacity[0]=78 InitialSpareMags[0]=3 bCanBeReloaded=true bReloadFromMagazine=true MagazineCapacity[1]=100 SeedAmmo=100 bCanRefillSecondaryAmmo=false // Zooming/Position PlayerViewOffset=(X=3.0,Y=8,Z=-1.8) //IronSightPosition=(X=0,Y=-0.07,Z=1.03) IronSightPosition=(X=0,Y=-0.09,Z=1.042) // AI warning system bWarnAIWhenAiming=true AimWarningDelay=(X=0.4f, Y=0.8f) AimWarningCooldown=0.0f // Recoil maxRecoilPitch=575 //700 minRecoilPitch=425 //600 maxRecoilYaw=135 minRecoilYaw=-135 RecoilRate=0.08 RecoilMaxYawLimit=500 RecoilMinYawLimit=65035 RecoilMaxPitchLimit=1250 RecoilMinPitchLimit=64785 RecoilISMaxYawLimit=50 RecoilISMinYawLimit=65485 RecoilISMaxPitchLimit=500 RecoilISMinPitchLimit=65485 RecoilViewRotationScale=0.6 IronSightMeshFOVCompensationScale=1.5 AltFireRecoilScale=0.2f // Scope Render // 2D scene capture Begin Object Name=SceneCapture2DComponent0 //TextureTarget=TextureRenderTarget2D'Wep_Mat_Lib.WEP_ScopeLense_Target' FieldOfView=12.5 //23.0 // "1.5X" = 35.0(our real world FOV determinant)/1.5 End Object ScopedSensitivityMod=8.0 //16.0 ScopeLenseMICTemplate=MaterialInstanceConstant'WEP_1P_ParasiteImplanter_MAT.Wep_1stP_Parasite_Lens_MIC' ScopeMICIndex = 2 // DEFAULT_FIREMODE FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletSingle' FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_ParasiteImplanter' InstantHitDamage(DEFAULT_FIREMODE)=275 //250 InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_ParasiteImplanter' FireInterval(DEFAULT_FIREMODE)=+1.0 //60 RPM Spread(DEFAULT_FIREMODE)=0.005 PenetrationPower(DEFAULT_FIREMODE)=3 FireOffset=(X=25,Y=3.0,Z=-2.5) LastFireInterval=0.3 // ALT_FIREMODE FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile FireInterval(ALTFIRE_FIREMODE)=+0.5 //+1.0 //+0.175 InstantHitDamage(ALTFIRE_FIREMODE)=1.0 Spread(ALTFIRE_FIREMODE)=0.005 AmmoCost(ALTFIRE_FIREMODE)=50 WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_ParasiteImplanterAlt' InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_ParasiteImplanterAlt' SecondaryAmmoTexture=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity' // BASH_FIREMODE InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_ParasiteImplanter' InstantHitDamage(BASH_FIREMODE)=26 // Custom animations FireSightedAnims=(Shoot_Iron) BonesToLockOnEmpty=(RW_Hammer) bHasFireLastAnims=true // Fire Effects WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_3P_Rifle', FirstPersonCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_1P_Rifle') WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_Dry_Fire_Rifle' WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_3P_Altfire', FirstPersonCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_1P_Altfire') WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_Dry_Fire_Altfire' EjectedShellForegroundDuration=1.5f // Attachments bHasIronSights=true bHasFlashlight=false WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Medium_Recoil' WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Weight, Add=1))) // From original KFWeap_RifleBase base class AimCorrectionSize=40.f NoAmmoMaterialColor=(R=0.0f,G=0.0f,B=0.0f) AmmoReadyMaterialColor=(R=0.08f,G=1.0f,B=0.08f) NumBloodMapMaterials=2 }