diff --git a/Engine/Classes/GravityVolume.uc b/Engine/Classes/GravityVolume.uc index 6b405c3..4712a6f 100644 --- a/Engine/Classes/GravityVolume.uc +++ b/Engine/Classes/GravityVolume.uc @@ -11,13 +11,21 @@ class GravityVolume extends PhysicsVolume /** Gravity along Z axis applied to objects inside this volume. */ var() float GravityZ; +/** Scaling GravityZ and being used different function (GetGravityZHuman) to retrieve GravityZ */ +var() float ScaleGravityHuman; +/** Scaling GravityZ and being used different function (GetGravityZMonster) to retrieve GravityZ */ +var() float ScaleGravityMonster; cpptext { virtual FLOAT GetGravityZ() { return GravityZ; } + virtual FLOAT GetGravityZHuman() { return GravityZ * ScaleGravityHuman; } + virtual FLOAT GetGravityZMonster() { return GravityZ * ScaleGravityMonster; } } defaultproperties { GravityZ = -520.0 + ScaleGravityHuman = 1.0 + ScaleGravityMonster = 1.0 } diff --git a/Engine/Classes/Pawn.uc b/Engine/Classes/Pawn.uc index 6c8ddda..e5dceca 100644 --- a/Engine/Classes/Pawn.uc +++ b/Engine/Classes/Pawn.uc @@ -2596,10 +2596,17 @@ event TakeDamage(int Damage, Controller InstigatedBy, vector HitLocation, vector Killer = SetKillInstigator(InstigatedBy, DamageType); TearOffMomentum = momentum; Died(Killer, damageType, HitLocation); + + // using the passed in damage type instead of the hitfxinfo since that doesn't get updated when zero damage is done + HandleAfflictionsOnHit(InstigatedBy, Normal(Momentum), DamageType, DamageCauser); } else { HandleMomentum( momentum, HitLocation, DamageType, HitInfo ); + + // using the passed in damage type instead of the hitfxinfo since that doesn't get updated when zero damage is done + HandleAfflictionsOnHit(InstigatedBy, Normal(Momentum), DamageType, DamageCauser); + NotifyTakeHit(InstigatedBy, HitLocation, ActualDamage, DamageType, Momentum, DamageCauser); if (DrivenVehicle != None) { @@ -2619,6 +2626,8 @@ event TakeDamage(int Damage, Controller InstigatedBy, vector HitLocation, vector `endif } +function HandleAfflictionsOnHit(Controller DamageInstigator, vector HitDir, class DamageType, Actor DamageCauser); + /* * Queries the PRI and returns our current team index. */ diff --git a/Engine/Classes/PhysicsVolume.uc b/Engine/Classes/PhysicsVolume.uc index f62a737..fcb80ad 100644 --- a/Engine/Classes/PhysicsVolume.uc +++ b/Engine/Classes/PhysicsVolume.uc @@ -79,6 +79,8 @@ cpptext } native function float GetGravityZ(); +native function float GetGravityZHuman(); +native function float GetGravityZMonster(); native function vector GetZoneVelocityForActor(Actor TheActor); simulated event PostBeginPlay() diff --git a/KFGame/Classes/EphemeralMatchStats.uc b/KFGame/Classes/EphemeralMatchStats.uc index e8f35c9..a61a835 100644 --- a/KFGame/Classes/EphemeralMatchStats.uc +++ b/KFGame/Classes/EphemeralMatchStats.uc @@ -43,6 +43,7 @@ var array TeamAwardList; enum ETeamAwards { + ETA_ZedStomper, ETA_MedicineMaster, ETA_ZedSlayer, ETA_Enforcer, @@ -70,7 +71,8 @@ enum EPersonalBests EPB_Assists, EPB_LargeZedKill, EPB_Dosh, - EPB_DoorWelding + EPB_DoorWelding, + EPB_ZedStomps }; var array PersonalBestList; @@ -99,6 +101,7 @@ var int TotalAmountHealGiven; //dialog var int TotalAmountHealReceived; //dialog var int TotalLargeZedKills; +var int TotalStomps; var bool bKilledBoss; @@ -158,6 +161,9 @@ function RecordIntStat(int StatID, int Value) case MATCH_EVENT_HEAL_RECEIVED: IncrementHealReceivedInWave(Value); break; + case MATCH_EVENT_STOMP_GIVEN: + IncrementStompsGivenInWave(Value); + break; } } @@ -224,6 +230,16 @@ function int GetHealGivenInWave() return PWRI.VectData2.Z; } +function IncrementStompsGivenInWave(int Delta) +{ + PWRI.NumStomps += Delta; +} + +function int GetStompsGivenInWave() +{ + return PWRI.NumStomps; +} + //Called at the end of the wave. @Note - End of wave is also called with the loss condition is met. This includes at trader time. function RecordWaveInfo() { @@ -239,6 +255,7 @@ function RecordWaveInfo() TotalAmountHealReceived += GetHealReceivedInWave(); TotalDamageTaken += GetDamageTakenInWave(); TotalDamageDealt += GetDamageDealtInWave(); + TotalStomps += GetStompsGivenInWave(); if ( PWRI.bDiedDuringWave ) { @@ -273,6 +290,7 @@ function ResetLastWaveInfo() PWRI.bSomeSurvivedLastWave = false; PWRI.bOneSurvivedLastWave = false; PWRI.bDiedDuringWave = false; + PWRI.NumStomps = 0; ZedsKilledLastWave = 0; } @@ -736,6 +754,9 @@ function GetPersonalBests(out Array PersonalBests) PersonalBests.AddItem( GivePersonalBestDoshEarned() ); //Headshots PersonalBests.AddItem( GivePersonalBestHeadShots() ); + // Stomps + PersonalBests.AddItem( GivePersonalBestZedStomp() ); + } function int GetPistolKills() @@ -1002,6 +1023,29 @@ function AARAward GivePersonalBestDoorWelding() return PersonalBestList[EPB_DoorWelding]; } +function AARAward GivePersonalBestZedStomp() +{ + local int Value; + local KFPlayerReplicationInfo KFPRI; + + KFPRI = KFPlayerReplicationInfo(PlayerReplicationInfo); + Value = GetPersonalBest(EPB_ZedStomps); + + if(Value < KFPRI.ZedStomps) + { + PersonalBestList[EPB_ZedStomps].DisplayValue = KFPRI.ZedStomps; + PersonalBestList[EPB_ZedStomps].bHighLight = true; + + SavePersonalBest(EPB_ZedStomps, KFPRI.ZedStomps); + } + else + { + PersonalBestList[EPB_ZedStomps].DisplayValue = Value; + } + + return PersonalBestList[EPB_ZedStomps]; +} + static function GetTeamAward(ETeamAwards AwardIndex, out AARAward TempAwardObject, const out Array KFPCArray) { switch (AwardIndex) @@ -1056,6 +1100,9 @@ static function GetTeamAward(ETeamAwards AwardIndex, out AARAward TempAwardObjec case ETA_Zednnihilation: Give_Zednnihilation(TempAwardObject, KFPCArray); break; + case ETA_ZedStomper: + Give_ZedStomper(TempAwardObject, KFPCArray); + break; } } @@ -1352,6 +1399,23 @@ static function Give_Dominator(out AARAward outAward, const out Array KFPCArray) +{ + local int i; + for(i = 0; i < KFPCArray.Length; i++) + { + if(KFPCArray[i].MatchStats != none) + { + if(KFPCArray[i].MatchStats.TotalStomps > outAward.DisplayValue) + { + outAward.PRI = KFPCArray[i].PlayerReplicationInfo; + outAward.DisplayValue = KFPCArray[i].MatchStats.TotalStomps; + `log(KFPCArray[i].PlayerReplicationInfo.PlayerName @KFPCArray[i].MatchStats.TotalStomps, class'EphemeralMatchStats'.default.bShowMatchStatsLogging); + } + } + } +} + function ReceiveAwardInfo(byte AwardID, PlayerReplicationInfo PRI, int Value) { TeamAwardList[AwardID].PRI = PRI; @@ -1370,6 +1434,7 @@ DefaultProperties TeamAwardList(ETA_MoneyBags)=(TitleIdentifier="MoneyBags",ValueIdentifier="MoneyBagsValue",IconPath="UI_Award_Team.UI_Award_Team-Dosh") TeamAwardList(ETA_HeadPopper)=(TitleIdentifier="HeadPopper",ValueIdentifier="HeadPopperValue",IconPath="UI_Award_Team.UI_Award_Team-Headshots") TeamAwardList(ETA_Dominator)=(TitleIdentifier="Dominator",ValueIdentifier="DominatorValue",IconPath="UI_Award_Team.UI_Award_Team-BossKO") + TeamAwardList(ETA_ZedStomper)=(TitleIdentifier="ZedStomper",ValueIdentifier="ZedStomperValue",IconPath="UI_Award_Team.UI_Award_Team-ZedStomper") //zed awards TeamAwardList(ETA_Carnage)=(TitleIdentifier="Carnage",ValueIdentifier="CarnageValue",IconPath="ui_award_zeds.UI_Award_ZED_RawDmg") TeamAwardList(ETA_Closer)=(TitleIdentifier="Closer",ValueIdentifier="CloserValue",IconPath="ui_award_zeds.UI_Award_ZED_Kills") @@ -1378,7 +1443,6 @@ DefaultProperties TeamAwardList(ETA_ZedSupport)=(TitleIdentifier="ZedSupport",ValueIdentifier="ZedSupportValue",IconPath="ui_award_zeds.UI_Award_ZED_SupportAoE") TeamAwardList(ETA_Zednnihilation)=(TitleIdentifier="Zednnihilation",ValueIdentifier="ZednnihilationValue",IconPath="ui_award_zeds.UI_Award_ZED_MostKills") - PersonalBestList(EPB_Healing)=(TitleIdentifier="EPB_Healing",ValueIdentifier="EPB_HealingValue",IconPath="UI_Award_PersonalMulti.UI_Award_PersonalMulti-Healing") PersonalBestList(EPB_Kills)=(TitleIdentifier="EPB_Kills",ValueIdentifier="EPB_KillsValue",IconPath="UI_Award_PersonalMulti.UI_Award_PersonalMulti-Kills") PersonalBestList(EPB_Assists)=(TitleIdentifier="EPB_Assists",ValueIdentifier="EPB_AssistsValue",IconPath="UI_Award_PersonalMulti.UI_Award_PersonalMulti-Assists") @@ -1388,4 +1452,5 @@ DefaultProperties PersonalBestList(EPB_KnifeKills)=(TitleIdentifier="EPB_KnifeKills",ValueIdentifier="EPB_KnifeKillsValue",IconPath="UI_Award_PersonalSolo.UI_Award_PersonalSolo-Knife") PersonalBestList(EPB_PistolKills)=(TitleIdentifier="EPB_PistolKills",ValueIdentifier="EPB_PistolKillsValue",IconPath="UI_Award_PersonalSolo.UI_Award_PersonalSolo-Pistol") PersonalBestList(EPB_DoorWelding)=(TitleIdentifier="EPB_DoorWelding",ValueIdentifier="EPB_DoorWeldingValue",IconPath="ui_weaponselect_tex.UI_WeaponSelect_Welder") + PersonalBestList(EPB_ZedStomps)=(TitleIdentifier="EPB_ZedStomps",ValueIdentifier="EPB_ZedStompsValue",IconPath="UI_Award_PersonalSolo.UI_Award_PersonalSolo-ZedStomper") } \ No newline at end of file diff --git a/KFGame/Classes/KFAfflictionManager.uc b/KFGame/Classes/KFAfflictionManager.uc index 0b47291..b1b559c 100644 --- a/KFGame/Classes/KFAfflictionManager.uc +++ b/KFGame/Classes/KFAfflictionManager.uc @@ -192,7 +192,8 @@ protected function ProcessSpecialMoveAfflictions(KFPerk InstigatorPerk, vector H return; } - HitZoneIdx = HitFxInfo.HitBoneIndex; + // HitZoneIdx = HitFxInfo.HitBoneIndex; + HitZoneIdx = LastHitZoneIndex; BodyPart = (HitZoneIdx != 255 && HitZoneIdx < HitZones.Length) ? HitZones[HitZoneIdx].Limb : BP_Torso; diff --git a/KFGame/Classes/KFDT_GoompaStomp.uc b/KFGame/Classes/KFDT_GoompaStomp.uc new file mode 100644 index 0000000..7175735 --- /dev/null +++ b/KFGame/Classes/KFDT_GoompaStomp.uc @@ -0,0 +1,24 @@ +//============================================================================= +// KFDT_GoompaStomp +//============================================================================= +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_GoompaStomp extends KFDamageType; + +defaultproperties +{ + RadialDamageImpulse = 1000.f // This controls how much impulse is applied to gibs when exploding + bUseHitLocationForGibImpulses = false // This will make the impulse origin where the victim was hit for directional gibs + bPointImpulseTowardsOrigin = true // This creates an impulse direction aligned along hitlocation and pawn location -- this will push all gibs in the same direction + ImpulseOriginScale = 100.f // Higher means more directional gibbing, lower means more outward (and upward) gibbing + ImpulseOriginLift = 150.f + MaxObliterationGibs = 12 // Maximum number of gibs that can be spawned by obliteration, 0=MAX + bCanGib = true + bCanObliterate = true + ObliterationHealthThreshold = 0 + ObliterationDamageThreshold = 1 + bIgnoreAggroOnDamage=true +} diff --git a/KFGame/Classes/KFDroppedPickup.uc b/KFGame/Classes/KFDroppedPickup.uc index 34e69b3..0c8c1c4 100644 --- a/KFGame/Classes/KFDroppedPickup.uc +++ b/KFGame/Classes/KFDroppedPickup.uc @@ -83,6 +83,7 @@ simulated function SetPickupMesh(PrimitiveComponent NewPickupMesh) local ActorComponent Comp; local SkeletalMeshComponent SkelMC; local StaticMeshComponent StaticMC; + local KFGameInfo KFGI; if (Role == ROLE_Authority ) { @@ -93,6 +94,13 @@ simulated function SetPickupMesh(PrimitiveComponent NewPickupMesh) bUpgradedPickup = KFWeapon(Inventory).CurrentWeaponUpgradeIndex > 0; } + + KFGI = KFGameInfo(WorldInfo.Game); + if (KFGI != none && KFGI.OutbreakEvent != none && KFGI.OutbreakEvent.ActiveEvent.DroppedItemLifespan >= 0.0f) + { + LifeSpan = KFGI.OutbreakEvent.ActiveEvent.DroppedItemLifespan; + } + SetTimer(LifeSpan, false, nameof(TryFadeOut)); } diff --git a/KFGame/Classes/KFGFxHUD_PlayerBackpack.uc b/KFGame/Classes/KFGFxHUD_PlayerBackpack.uc index bc68211..e999f43 100644 --- a/KFGame/Classes/KFGFxHUD_PlayerBackpack.uc +++ b/KFGame/Classes/KFGFxHUD_PlayerBackpack.uc @@ -30,9 +30,11 @@ var int LastMaxWeight; var int LastWeight; // Amount of secondary ammo var byte LastSecondaryAmmo; +var int LastSecondarySpareAmmo; var bool bWasUsingAltFireMode; var bool bUsesSecondaryAmmo; var bool bUsesGrenadesAsSecondaryAmmo; +var bool bUsesSecondaryAmmoAltHUD; var class LastPerkClass; var KFWeapon LastWeapon; @@ -138,6 +140,7 @@ function UpdateWeapon() local int CurrentSpareAmmo; local int CurrentMagazineAmmo; local byte CurrentSecondaryAmmo; + local int CurrentSecondarySpareAmmo; local string CurrentSpecialAmmo; local KFWeapon CurrentWeapon; local ASColorTransform ColorChange; @@ -198,10 +201,28 @@ function UpdateWeapon() CurrentSecondaryAmmo = CurrentWeapon.GetSecondaryAmmoForHUD(); // Update the amount of ammo - if (CurrentSecondaryAmmo != LastSecondaryAmmo) + if (!bUsesSecondaryAmmoAltHUD) { - SetInt("secondaryAmmo" , CurrentSecondaryAmmo); - LastSecondaryAmmo = CurrentSecondaryAmmo; + if (CurrentSecondaryAmmo != LastSecondaryAmmo) + { + SetInt("secondaryAmmo" , CurrentSecondaryAmmo); + LastSecondaryAmmo = CurrentSecondaryAmmo; + } + } + else + { + if (CurrentSecondaryAmmo != LastSecondaryAmmo) + { + SetInt("secondaryAltAmmo" , CurrentSecondaryAmmo); + LastSecondaryAmmo = CurrentSecondaryAmmo; + } + + CurrentSecondarySpareAmmo = CurrentWeapon.GetSecondarySpareAmmoForHUD(); + if (CurrentSecondarySpareAmmo != LastSecondarySpareAmmo) + { + SetInt("secondaryAltSpareAmmo", CurrentSecondarySpareAmmo); + LastSecondarySpareAmmo = CurrentSecondarySpareAmmo; + } } // Force the color of the background if we detect a weapon change and the weapon doesn't use secondary ammo @@ -251,8 +272,18 @@ function RefreshWeapon(KFWeapon CurrentWeapon) SetBool("bUsesAmmo", bUsesAmmo); bUsesSecondaryAmmo = CurrentWeapon.UsesSecondaryAmmo(); + bUsesSecondaryAmmoAltHUD = bUsesSecondaryAmmo && CurrentWeapon.bUsesSecondaryAmmoAltHUD; bUsesGrenadesAsSecondaryAmmo = CurrentWeapon.UsesGrenadesAsSecondaryAmmo(); - SetBool("bUsesSecondaryAmmo", bUsesSecondaryAmmo); + + if (bUsesSecondaryAmmoAltHUD) + { + SetBool("bUsesSecondaryAmmoAlt", bUsesSecondaryAmmoAltHUD); + } + else + { + SetBool("bUsesSecondaryAmmo", bUsesSecondaryAmmo); + } + if( bUsesSecondaryAmmo ) { SetString("secondaryIcon", "img://"$CurrentWeapon.SecondaryAmmoTexture.GetPackageName()$"."$CurrentWeapon.SecondaryAmmoTexture); diff --git a/KFGame/Classes/KFGFxMenu_PostGameReport.uc b/KFGame/Classes/KFGFxMenu_PostGameReport.uc index 1f77691..8e8755c 100644 --- a/KFGame/Classes/KFGFxMenu_PostGameReport.uc +++ b/KFGame/Classes/KFGFxMenu_PostGameReport.uc @@ -45,20 +45,23 @@ function InitializeMenu( KFGFxMoviePlayer_Manager InManager ) KFGRI = KFGameReplicationInfo(GetPC().WorldInfo.GRI); - //@SABER_EGS IsEosBuild() case added - if( class'WorldInfo'.static.IsConsoleBuild() || class'WorldInfo'.static.IsEosBuild() ) + if (class'GameEngine'.Static.IsGameFullyInstalled()) { - class'GameEngine'.static.GetPlayfabInterface().AddOnCloudScriptExecutionCompleteDelegate(OnProcessEndGameRewardsComplete); - KFGRI.SendPlayfabGameTimeUpdate(true); - class'GameEngine'.static.GetPlayfabInterface().AddInventoryReadCompleteDelegate( SearchPlayfabInventoryForNewItem ); - } - else - { - if (KFGRI != none) + //@SABER_EGS IsEosBuild() case added + if( class'WorldInfo'.static.IsConsoleBuild() || class'WorldInfo'.static.IsEosBuild() ) { - KFGRI.ProcessChanceDrop(); + class'GameEngine'.static.GetPlayfabInterface().AddOnCloudScriptExecutionCompleteDelegate(OnProcessEndGameRewardsComplete); + KFGRI.SendPlayfabGameTimeUpdate(true); + class'GameEngine'.static.GetPlayfabInterface().AddInventoryReadCompleteDelegate( SearchPlayfabInventoryForNewItem ); } - OnlineSub.AddOnInventoryReadCompleteDelegate(SearchInventoryForNewItem); + else + { + if (KFGRI != none) + { + KFGRI.ProcessChanceDrop(); + } + OnlineSub.AddOnInventoryReadCompleteDelegate(SearchInventoryForNewItem); + } } LocalizeText(); diff --git a/KFGame/Classes/KFGFxMoviePlayer_HUD.uc b/KFGame/Classes/KFGFxMoviePlayer_HUD.uc index 014588f..9463a8a 100644 --- a/KFGame/Classes/KFGFxMoviePlayer_HUD.uc +++ b/KFGame/Classes/KFGFxMoviePlayer_HUD.uc @@ -62,6 +62,8 @@ var KFGFxWidget_NonCriticalGameMessage NonCriticalGameMessageWidget; var KFGFxWidget_NonCriticalGameMessage InviteGameMessageWidget; // Widget that shows headshots for gunslinger var KFGFxWidget_RhythmCounter RhythmCounterWidget; +// Widget that shows goompa jumps. +var KFGFxWidget_GoompaCounter GoompaCounterWidget; // Widget that displays health bar var KFGFxWidget_BossHealthBar bossHealthBar; // Widget that displays map texts @@ -335,12 +337,18 @@ event bool WidgetInitialized(name WidgetName, name WidgetPath, GFxObject Widget) break; case 'RhythmCounter': if(RhythmCounterWidget == none) - { + { RhythmCounterWidget=KFGFxWidget_RhythmCounter(Widget); - } + } + break; + case 'GoompaCounter': + if (GoompaCounterWidget == none) + { + GoompaCounterWidget=KFGFxWidget_GoompaCounter(Widget); + } break; } - + return true; } @@ -1074,6 +1082,14 @@ function UpdateRhythmCounterWidget(int value, int max) } } +function UpdateGoompaCounterWidget(int value, int max) +{ + if(GoompaCounterWidget != none) + { + GoompaCounterWidget.SetCount(value, max); + } +} + //============================================================== // Input //============================================================== @@ -1393,6 +1409,7 @@ DefaultProperties WidgetBindings.Add((WidgetName="NonCriticalMessageWidget", WidgetClass=class'KFGFxWidget_NonCriticalGameMessage')) WidgetBindings.Add((WidgetName="InviteMessageWidget", WidgetClass=class'KFGFxWidget_NonCriticalGameMessage')) WidgetBindings.Add((WidgetName="RhythmCounter", WidgetClass=class'KFGFxWidget_RhythmCounter')) + WidgetBindings.ADD((WidgetName="GoompaCounter", WidgetClass=class'KFGFxWidget_GoompaCounter')); WidgetBindings.Add((WidgetName="bossHealthBar", WidgetClass=class'KFGFxWidget_BossHealthBar')) WidgetBindings.Add((WidgetName="mapTextWidget", WidgetClass=class'KFGFxWidget_MapText')) WidgetBindings.Add((WidgetName="counterMapTextWidget", WidgetClass=class'KFGFxWidget_MapCounterText')) diff --git a/KFGame/Classes/KFGFxPostGameContainer_MapVote.uc b/KFGame/Classes/KFGFxPostGameContainer_MapVote.uc index fa57caf..5f46457 100644 --- a/KFGame/Classes/KFGFxPostGameContainer_MapVote.uc +++ b/KFGame/Classes/KFGFxPostGameContainer_MapVote.uc @@ -41,25 +41,40 @@ function SetMapOptions() { local GFxObject MapList; local GFxObject MapObject; - local int i; + local int i, Counter; local array ServerMapList; local KFGameReplicationInfo KFGRI; + local bool IsBrokenTrader; KFGRI = KFGameReplicationInfo(GetPC().WorldInfo.GRI); + Counter = 0; if(KFGRI != none && KFGRI.VoteCollector != none) { ServerMapList = KFGRI.VoteCollector.MapList; + IsBrokenTrader = class'KFGameEngine'.static.GetWeeklyEventIndex() == 11; //gfx MapList = CreateArray(); for (i = 0; i < ServerMapList.length; i++) { + if (IsBrokenTrader && ( ServerMapList[i] == "KF-Biolapse" || + ServerMapList[i] == "KF-Nightmare" || + ServerMapList[i] == "KF-PowerCore_Holdout" || + ServerMapList[i] == "KF-TheDescent" || + ServerMapList[i] == "KF-KrampusLair")) + { + continue; + } + MapObject = CreateObject("Object"); MapObject.SetString("label", class'KFCommon_LocalizedStrings'.static.GetFriendlyMapName(ServerMapList[i]) ); MapObject.SetString("mapSource", GetMapSource(ServerMapList[i]) ); - MapList.SetElementObject(i, MapObject); + MapObject.SetInt("mapindex", i); + MapList.SetElementObject(Counter, MapObject); + + Counter++; } } diff --git a/KFGame/Classes/KFGFxPostGameContainer_PlayerStats.uc b/KFGame/Classes/KFGFxPostGameContainer_PlayerStats.uc index 133141d..ca9058d 100644 --- a/KFGame/Classes/KFGFxPostGameContainer_PlayerStats.uc +++ b/KFGame/Classes/KFGFxPostGameContainer_PlayerStats.uc @@ -12,7 +12,7 @@ class KFGFxPostGameContainer_PlayerStats extends KFGFxObject_Container dependson(EphemeralMatchStats); var localized string AchievementsString, ZedKillsString, TopWeaponsString; -var localized string TotalDamageDealtString, HeadShotsString, LargeZedKillsString, TotalDoshEarnedString, TotalKillsString, AssistsString, DamageDealtString; +var localized string TotalDamageDealtString, HeadShotsString, LargeZedKillsString, TotalDoshEarnedString, TotalKillsString, AssistsString, DamageDealtString, TotalStompsString; var localized string KnifeString; var string PlayerStatsString; var int ItemCount; @@ -74,7 +74,7 @@ function SetPlayerStats() ObjectArray.SetElementObject(ItemCount, MakeTextObject(HeadShotsString, String(StatCollector.TotalHeadShots) )); ObjectArray.SetElementObject(ItemCount, MakeTextObject(TotalDamageDealtString, String(StatCollector.TotalDamageDealt) )); //ObjectArray.SetElementObject(ItemCount, MakeTextObject("Total Damage Received:", String(StatCollector.TotalDamageTaken) )); - + //weapons StatCollector.GetTopWeapons(3, TopWeaponList); @@ -141,7 +141,7 @@ function GFxObject MakeZedKillObject(Class MonsterClass, String function GFxObject MakeWeaponObject( string WeaponName, string WeaponIcon, int WeaponDamage, int HeadShotsWithWeapon, int LargeZedKillsWithWeapon ) { local GFxObject TempObject; - + TempObject = CreateObject("Object"); TempObject.SetString("typeString", "TopWeapon"); TempObject.SetString("weaponName", WeaponName); diff --git a/KFGame/Classes/KFGFxSpecialEventObjectivesContainer_Summer2021.uc b/KFGame/Classes/KFGFxSpecialEventObjectivesContainer_Summer2021.uc new file mode 100644 index 0000000..76cc05e --- /dev/null +++ b/KFGame/Classes/KFGFxSpecialEventObjectivesContainer_Summer2021.uc @@ -0,0 +1,27 @@ +class KFGFxSpecialEventObjectivesContainer_Summer2021 extends KFGFxSpecialEventObjectivesContainer; + +function Initialize(KFGFxObject_Menu NewParentMenu) +{ + super.Initialize(NewParentMenu); +} + +DefaultProperties +{ + ObjectiveIconURLs[0] = "Summer2021_UI.UI_Objective_Summer2021_Kicked" // Stomp on 50 Zeds + ObjectiveIconURLs[1] = "Spring2021_UI.UI_Objectives_Spring2021_Weekly_Hack" // Complete the Weekly on Moonbase + ObjectiveIconURLs[2] = "Summer2021_UI.UI_Objective_Summer2021_ShckingMoonlight" // Use the laser trap to kill 20 Zeds on Moonbase + ObjectiveIconURLs[3] = "Summer2021_UI.UI_Objective_Summer2021_WeightlessSklls" // Kill 300 Zeds while jumping in the air on Moonbase + ObjectiveIconURLs[4] = "Summer2021_UI.UI_Objective_Summer2021_InfiniteVoid" // Complete wave 15 on Endless Hard or higher difficulty on Moonbase + + //defaults + AllCompleteRewardIconURL="CHR_CosmeticSet_SS_02_ItemTex.astronaut_companionbackpack.astronautcompanionbackpack_precious" + ChanceDropIconURLs[0]="CHR_CosmeticSet_SS_01_ItemTex.SideshowPremiumTicket_Small" + ChanceDropIconURLs[1]="CHR_CosmeticSet_SS_01_ItemTex.SideshowGoldenTicket_Small" + IconURL="Summer2021_UI.KF2_Summer_InterstellarInsanity_SmallLogo" + + UsesProgressList[0] = true + UsesProgressList[1] = false + UsesProgressList[2] = true + UsesProgressList[3] = true + UsesProgressList[4] = false +} \ No newline at end of file diff --git a/KFGame/Classes/KFGFxStartGameContainer_FindGame.uc b/KFGame/Classes/KFGFxStartGameContainer_FindGame.uc index 87efa45..77f16f6 100644 --- a/KFGame/Classes/KFGFxStartGameContainer_FindGame.uc +++ b/KFGame/Classes/KFGFxStartGameContainer_FindGame.uc @@ -182,28 +182,31 @@ function FillWhatsNew() local SWhatsNew item; WhatsNewItems.Remove(0, WhatsNewItems.Length); // Latest Update - item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Spring_DystopianDevastation_Event", "LatestUpdate", "http://www.tripwireinteractive.com/redirect/KF2LatestUpdate/"); + item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Summer_InterstellarInsanity_Event", "LatestUpdate", "http://www.tripwireinteractive.com/redirect/KF2LatestUpdate/"); WhatsNewItems.AddItem(item); // KF2 Armory Season Pass 2021 item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Spring_Armory_Season_Pass", "ArmorySeasonPass", "https://store.steampowered.com/app/1524820/Killing_Floor_2__Armory_Season_Pass"); WhatsNewItems.AddItem(item); // Featured Time Limited Item - item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Spring_PremiumTicket", "FeaturedEventItem", "https://store.steampowered.com/buyitem/232090/5803"); + item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_SS_PremiumTicket", "FeaturedEventItem", "https://store.steampowered.com/buyitem/232090/4928"); + WhatsNewItems.AddItem(item); +// Featured Cosmetic Bundle + item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Summer_Astronaut", "FeaturedItemBundle", "https://store.steampowered.com/buyitem/232090/8953"); + WhatsNewItems.AddItem(item); +// Featured Cosmetic Bundle + item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Summer_Foundry","FeaturedItemBundle","https://store.steampowered.com/buyitem/232090/8956"); WhatsNewItems.AddItem(item); // Featured Weapon Skin Bundle - item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Spring_Neon_MKVII", "FeaturedItemBundle", "https://store.steampowered.com/buyitem/232090/8774"); - WhatsNewItems.AddItem(item); -// Featured Cosmetic Bundle - item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Spring_Paratrooper","FeaturedItemBundle","https://store.steampowered.com/buyitem/232090/8775"); - WhatsNewItems.AddItem(item); -// Featured Cosmetic Bundle - item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Spring_DystopianDevastation", "FeaturedItemBundle", "https://store.steampowered.com/buyitem/232090/8773"); - WhatsNewItems.AddItem(item); -// Featured Cosmetic Bundle - item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Spring_Chemical", "FeaturedItemBundle", "https://store.steampowered.com/buyitem/232090/8776"); + item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Summer_BeyondHorizon", "FeaturedItemBundle", "https://store.steampowered.com/buyitem/232090/8955"); WhatsNewItems.AddItem(item); // Featured Weapon Bundle - item=SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Spring_GravityImploder", "FeaturedItemBundle", "https://store.steampowered.com/buyitem/232090/8777"); + item = SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Summer_FamasMasterkey", "FeaturedItemBundle", "https://store.steampowered.com/buyitem/232090/8957"); + WhatsNewItems.AddItem(item); +// Featured Weapon Bundle + item=SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Summer_ThermiteBore", "FeaturedItemBundle", "https://store.steampowered.com/buyitem/232090/8958"); + WhatsNewItems.AddItem(item); + // Featured Weapon Bundle + item=SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_Summer_Weaponsbundle", "FeaturedItemBundle", "https://store.steampowered.com/buyitem/232090/8959"); WhatsNewItems.AddItem(item); // Misc Community Links item=SetWhatsNewItem("img://UI_WhatsNew.UI_WhatsNew_CommunityHub", "Jaegorhorn", "https://steamcommunity.com/app/232090"); diff --git a/KFGame/Classes/KFGFxStartGameContainer_Options.uc b/KFGame/Classes/KFGFxStartGameContainer_Options.uc index 8cdbbc3..a7e904d 100644 --- a/KFGame/Classes/KFGFxStartGameContainer_Options.uc +++ b/KFGame/Classes/KFGFxStartGameContainer_Options.uc @@ -201,6 +201,8 @@ function InitializeGameOptions() bIsSoloGame = GetBool("bIsSoloGame"); StartMenu.GetMapList(StartMenu.MapStringList, ParentMenu.Manager.GetModeIndex(false), StartMenu.GetStartMenuState() == EMatchmaking); + FilterWeeklyMaps(StartMenu.MapStringList); + InitialMapIndex = GetInitialMapIndex(); UpdateButtonsEnabled(); @@ -260,6 +262,24 @@ function InitializeGameOptions() SetObject("localizedText", TextObject); } +function FilterWeeklyMaps(out array List) +{ + if (ParentMenu.Manager.GetModeIndex(false) != EGameMode_Weekly) + { + return; + } + + // Scavenger index = 11 + if (class'KFGameEngine'.static.GetWeeklyEventIndex() == 11) + { + List.RemoveItem("KF-Biolapse"); + List.RemoveItem("KF-Nightmare"); + List.RemoveItem("KF-PowerCore_Holdout"); + List.RemoveItem("KF-TheDescent"); + List.RemoveItem("KF-KrampusLair"); + } +} + function GFxObject CreateList( array TextArray, byte SelectedIndex, bool bAddNoPrefString, optional bool bIsMapList, optional byte MaxLength) { local int i; diff --git a/KFGame/Classes/KFGFxStoreContainer_Main.uc b/KFGame/Classes/KFGFxStoreContainer_Main.uc index f92bded..24a38ca 100644 --- a/KFGame/Classes/KFGFxStoreContainer_Main.uc +++ b/KFGame/Classes/KFGFxStoreContainer_Main.uc @@ -446,19 +446,21 @@ DefaultProperties XboxFilterExceptions[0]="Wasteland Bundle" // Wasteland Outfit Bundle - FeaturedItemIDs[0]=8115 - FeaturedItemIDs[1]=8773 - FeaturedItemIDs[2]=8774 - FeaturedItemIDs[3]=8775 - FeaturedItemIDs[4]=8776 - FeaturedItemIDs[5]=8777 + FeaturedItemIDs[0]=8178 + FeaturedItemIDs[1]=8953 + FeaturedItemIDs[2]=8959 + FeaturedItemIDs[3]=8956 + FeaturedItemIDs[4]=8955 + FeaturedItemIDs[5]=8957 + FeaturedItemIDs[6]=8958 - ConsoleFeaturedItemIDs[0]=8116 - ConsoleFeaturedItemIDs[1]=8773 - ConsoleFeaturedItemIDs[2]=8774 - ConsoleFeaturedItemIDs[3]=8775 - ConsoleFeaturedItemIDs[4]=8776 - ConsoleFeaturedItemIDs[5]=8777 + ConsoleFeaturedItemIDs[0]=8181 + ConsoleFeaturedItemIDs[1]=8953 + ConsoleFeaturedItemIDs[2]=8959 + ConsoleFeaturedItemIDs[3]=8956 + ConsoleFeaturedItemIDs[4]=8955 + ConsoleFeaturedItemIDs[5]=8957 + ConsoleFeaturedItemIDs[6]=8958 MaxFeaturedItems=5 } \ No newline at end of file diff --git a/KFGame/Classes/KFGFxWidget_GoompaCounter.uc b/KFGame/Classes/KFGFxWidget_GoompaCounter.uc new file mode 100644 index 0000000..b64091d --- /dev/null +++ b/KFGame/Classes/KFGFxWidget_GoompaCounter.uc @@ -0,0 +1,29 @@ + + +//============================================================================= +// KFGFxWidget_GoompaCounter +//============================================================================= +// HUD Widget that displays messages to the player +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2015 Tripwire Interactive LLC +// - Zane Gholson 01/14/2015 +//============================================================================= + +class KFGFxWidget_GoompaCounter extends GFxObject; + +function SetCount( int Count, int Max ) +{ + SetInt("count", Count); + SetBonusPercentage(float(Min(Max,Count)) / float(Max)); + + if (Count > 0) + { + SetBool("hidden", false); + } +} + +function SetBonusPercentage( float NewValue ) +{ + SetFloat("bonusPercentage", NewValue); +} diff --git a/KFGame/Classes/KFGFxWidget_PartyInGame.uc b/KFGame/Classes/KFGFxWidget_PartyInGame.uc index 6a6a0c4..16c3201 100644 --- a/KFGame/Classes/KFGFxWidget_PartyInGame.uc +++ b/KFGame/Classes/KFGFxWidget_PartyInGame.uc @@ -68,7 +68,7 @@ function UpdateReadyButtonVisibility() KFGRI = KFGameReplicationInfo( GetPC().WorldInfo.GRI ); if ( KFGRI != none ) { - if (KFGRI.bMatchHasBegun && (MyKFPRI != none && MyKFPRI.bHasSpawnedIn && KFGRI.bTraderIsOpen) && !KFGRI.bMatchIsOver && !KFGRI.bVersusGame) + if (KFGRI.bMatchHasBegun && (MyKFPRI != none && MyKFPRI.bHasSpawnedIn && KFGRI.bTraderIsOpen) && !KFGRI.bMatchIsOver && MyKFPRI.GetTeamNum() != 255 ) { bShowingSkipTrader = !MyKFPRI.bVotedToSkipTraderTime; if (bShowingSkipTrader && !ReadyButton.GetBool("visible")) diff --git a/KFGame/Classes/KFGameInfo.uc b/KFGame/Classes/KFGameInfo.uc index a157072..9959169 100644 --- a/KFGame/Classes/KFGameInfo.uc +++ b/KFGame/Classes/KFGameInfo.uc @@ -1165,24 +1165,34 @@ function ResetAllPickups() AllPickupFactories.AddItem( AmmoPickups[i] ); } - if(NumWeaponPickups > 0 ) - { - ResetPickups( ItemPickups, NumWeaponPickups ); - } - if(NumAmmoPickups > 0) - { - ResetPickups( AmmoPickups, NumAmmoPickups ); - } + ResetPickups( ItemPickups, NumWeaponPickups ); + + ResetPickups( AmmoPickups, NumAmmoPickups ); } +/** Pick random pickup items to enable and put all others to sleep */ /** Pick random pickup items to enable and put all others to sleep */ function ResetPickups( array PickupList, int NumPickups ) { local byte i, ChosenIndex; local array PossiblePickups; + local int NumIterations; + + if (PickupList.Length == 0) + return; PossiblePickups = PickupList; - for ( i = 0; i < NumPickups; i++ ) + + if (OutbreakEvent != none && OutbreakEvent.ActiveEvent.bUnlimitedWeaponPickups && KFPickupFactory_Item(PickupList[0]) != none) + { + NumIterations = Min(NumPickups, PickupList.Length - 1); + } + else + { + NumIterations = Min(NumPickups, PickupList.Length); + } + + for ( i = 0; i < NumIterations; i++ ) { ChosenIndex = Rand( PossiblePickups.Length ); PossiblePickups[ChosenIndex].Reset(); @@ -3774,6 +3784,19 @@ static function bool HasCustomTraderVoiceGroup() return false; } +/*********************************************** + * @name Initial loadout modifier + **********************************************/ + +simulated function AddWeaponsFromSpawnList(KFPawn P); + +simulated function OverrideHumanDefaults(KFPawn_Human P); + +/*********************************************** + * @name Damage Modifier for Event + **********************************************/ +simulated function ModifyDamageGiven(out int InDamage, optional Actor DamageCauser, optional KFPawn_Monster MyKFPM, optional KFPlayerController DamageInstigator, optional class DamageType, optional int HitZoneIdx ); + defaultproperties { /** Scoring */ diff --git a/KFGame/Classes/KFGameReplicationInfo.uc b/KFGame/Classes/KFGameReplicationInfo.uc index dd8338b..57738c8 100644 --- a/KFGame/Classes/KFGameReplicationInfo.uc +++ b/KFGame/Classes/KFGameReplicationInfo.uc @@ -343,6 +343,11 @@ var repnotify KFMusicTrackInfo ReplicatedMusicTrackInfo; * debug ************************************/ +/************************************ +* Broken Trader Utils +************************************/ +var transient bool bIsBrokenTrader; + /************************************ * Steam heartbeat ************************************/ @@ -353,6 +358,7 @@ native function SendSteamRequestItemDrop(); function native private EndOfWave(); + cpptext { INT* GetOptimizedRepList( BYTE* InDefault, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, UActorChannel* Channel ); @@ -375,7 +381,7 @@ replication if ( bNetDirty ) TraderVolume, TraderVolumeCheckType, bTraderIsOpen, NextTrader, WaveNum, bWaveIsEndless, AIRemaining, WaveTotalAICount, bWaveIsActive, MaxHumanCount, bGlobalDamage, CurrentObjective, PreviousObjective, PreviousObjectiveResult, PreviousObjectiveXPResult, PreviousObjectiveVoshResult, MusicIntensity, ReplicatedMusicTrackInfo, MusicTrackRepCount, - bIsUnrankedGame, GameSharedUnlocks, bHidePawnIcons, ConsoleGameSessionGuid, GameDifficulty, GameDifficultyModifier, BossIndex, bWaveStarted, NextObjective; //@HSL - JRO - 3/21/2016 - PS4 Sessions + bIsUnrankedGame, GameSharedUnlocks, bHidePawnIcons, ConsoleGameSessionGuid, GameDifficulty, GameDifficultyModifier, BossIndex, bWaveStarted, NextObjective, bIsBrokenTrader; //@HSL - JRO - 3/21/2016 - PS4 Sessions if ( bNetInitial ) GameLength, WaveMax, bCustom, bVersusGame, TraderItems, GameAmmoCostScale, bAllowGrenadePurchase, MaxPerkLevel, bTradersEnabled; if ( bNetInitial || bNetDirty ) @@ -796,7 +802,7 @@ exec reliable client function ShowPreGameServerWelcomeScreen() } -simulated function GetKFPRIArray(out array KFPRIArray, optional bool bGetSpectators) +simulated function GetKFPRIArray(out array KFPRIArray, optional bool bGetSpectators, optional bool bGetZedPlayers) { local int i; local int Num; @@ -805,7 +811,8 @@ simulated function GetKFPRIArray(out array KFPRIArray, for ( i = 0; i < PRIArray.Length; i++) { if ( PRIArray[i] != None && KFPlayerReplicationInfo(PRIArray[i]) != none && - (bGetSpectators || !PRIArray[i].bOnlySpectator)) + (bGetSpectators || !PRIArray[i].bOnlySpectator) && + (bGetZedPlayers || PRIArray[i].GetTeamNum() != 255)) { KFPRIArray[num++] = KFPlayerReplicationInfo(PRIArray[i]); } @@ -2170,6 +2177,12 @@ simulated function UpdatePerksAvailable() KFPlayerController(GetALocalPlayerController()).UpdatePerkOnInit(); } +simulated function NotifyBrokenTrader() +{ + bIsBrokenTrader = true; + bNetDirty = true; +} + defaultproperties { TraderItemsPath="GP_Trader_ARCH.DefaultTraderItems" @@ -2188,4 +2201,5 @@ defaultproperties PreviousObjectiveResult=-1 PreviousObjectiveVoshResult=-1 PreviousObjectiveXPResult=-1 + bIsBrokenTrader=false } diff --git a/KFGame/Classes/KFGfxMenu_StartGame.uc b/KFGame/Classes/KFGfxMenu_StartGame.uc index 612edff..d4d09af 100644 --- a/KFGame/Classes/KFGfxMenu_StartGame.uc +++ b/KFGame/Classes/KFGfxMenu_StartGame.uc @@ -204,7 +204,7 @@ static function class GetSpecialEventClass case SEI_Spring: return class'KFGFxSpecialEventObjectivesContainer_Spring2021'; case SEI_Summer: - return class'KFGFxSpecialEventObjectivesContainer_Summer2020'; + return class'KFGFxSpecialEventObjectivesContainer_Summer2021'; case SEI_Fall: return class'KFGFxSpecialEventObjectivesContainer_Fall2020'; case SEI_Winter: diff --git a/KFGame/Classes/KFGfxObject_Menu.uc b/KFGame/Classes/KFGfxObject_Menu.uc index f0c956f..7c1e998 100644 --- a/KFGame/Classes/KFGfxObject_Menu.uc +++ b/KFGame/Classes/KFGfxObject_Menu.uc @@ -209,7 +209,7 @@ function Callback_ReadyClicked( bool bReady ) //player has spawned, skip trader time if (KFGRI.bTraderIsOpen && KFPRI.bHasSpawnedIn) { - if (KFPC.MyGFxManager.bMenusOpen && KFPC.MyGFxManager.CurrentMenu != KFPC.MyGFxManager.TraderMenu && !KFGRI.bVersusGame) + if (KFPC.MyGFxManager.bMenusOpen && KFPC.MyGFxManager.CurrentMenu != KFPC.MyGFxManager.TraderMenu) { //skip trader request KFPRI.RequestSkiptTrader(KFPRI); diff --git a/KFGame/Classes/KFMeleeHelperWeapon.uc b/KFGame/Classes/KFMeleeHelperWeapon.uc index 7b68d30..2905fed 100644 --- a/KFGame/Classes/KFMeleeHelperWeapon.uc +++ b/KFGame/Classes/KFMeleeHelperWeapon.uc @@ -26,8 +26,8 @@ enum EMeleeAttackType }; /** Attack settings that should be initialized before calling BeginMeleeAttack */ -var private EPawnOctant NextAttackDir; -var private EMeleeAttackType NextAttackType; +var protected EPawnOctant NextAttackDir; +var protected EMeleeAttackType NextAttackType; /** Direction of the last played attack */ var EPawnOctant CurrentAttackDir; diff --git a/KFGame/Classes/KFOnlineStatsReadDingo.uc b/KFGame/Classes/KFOnlineStatsReadDingo.uc index 46d5aa2..714b608 100644 --- a/KFGame/Classes/KFOnlineStatsReadDingo.uc +++ b/KFGame/Classes/KFOnlineStatsReadDingo.uc @@ -67,6 +67,7 @@ defaultproperties ColumnIds.Add(STATID_ACHIEVE_HellmarkStationCollectibles) ColumnIds.Add(STATID_ACHIEVE_ElysiumEndlessWaveFifteen) ColumnIds.Add(STATID_ACHIEVE_Dystopia2029Collectibles) + ColumnIds.Add(STATID_ACHIEVE_MoonbaseCollectibles) ColumnMappings.Add((Id=STATID_ACHIEVE_MrPerky5, Name="AchievementMrPerky5")) ColumnMappings.Add((Id=STATID_ACHIEVE_MrPerky10, Name = "AchievementMrPerky10")) @@ -122,4 +123,5 @@ defaultproperties ColumnMappings.Add((Id=STATID_ACHIEVE_HellmarkStationCollectibles,Name="AchievementCollectHellmarkStation")) ColumnMappings.Add((Id=STATID_ACHIEVE_ElysiumEndlessWaveFifteen,Name="AchievementEndlessElysium")) ColumnMappings.Add((Id=STATID_ACHIEVE_Dystopia2029Collectibles,NAme="AchievementCollectDystopia2029")) + ColumnMappings.Add((Id=STATID_ACHIEVE_MoonbaseCollectibles,NAme="AchievementCollectMoonbase")) } diff --git a/KFGame/Classes/KFOnlineStatsWrite.uc b/KFGame/Classes/KFOnlineStatsWrite.uc index d01b3a5..a4b77a5 100644 --- a/KFGame/Classes/KFOnlineStatsWrite.uc +++ b/KFGame/Classes/KFOnlineStatsWrite.uc @@ -429,6 +429,10 @@ const KFACHID_Dystopia2029Hard = 280; const KFACHID_Dystopia2029HellOnEarth = 281; const KFACHID_Dystopia2029Collectibles = 282; +const KFACHID_MoonbaseHard = 283; +const KFACHID_MoonbaseHellOnEarth = 284; +const KFACHID_MoonbaseCollectibles = 285; + /* __TW_ANALYTICS_ */ var int PerRoundWeldXP; var int PerRoundHealXP; @@ -1083,6 +1087,11 @@ private event AddToHitsTaken() SeasonalEventStats_OnHitTaken(); } +private event AddToHitsGiven(class DT) +{ + SeasonalEventStats_OnHitGiven(DT); +} + /** * @brief Add a kill and give some EXP tp the player * @param MonsterClass The killed monster's class @@ -1810,6 +1819,14 @@ final simulated function SeasonalEventStats_OnHitTaken() } } +final simulated function SeasonalEventStats_OnHitGiven(class DT) +{ + if (SeasonalEventIsValid()) + { + SeasonalEvent.OnHitGiven(DT); + } +} + final simulated function SeasonalEventStats_OnZedKilled(class MonsterClass, int Difficulty, class DT) { if (SeasonalEventIsValid()) @@ -2003,6 +2020,7 @@ defaultproperties DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_SMG_P90, KFDT_Ballistic_P90,KFDT_Bludgeon_P90),CompletionAmount=10000)) DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_SMG_Kriss, KFDT_Ballistic_Kriss,KFDT_Bludgeon_Kriss),CompletionAmount=10000)) DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_SMG_HK_UMP, KFDT_Ballistic_HK_UMP,KFDT_Bludgeon_HK_UMP),CompletionAmount=10000)) + DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_HRG_BarrierRifle, KFDT_Ballistic_HRG_BarrierRifle,KFDT_Bludgeon_HRG_BarrierRifle),CompletionAmount=10000)) //Commando Weapons DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_AssaultRifle_AR15, KFDT_Ballistic_AR15,KFDT_Bludgeon_AR15),CompletionAmount=5000)) //3000 @@ -2020,6 +2038,7 @@ defaultproperties DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_Shotgun_M4, KFDT_Ballistic_M4Shotgun,KFDT_Bludgeon_M4Shotgun),CompletionAmount=10000)) //7000 DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_Shotgun_AA12, KFDT_Ballistic_AA12Shotgun,KFDT_Bludgeon_AA12Shotgun),CompletionAmount=10000)) DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_Shotgun_ElephantGun, KFDT_Ballistic_ElephantGun,KFDT_Bludgeon_ElephantGun),CompletionAmount=10000)) + DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_HRG_BlastBrawlers, KFDT_Ballistic_BlastBrawlersShotgun,KFDT_Bludgeon_BlastBrawlers,KFDT_Bludgeon_BlastBrawlersHeavy,KFDT_Bludgeon_BlastBrawlersBash),CompletionAmount=10000)) //Medic Weapons DailyEvents.Add((ObjectiveType=DOT_WeaponDamage,ObjectiveClasses=(KFWeap_Pistol_Medic, KFDT_Ballistic_Pistol_Medic,KFDT_Bludgeon_Pistol_Medic),CompletionAmount=5000)) //3000 @@ -2225,7 +2244,10 @@ defaultproperties DailyEvents.Add((ObjectiveType=DOT_Maps,SecondaryType=DOST_MapCompletion,ObjectiveClasses=(KF-DYSTOPIA2029),CompletionAmount=1)) DailyEvents.Add((ObjectiveType=DOT_Maps,SecondaryType=DOST_MapCompletion,ObjectiveClasses=(KF-DYSTOPIA2029),CompletionAmount=2)) DailyEvents.Add((ObjectiveType=DOT_Maps,SecondaryType=DOST_MapCompletion,ObjectiveClasses=(KF-DYSTOPIA2029),CompletionAmount=3)) - + DailyEvents.Add((ObjectiveType=DOT_Maps,SecondaryType=DOST_MapCompletion,ObjectiveClasses=(KF-MOONBASE),CompletionAmount=1)) + DailyEvents.Add((ObjectiveType=DOT_Maps,SecondaryType=DOST_MapCompletion,ObjectiveClasses=(KF-MOONBASE),CompletionAmount=2)) + DailyEvents.Add((ObjectiveType=DOT_Maps,SecondaryType=DOST_MapCompletion,ObjectiveClasses=(KF-MOONBASE),CompletionAmount=3)) + //Versus Damage // Per design doc that I have right now, these are x class damage y players, not damage y amount /*DailyEvents.Add((ObjectiveType=DOT_Maps,SecondaryType=DOST_VersusDamage,ObjectiveClasses=(KFPawn_ZedClot_Alpha, KFPawn_ZedClot_Alpha_Versus),CompletionAmount=1)) diff --git a/KFGame/Classes/KFOnlineStatsWriteDingo.uc b/KFGame/Classes/KFOnlineStatsWriteDingo.uc index 866cccc..14afe34 100644 --- a/KFGame/Classes/KFOnlineStatsWriteDingo.uc +++ b/KFGame/Classes/KFOnlineStatsWriteDingo.uc @@ -69,4 +69,5 @@ defaultproperties Properties.Add((PropertyId = STATID_ACHIEVE_HellmarkStationCollectibles,Data = (Type = SDT_Int32,Value1 = 0))) Properties.Add((PropertyId = STATID_ACHIEVE_ElysiumEndlessWaveFifteen,Data = (Type = SDT_Int32,Value1 = 0))) Properties.Add((PropertyId = STATID_ACHIEVE_Dystopia2029Collectibles, Data = (Type = SDT_Int32,Value1 = 0))) + Properties.Add((PropertyId = STATID_ACHIEVE_MoonbaseCollectibles, Data = (Type = SDT_Int32, Value1 = 0))) } diff --git a/KFGame/Classes/KFOutbreakEvent.uc b/KFGame/Classes/KFOutbreakEvent.uc index badc695..c935e84 100644 --- a/KFGame/Classes/KFOutbreakEvent.uc +++ b/KFGame/Classes/KFOutbreakEvent.uc @@ -93,7 +93,6 @@ struct StatAdjustments /** Speed modifier */ var() float InitialGroundSpeedModifierScale; - structdefaultproperties { HealthScale = 1.f; @@ -146,6 +145,9 @@ struct WeeklyOverrides * array prior to calling in to P.AddDefaultInventory */ var() KFGFxObject_TraderItems SpawnWeaponList; + + /** Adds weapon spawn list to the player's loadout */ + var() bool bAddSpawnListToLoadout; /** If this flag is set to true, the secondary weapon will be checked for availability in the current game mode */ var() bool bSpawnWeaponListAffectsSecondaryWeapons; @@ -333,12 +335,39 @@ struct WeeklyOverrides /** Replenish player's health once a wave ends. */ var() bool bHealPlayerAfterWave; + /** Can kill enemies by jumping on them */ + var() bool bGoompaJumpEnabled; + + /** Damage done when jumping over an enemy */ + var() int GoompaJumpDamage; + + /** Damage added per goompa streak */ + var() float GoompaStreakDamage; + + /** Max number of goompa jumps that counts for damage increase */ + var() int GoompaStreakMax; + + /** Impulse applied to the player when jumping over an enemy */ + var() float GoompaJumpImpulse; + + /** Duration of the goompa streak bonus */ + var() float GoompaBonusDuration; + + /** Z velocity for jumping */ + var() float JumpZ; + + /** Drop items lifespan */ + var() float DroppedItemLifespan; + /** Global modifier of dosh received by players when a zed is killed. Default value is 1.0 */ var() float DoshOnKillGlobalModifier; /** Delay After a wave starts for applying global damage. */ var() float DamageDelayAfterWaveStarted; + /** If weapon pickups should spawn unfinitely */ + var() bool bUnlimitedWeaponPickups; + /** If another outbreak mode shares the same events, this will link the two to quicker UI lookup */ var() int WeeklyOutbreakId; @@ -378,13 +407,23 @@ struct WeeklyOverrides bGlobalDamageAffectsShield = true bApplyGlobalDamageBossWave = true bHealPlayerAfterWave = false + bGoompaJumpEnabled = false + bUnlimitedWeaponPickups = false + GoompaJumpDamage = 0; + GoompaStreakDamage = 0; + GoompaJumpImpulse = 0; + GoompaStreakMax = 0; + GoompaBonusDuration = 0.0f; DamageDelayAfterWaveStarted = 10.0f WeeklyOutbreakId=INDEX_NONE + bAddSpawnListToLoadout = false bSpawnWeaponListAffectsSecondaryWeapons = false bColliseumSkillConditionsActive = false bModifyZedTimeOnANearZedKill = false ZedTimeOnANearZedKill = 0.05 DoshOnKillGlobalModifier = 1.0f + JumpZ = -1.f + DroppedItemLifespan=-1.0f } }; @@ -756,7 +795,6 @@ function AdjustMonsterDefaults(out KFPawn_Monster P) P.HealByKill = ToAdjust.HealByKill; P.HealByAssistance = ToAdjust.HealByAssistance; - P.InitialGroundSpeedModifier *= ToAdjust.InitialGroundSpeedModifierScale; if (ToAdjust.bStartEnraged) diff --git a/KFGame/Classes/KFPawn.uc b/KFGame/Classes/KFPawn.uc index 36c6feb..a427045 100644 --- a/KFGame/Classes/KFPawn.uc +++ b/KFGame/Classes/KFPawn.uc @@ -871,6 +871,14 @@ var bool bLogCustomAnim; var Texture2D DebugRadarTexture; var repnotify bool bHasStartedFire; +var repnotify byte WeaponSpecialAction; + +/********************************************************************************************* +* @name Cached last hit index. +* Afflictions are failing to get the proper zone index of the hit as it is read before + written. This is a temp fix for it. +********************************************************************************************* */ +var transient byte LastHitZoneIndex; replication { @@ -897,7 +905,7 @@ replication // Replicated to all but the owning client if ( bNetDirty && (!bNetOwner || bDemoRecording) ) - WeaponAmbientSound, SecondaryWeaponAmbientSound; + WeaponAmbientSound, SecondaryWeaponAmbientSound, WeaponSpecialAction; if ( bEnableAimOffset && (!bNetOwner || bDemoRecording) ) ReplicatedAimOffsetPct; if ( bNetDirty && bCanCloak ) @@ -1155,6 +1163,8 @@ simulated event ReplicatedEvent(name VarName) OnStartFire(); } break; + case nameof(WeaponSpecialAction): + OnWeaponSpecialAction(WeaponSpecialAction); } Super.ReplicatedEvent(VarName); @@ -1886,6 +1896,20 @@ simulated function OnStartFire() } } +simulated function OnWeaponSpecialAction(int Arg) +{ + if (Role == ROLE_Authority) + { + WeaponSpecialAction = Arg; + bNetDirty = true; + } + + if(WeaponAttachment != none) + { + WeaponAttachment.OnSpecialEvent(Arg); + } +} + /** * Called when a pawn's weapon has fired and is responsibile for * delegating the creation off all of the different effects. @@ -2673,7 +2697,7 @@ event TakeDamage(int Damage, Controller InstigatedBy, vector HitLocation, vector Super.TakeDamage(Damage, InstigatedBy, HitLocation, Momentum, DamageType, HitInfo, DamageCauser); // using the passed in damage type instead of the hitfxinfo since that doesn't get updated when zero damage is done - HandleAfflictionsOnHit(InstigatedBy, Normal(Momentum), class(DamageType), DamageCauser); + // HandleAfflictionsOnHit(InstigatedBy, Normal(Momentum), class(DamageType), DamageCauser); ActualDamage = OldHealth - Health; if( ActualDamage > 0 ) @@ -2776,6 +2800,8 @@ function AdjustDamage(out int InDamage, out vector Momentum, Controller Instigat InDamage = Health - 1; } + LastHitZoneIndex = HitZoneIdx; + `log(self @ GetFuncName() @ " After KFPawn adjustment Damage=" $ InDamage @ "Momentum=" $ Momentum @ "Zone=" $ HitInfo.BoneName @ "DamageType=" $ DamageType, bLogTakeDamage); } @@ -3999,12 +4025,12 @@ simulated function KFSkinTypeEffects GetHitZoneSkinTypeEffects( int HitZoneIdx ) */ simulated function AdjustAffliction(out float AfflictionPower); -function HandleAfflictionsOnHit(Controller DamageInstigator, vector HitDir, class DamageType, Actor DamageCauser) +function HandleAfflictionsOnHit(Controller DamageInstigator, vector HitDir, class DamageType, Actor DamageCauser) { //Handle afflictions if (AfflictionHandler != None) { - AfflictionHandler.NotifyTakeHit(DamageInstigator, HitDir, DamageType, DamageCauser); + AfflictionHandler.NotifyTakeHit(DamageInstigator, HitDir, class(DamageType), DamageCauser); } } @@ -5623,4 +5649,5 @@ defaultproperties bAllowDeathSM=true bCanBePinned=false + LastHitZoneIndex=0 } diff --git a/KFGame/Classes/KFPawn_Human.uc b/KFGame/Classes/KFPawn_Human.uc index 93b8143..d255d66 100644 --- a/KFGame/Classes/KFPawn_Human.uc +++ b/KFGame/Classes/KFPawn_Human.uc @@ -230,6 +230,8 @@ cpptext virtual UBOOL ShouldTrace(UPrimitiveComponent* Primitive,AActor *SourceActor, DWORD TraceFlags); } +native function float GetGravityZ(); + /********************************************************************************************* * @name General ********************************************************************************************* */ @@ -309,6 +311,9 @@ function PossessedBy(Controller C, bool bVehicleTransition) { SetTimer( 1.f, true, nameOf(Timer_CheckSurrounded) ); } + + KFGameInfo(WorldInfo.Game).OverrideHumanDefaults( self ); + } simulated function NotifyTeamChanged() @@ -2093,6 +2098,22 @@ function UpdateActiveSkillsPath(string IconPath, bool Active) KFPC.MyGFxHUD.PlayerStatusContainer.ShowActiveIndicators(ActiveSkillIconPaths); } +event Landed(vector HitNormal, actor FloorActor) +{ + local KFPlayerController_WeeklySurvival KFPC; + + super.Landed(HitNormal, FloorActor); + + if (KFPawn_Monster(FloorActor) == none) + { + KFPC = KFPlayerController_WeeklySurvival(Controller); + if (KFPC != none) + { + KFPC.ResetGoompaStreak(); + } + } +} + defaultproperties { Begin Object Class=KFFlashlightAttachment name=Flashlight_0 diff --git a/KFGame/Classes/KFPawn_Monster.uc b/KFGame/Classes/KFPawn_Monster.uc index 2cc6465..d03e54b 100644 --- a/KFGame/Classes/KFPawn_Monster.uc +++ b/KFGame/Classes/KFPawn_Monster.uc @@ -592,6 +592,8 @@ native function SetChokePointCollision( bool bUseChokeCollision ); /** Checks if we are our current location encroaches any world geometry */ native function bool CheckEncroachingWorldGeometry(); +native function float GetGravityZ(); + /** * Check on various replicated data and act accordingly. */ @@ -1392,6 +1394,58 @@ function SetMovementPhysics() /** Implements bKnockdownWhenJumpedOn */ function CrushedBy(Pawn OtherPawn) { + local KFGameInfo KFGI; + local KFPlayerController_WeeklySurvival KFPC_WS; + local KFPawn_Human KFPH; + local KFPlayerController KFPC; + local KFPlayerReplicationInfo KFPRI; + + KFPH = KFPawn_Human(OtherPawn); + + if (KFPH != none) + { + /* + * For summer season event, we wanto to know if we stomp a zed. + * Adding the notify here will prevent more network data. + * DmgType_Crushed is enough for it, no need to add the goompa. + */ + KFPC = KFPlayerController(KFPH.Controller); + if (KFPC != none) + { + KFPC.NotifyHitGiven(class'DmgType_Crushed'); + } + + /// + + KFGI = KFGameInfo(WorldInfo.Game); + if (KFGI != none) // Only for players + { + if (KFGI.OutbreakEvent.ActiveEvent.bGoompaJumpEnabled) + { + OtherPawn.Velocity = OtherPawn.Velocity * vect(1,1,0); + OtherPawn.AddVelocity( vect(0,0,1) * KFGI.OutbreakEvent.ActiveEvent.GoompaJumpImpulse, Instigator.Location, none); + TakeDamage( KFGI.OutbreakEvent.ActiveEvent.GoompaJumpDamage, OtherPawn.Controller,Location, vect(0,0,0) , class'KFDT_GoompaStomp'); + + KFPC_WS = KFPlayerController_WeeklySurvival(OtherPawn.Controller); + if(KFPC_WS != none) + { + KFPC_WS.UpdateGoompaStreak(); + } + + // Registering awards information. + `RecordAARIntStat(KFPC, STOMP_GIVEN, 1); + KFPRI = KFPlayerReplicationInfo(KFPC.PlayerReplicationInfo); + if (KFPRI != none) + { + KFPRI.ZedStomps++; + } + + return; + } + } + } + + Super.CrushedBy(OtherPawn); if ( bKnockdownWhenJumpedOn @@ -2087,6 +2141,7 @@ function AdjustDamageForInstigator(out int InDamage, Controller InstigatedBy, cl local KFPawn_Human KFPH; local KFPerk InstigatorPerk; local KFPowerUp InstigatorPowerUp; + local KFGameInfo KFGI; local float TempDamage; // Let the instigator's perk adjust the damage @@ -2105,6 +2160,12 @@ function AdjustDamageForInstigator(out int InDamage, Controller InstigatedBy, cl InstigatorPowerUp.ModifyDamageGiven(InDamage, DamageCauser, self, KFPC, class(DamageType), HitZoneIdx); } + KFGI = KFGameInfo(WorldInfo.Game); + if(KFGI != none && KFGI.OutbreakEvent != none) + { + KFGI.ModifyDamageGiven(InDamage, DamageCauser, self, KFPC, class(DamageType), HitZoneIdx); + } + if( KFPC.Pawn != none ) { KFPH = KFPawn_Human(KFPC.Pawn); diff --git a/KFGame/Classes/KFPerk.uc b/KFGame/Classes/KFPerk.uc index a6c4e25..c78b2de 100644 --- a/KFGame/Classes/KFPerk.uc +++ b/KFGame/Classes/KFPerk.uc @@ -472,6 +472,28 @@ static function bool IsDual9mm( KFWeapon KFW ) return KFW != none && KFW.Class.Name == 'KFWeap_Pistol_Dual9mm'; } +/** + * @brief Return if a weapon is FAMAS (special case for high capacity perk) + * + * @param KFW Weapon to check + * @return true if backup weapon + */ +static function bool IsFAMAS( KFWeapon KFW ) +{ + return KFW != none && KFW.Class.Name == 'KFWeap_AssaultRifle_FAMAS'; +} + +/** + * @brief Return if a weapon is the Blast Brawlers (special case needed for ZedTime perks) + * + * @param KFW Weapon to check + * @return true if backup weapon + */ +static function bool IsBlastBrawlers( KFWeapon KFW ) +{ + return KFW != none && KFW.Class.Name == 'KFWeap_HRG_BlastBrawlers'; +} + /********************************************************************************************* * @name Build / Level Management - Apply and save the updated build and level ********************************************************************************************* */ @@ -941,15 +963,17 @@ function AddDefaultInventory( KFPawn P ) if (KFGameInfo(WorldInfo.Game) != none) { - if (KFGameInfo(WorldInfo.Game).AllowPrimaryWeapon(GetPrimaryWeaponClassPath())) - { - P.DefaultInventory.AddItem(class(DynamicLoadObject(GetPrimaryWeaponClassPath(), class'Class'))); - } + if (KFGameInfo(WorldInfo.Game).AllowPrimaryWeapon(GetPrimaryWeaponClassPath())) + { + P.DefaultInventory.AddItem(class(DynamicLoadObject(GetPrimaryWeaponClassPath(), class'Class'))); + } if(KFGameInfo(WorldInfo.Game).AllowSecondaryWeapon(GetSecondaryWeaponClassPath())) { P.DefaultInventory.AddItem(class(DynamicLoadObject(GetSecondaryWeaponClassPath(), class'Class'))); } + + KFGameInfo(WorldInfo.Game).AddWeaponsFromSpawnList(P); } else { diff --git a/KFGame/Classes/KFPerk_Berserker.uc b/KFGame/Classes/KFPerk_Berserker.uc index 34185a3..8082cdd 100644 --- a/KFGame/Classes/KFPerk_Berserker.uc +++ b/KFGame/Classes/KFPerk_Berserker.uc @@ -195,7 +195,7 @@ simulated function ModifyMeleeAttackSpeed( out float InDuration, KFWeapon KFW ) { local float TempDuration; - if( KFW == none || !KFW.IsMeleeWeapon() ) + if( KFW == none || !KFW.IsMeleeWeapon() || IsBlastBrawlers(KFW) ) { return; } @@ -265,7 +265,7 @@ simulated function ModifySpeed( out float Speed ) } if (MyKFWeapon != none && - (MyKFWeapon.IsMeleeWeapon() || IsWeaponOnPerk(MyKFWeapon,, self.class))) + ((MyKFWeapon.IsMeleeWeapon() && !IsBlastBrawlers(MyKFWeapon)) || IsWeaponOnPerk(MyKFWeapon,, self.class))) { Speed += Speed * GetSkillValue( PerkSkills[EBerserkerNinja] ); } @@ -297,7 +297,7 @@ simulated function ModifySprintSpeed( out float Speed ) } if (MyKFWeapon != none && - (MyKFWeapon.IsMeleeWeapon() || IsWeaponOnPerk(MyKFWeapon,, self.class))) + ((MyKFWeapon.IsMeleeWeapon() && !IsBlastBrawlers(MyKFWeapon)) || IsWeaponOnPerk(MyKFWeapon,, self.class))) { Speed += Speed * static.GetNinjaSprintModifier(); } @@ -973,7 +973,7 @@ static function PrepareExplosive( Pawn ProjOwner, KFProjectile Proj, optional fl DefaultProperties { - ParryDuration=10.f + ParryDuration=6.f //10.f ParrySpeed=0.05 FurySpeed=0.05 NinjaSprintModifer=0.25 @@ -982,14 +982,14 @@ DefaultProperties SpeedDamageModifier=0.2 SmashHeadDamageModifier=0.25 VampireAttackSpeedModifier=0.2f - ParryDamageReduction=0.4f //0.75 + ParryDamageReduction=0.25f //0.4f //0.75 RageRadius=1000 //300 RageFleeDuration=5.f //3 RageFleeDistance=2500 //5000 RageDialogEvent=229 RegenerationInterval=1 - RegenerationAmount=2 + RegenerationAmount=1 //2 ZedTimeModifyingStates(0)="MeleeChainAttacking" ZedTimeModifyingStates(1)="MeleeAttackBasic" @@ -1013,14 +1013,14 @@ DefaultProperties GrenadeWeaponDef=class'KFWeapDef_Grenade_Berserker' BerserkerDamage=(Name="Berserker Damage",Increment=0.01,Rank=0,StartingValue=0.f,MaxValue=0.25) - DamageResistance=(Name="Damage Resistance",Increment=0.03f,Rank=0,StartingValue=0.f,MaxValue=0.15f) + DamageResistance=(Name="Damage Resistance",Increment=0.02f,Rank=0,StartingValue=0.f,MaxValue=0.1f) //0.03f, 0, 0.f, 0.15f NightVision=(Name="Night Vision",Increment=0.f,Rank=0,StartingValue=0.f,MaxValue=0.f) PerkSkills(EBerserkerFortitude)=(Name="Fortitude",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_Fortitude",Increment=0.f,Rank=0,StartingValue=1.0,MaxValue=1.0) //0.75 PerkSkills(EBerserkerNinja)=(Name="Ninja",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_Ninja",Increment=0.f,Rank=0,StartingValue=0.2f,MaxValue=0.2f) - PerkSkills(EBerserkerVampire)=(Name="Vampire",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_Vampire",Increment=0.f,Rank=0,StartingValue=4.f,MaxValue=4.f) + PerkSkills(EBerserkerVampire)=(Name="Vampire",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_Vampire",Increment=0.f,Rank=0,StartingValue=3.f,MaxValue=3.f) //4.f PerkSkills(EBerserkerSpeed)=(Name="Speed",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_Speed",Increment=0.f,Rank=0,StartingValue=0.2f,MaxValue=0.2f) - PerkSkills(EBerserkerResistance)=(Name="Resistance",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_PoisonResistance",Increment=0.f,Rank=0,StartingValue=0.25f,MaxValue=0.25f) //0.2 + PerkSkills(EBerserkerResistance)=(Name="Resistance",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_PoisonResistance",Increment=0.f,Rank=0,StartingValue=0.15f,MaxValue=0.15f) //0.15 //0.2 PerkSkills(EBerserkerParry)=(Name="Parry",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_Parry",Increment=0.f,Rank=0,StartingValue=0.35,MaxValue=0.35) PerkSkills(EBerserkerSmash)=(Name="Smash",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_Smash",Increment=0.f,Rank=0,StartingValue=0.5f,MaxValue=0.5f) PerkSkills(EBerserkerFury)=(Name="Fury",IconPath="UI_PerkTalent_TEX.berserker.UI_Talents_Berserker_Intimidate",Increment=0.f,Rank=0,StartingValue=0.3f,MaxValue=0.3f) diff --git a/KFGame/Classes/KFPerk_Commando.uc b/KFGame/Classes/KFPerk_Commando.uc index a937102..d4e0dbe 100644 --- a/KFGame/Classes/KFPerk_Commando.uc +++ b/KFGame/Classes/KFPerk_Commando.uc @@ -250,7 +250,8 @@ simulated function ModifyMagSizeAndNumber( KFWeapon KFW, out int MagazineCapacit TempCapacity = MagazineCapacity; - if( !bSecondary && IsWeaponOnPerk( KFW, WeaponPerkClass, self.class ) && (KFW == none || !KFW.bNoMagazine) ) + // FAMAS needs its secondary ammo affected + if( (!bSecondary || IsFAMAS(KFW)) && IsWeaponOnPerk( KFW, WeaponPerkClass, self.class ) && (KFW == none || !KFW.bNoMagazine) ) { if( IsLargeMagActive() ) { diff --git a/KFGame/Classes/KFPerk_Demolitionist.uc b/KFGame/Classes/KFPerk_Demolitionist.uc index e4f73e8..54af445 100644 --- a/KFGame/Classes/KFPerk_Demolitionist.uc +++ b/KFGame/Classes/KFPerk_Demolitionist.uc @@ -1037,7 +1037,7 @@ DefaultProperties PerkSkills(EDemoDamage)=(Name="Damage",IconPath="UI_PerkTalent_TEX.demolition.UI_Talents_Demolition_GrenadeSupplier",Increment=0.f,Rank=0,StartingValue=0.25f,MaxValue=0.25f) PerkSkills(EDemoTacticalReload)=(Name="Speed",IconPath="UI_PerkTalent_TEX.demolition.UI_Talents_Demolition_Speed",Increment=0.f,Rank=0,StartingValue=0.10f,MaxValue=0.10f) PerkSkills(EDemoDirectHit)=(Name="DirectHit",IconPath="UI_PerkTalent_TEX.demolition.UI_Talents_Demolition_ExplosiveResistance",Increment=0.f,Rank=0,StartingValue=0.25,MaxValue=0.25) - PerkSkills(EDemoAmmo)=(Name="Ammo",IconPath="UI_PerkTalent_TEX.demolition.UI_Talents_Demolition_Ammo",Increment=0.f,Rank=0,StartingValue=5.f,MaxValue=5.f,) + PerkSkills(EDemoAmmo)=(Name="Ammo",IconPath="UI_PerkTalent_TEX.demolition.UI_Talents_Demolition_Ammo",Increment=0.f,Rank=0,StartingValue=10.f,MaxValue=10.f) //5.f PerkSkills(EDemoSirenResistance)=(Name="SirenResistance",IconPath="UI_PerkTalent_TEX.demolition.UI_Talents_Demolition_SirenResistance",Increment=0.f,Rank=0,StartingValue=0.5,MaxValue=0.5) PerkSkills(EDemoAoE)=(Name="AreaOfEffect",IconPath="UI_PerkTalent_TEX.demolition.UI_Talents_Demolition_AoE",Increment=0.f,Rank=0,StartingValue=1.50,MaxValue=1.50) PerkSkills(EDemoCriticalHit)=(Name="CriticalHit",IconPath="UI_PerkTalent_TEX.demolition.UI_Talents_Demolition_Crit",Increment=0.f,Rank=0,StartingValue=0.5f,MaxValue=0.5f) diff --git a/KFGame/Classes/KFPerk_FieldMedic.uc b/KFGame/Classes/KFPerk_FieldMedic.uc index 5554a21..2ab17e2 100644 --- a/KFGame/Classes/KFPerk_FieldMedic.uc +++ b/KFGame/Classes/KFPerk_FieldMedic.uc @@ -645,7 +645,7 @@ DefaultProperties ProgressStatID=STATID_Medic_Progress PerkBuildStatID=STATID_Medic_Build - SelfHealingSurgePct=0.1f + SelfHealingSurgePct=0.06f //0.1f MaxSurvivalistResistance=0.60f //0.70f //0.5f //0.8 CombatantSpeedModifier=0.1f @@ -726,7 +726,7 @@ DefaultProperties HealPotency=(Name="Healer Potency",Increment=0.02f,Rank=0,StartingValue=1.0f,MaxValue=1.5f) BloatBileResistance=(Name="Bloat Bile Resistance",Increment=0.02,Rank=0,StartingValue=0.f,MaxValue=0.5f) MovementSpeed=(Name="Movement Speed",Increment=0.004f,Rank=0,StartingValue=0.f,MaxValue=0.1f) - Armor=(Name="Armor",Increment=0.03f,Rank=0,StartingValue=1.f,MaxValue=1.75f) + Armor=(Name="Armor",Increment=0.02f,Rank=0,StartingValue=1.f,MaxValue=1.5f) //0.03f, 0f, 1f, 1.75f PerkSkills(EMedicHealingSurge)=(Name="HealingSurge",IconPath="UI_PerkTalent_TEX.Medic.UI_Talents_Medic_HealingSurge", Increment=0.f,Rank=0,StartingValue=0.25,MaxValue=0.25) PerkSkills(EMedicSurvivalist)=(Name="Survivalist",IconPath="ui_perktalent_tex.Medic.UI_Talents_Medic_Resilience", Increment=0.f,Rank=0,StartingValue=0.01f,MaxValue=0.01f) diff --git a/KFGame/Classes/KFPerk_Support.uc b/KFGame/Classes/KFPerk_Support.uc index 465286c..4e18291 100644 --- a/KFGame/Classes/KFPerk_Support.uc +++ b/KFGame/Classes/KFPerk_Support.uc @@ -246,7 +246,8 @@ simulated function ModifyMagSizeAndNumber( KFWeapon KFW, out int MagazineCapacit TempCapacity = MagazineCapacity; - if( !bSecondary && IsWeaponOnPerk( KFW, WeaponPerkClass, self.class ) && (KFW == none || !KFW.bNoMagazine) && + // FAMAS needs its secondary ammo affected + if( (!bSecondary || IsFAMAS(KFW)) && IsWeaponOnPerk( KFW, WeaponPerkClass, self.class ) && (KFW == none || !KFW.bNoMagazine) && HighCapMagExemptList.Find(WeaponClassName) == INDEX_NONE ) { if( IsHighCapMagsMagActive() ) @@ -559,8 +560,9 @@ simulated function float GetZedTimeModifier( KFWeapon W ) local name StateName; StateName = W.GetStateName(); + // Blast Brawlers use a different state for shooting (combining melee + firing). Needs a special case for this if( IsWeaponOnPerk( W,, self.class ) && CouldBarrageActive() && - ZedTimeModifyingStates.Find( StateName ) != INDEX_NONE ) + (ZedTimeModifyingStates.Find( StateName ) != INDEX_NONE || (StateName == 'MeleeChainAttacking' && IsBlastBrawlers(W)))) { return BarrageFiringRate; } @@ -821,7 +823,7 @@ DefaultProperties ShotgunPenetration=(Name="Shotgun Penetration",Increment=0.20,Rank=0,StartingValue=0.0f,MaxValue=5.0f) //6.25 Strength=(Name="Strength",Increment=1.f,Rank=0,StartingValue=0.f,MaxValue=5.f) - PerkSkills(ESupportHighCapMags)=(Name="HighCapMags",IconPath="UI_PerkTalent_TEX.support.UI_Talents_Support_HighCapacityMags",Increment=0.f,Rank=0,StartingValue=0.5,MaxValue=0.5) //0.25 + PerkSkills(ESupportHighCapMags)=(Name="HighCapMags",IconPath="UI_PerkTalent_TEX.support.UI_Talents_Support_HighCapacityMags",Increment=0.f,Rank=0,StartingValue=0.75,MaxValue=0.75) //0.5 PerkSkills(ESupportTacticalReload)=(Name="TacticalReload",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_TacticalReload",Increment=0.f,Rank=0,StartingValue=0.8f,MaxValue=0.f) PerkSkills(ESupportFortitude)=(Name="Fortitude",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_Fortitude",Increment=0.f,Rank=0,StartingValue=0.5f,MaxValue=0.5f) PerkSkills(ESupportSalvo)=(Name="Salvo",IconPath="UI_PerkTalent_TEX.Support.UI_Talents_Support_Salvo",Increment=0.f,Rank=0,StartingValue=0.3f,MaxValue=0.3f) diff --git a/KFGame/Classes/KFPerk_Survivalist.uc b/KFGame/Classes/KFPerk_Survivalist.uc index 5a135fb..27adb60 100644 --- a/KFGame/Classes/KFPerk_Survivalist.uc +++ b/KFGame/Classes/KFPerk_Survivalist.uc @@ -462,11 +462,13 @@ simulated function float GetAoERadiusModifier() simulated function float GetZedTimeModifier( KFWeapon W ) { local name StateName; - if( GetMadManActive() && (!W.IsMeleeWeapon() || KFWeap_MeleeBase(W).default.bHasToBeConsideredAsRangedWeaponForPerks )) + if( GetMadManActive() && (!W.IsMeleeWeapon() || KFWeap_MeleeBase(W).default.bHasToBeConsideredAsRangedWeaponForPerks || IsBlastBrawlers(W) )) { StateName = W.GetStateName(); `Warn(StateName); - if( ZedTimeModifyingStates.Find( StateName ) != INDEX_NONE ) + + // Blast Brawlers use a different state for shooting (combining melee + firing). Needs a special case for this + if( ZedTimeModifyingStates.Find( StateName ) != INDEX_NONE || (StateName == 'MeleeChainAttacking' && IsBlastBrawlers(W)) ) { return GetSkillValue( PerkSkills[ESurvivalist_MadMan] ); } diff --git a/KFGame/Classes/KFPickupFactory_Item.uc b/KFGame/Classes/KFPickupFactory_Item.uc index ca2165c..972a1a8 100644 --- a/KFGame/Classes/KFPickupFactory_Item.uc +++ b/KFGame/Classes/KFPickupFactory_Item.uc @@ -20,7 +20,7 @@ struct native ItemPickup var() class ItemClass; /** Chance relative to other valid attacks (Works like AnimNodeRandom) */ - var() const float Priority; + var() float Priority; structdefaultproperties { @@ -49,6 +49,24 @@ replication PickupIndex; } +simulated event PreBeginPlay() +{ + local KFGameInfo KFGI; + +// For Scavenger weekly, we need to treat the factory items as non kismet items. + KFGI = KFGameInfo( WorldInfo.Game ); + if (KFGI != none && KFGI.OutbreakEvent != none && KFGI.OutbreakEvent.ActiveEvent.bUnlimitedWeaponPickups) + { + if (bKismetDriven && bEnabledAtStart) + { + bKismetDriven=false; + } + } +//////////////////////////////////////// + + super.PreBeginPlay(); +} + simulated event ReplicatedEvent(name VarName) { super.ReplicatedEvent( VarName ); @@ -98,14 +116,32 @@ function Reset() SetPickupMesh(); } +simulated event OverridePickup() +{ + PickupIndex = ChooseWeaponPickup(); + bNetDirty=true; + SetPickupMesh(); +} + function SetRespawn() { + local KFGameInfo KFGI; + //For ones that spawn in the world on timer, reset info here. if (bKismetDriven && bEnabledAtStart) { PickupIndex = ChooseWeaponPickup(); SetPickupMesh(); } + else + { + KFGI = KFGameInfo( WorldInfo.Game ); + if (KFGI != none && KFGI.OutbreakEvent != none && KFGI.OutbreakEvent.ActiveEvent.bUnlimitedWeaponPickups) + { + StartSleeping(); + return; + } + } super.SetRespawn(); } @@ -158,6 +194,11 @@ simulated native function GetPickupMesh(class ItemClass); /** Use the pickups static mesh for this factory */ simulated function SetPickupMesh() { + if (PickupIndex >= ItemPickups.Length) + { + return; + } + if (ItemPickups[PickupIndex].ItemClass.Name == ArmorClassName) { FinalizePickupMesh(StaticMeshComponent(ItemPickups[PickupIndex].ItemClass.default.PickupFactoryMesh).StaticMesh); @@ -181,6 +222,11 @@ simulated event FinalizePickupMesh(StaticMesh NewMesh) /** Give the pickup or its ammo to the player */ function GiveTo( Pawn P ) { + if (PickupIndex >= ItemPickups.Length) + { + return; + } + if ( ItemPickups[ PickupIndex ].ItemClass.Name == ArmorClassName ) { GiveArmor( P ); @@ -276,7 +322,7 @@ function ActivateNewPickup(Pawn P) /** Determine what kind of pickup is visible. Used for dialog. */ function bool CurrentPickupIsWeapon() { - if( ItemPickups.Length == 0 ) + if( ItemPickups.Length == 0 || ItemPickups.Length <= PickupIndex) { return false; } @@ -286,7 +332,7 @@ function bool CurrentPickupIsWeapon() function bool CurrentPickupIsArmor() { - if( ItemPickups.Length == 0 ) + if( ItemPickups.Length == 0 || ItemPickups.Length <= PickupIndex) { return false; } diff --git a/KFGame/Classes/KFPlayerController.uc b/KFGame/Classes/KFPlayerController.uc index ebaf45a..6b6237c 100644 --- a/KFGame/Classes/KFPlayerController.uc +++ b/KFGame/Classes/KFPlayerController.uc @@ -543,6 +543,7 @@ struct native PostWaveReplicationInfo var Vector VectData1; //used for compressing data //X:HeadShots Y:Dosh Earned Z:Damage Dealt var Vector VectData2; //used for compressing data //Damage Taken, Heals Received, Heals Given + var byte NumStomps; var byte LargeZedKills; //Dialog var bool bDiedDuringWave; @@ -6475,6 +6476,14 @@ function UpdateRhythmCounterWidget( int Count, int Max ) } } +function UpdateGoompaCounterWidget(int Count, int Max) +{ + if( MyGFxHUD != none ) + { + MyGFxHUD.UpdateGoompaCounterWidget(Count, Max); + } +} + /********************************************************************************************* * Objective * Tell the objective that a player has accepted/denied the objective @@ -7266,7 +7275,7 @@ reliable client event ClientUnlockAchievement( int AchievementIndex, optional bo { if( WorldInfo.IsConsoleBuild( CONSOLE_Durango ) ) { - `log("PS4: Client unlock achievement: " @AchievementIndex); + `log("Client unlock achievement: " @AchievementIndex); // Just toggle the stat relevent to this to on now, so the next stats write will trigger the achievement unlock. StatsWrite.UnlockDingoAchievement(AchievementIndex); OnlineSub.StatsInterface.WriteOnlineStats('Game', PlayerReplicationInfo.UniqueId, StatsWrite); @@ -7357,6 +7366,12 @@ function NotifyHitTaken() } native reliable client private function ClientNotifyHitTaken(); +function NotifyHitGiven(class DT) +{ + ClientNotifyHitGiven(DT); +} +native reliable client private function ClientNotifyHitGiven(class DT); + /** Kill stat */ function AddZedKill( class MonsterClass, byte Difficulty, class DT, bool bKiller ) { diff --git a/KFGame/Classes/KFPlayerController_WeeklySurvival.uc b/KFGame/Classes/KFPlayerController_WeeklySurvival.uc index abffe78..4ca6b41 100644 --- a/KFGame/Classes/KFPlayerController_WeeklySurvival.uc +++ b/KFGame/Classes/KFPlayerController_WeeklySurvival.uc @@ -24,6 +24,23 @@ var float ZedTimeHeight; /** How often to check for coming out of partial zed time if bUsingPermanentZedTime is on */ var float ZedRecheckTime; +/** Number of consecutive goompa stomps */ +var int GoompaStreak; + +/** Bonus to apply */ +var int GoompaStreakBonus; + +/** Max number of goompa stomps for damage bonus */ +var transient int MaxGoompaStreak; + +var protected const name RhytmMethodRTPCName; +var protected const AkEvent RhythmMethodSoundReset; +var protected const AkEvent RhythmMethodSoundHit; +var protected const AkEvent RhythmMethodSoundTop; +var protected const AkEvent AracnoStompSoundEvent; + + + cpptext { virtual UBOOL TestZedTimeVisibility(APawn* P, UNetConnection* Connection, UBOOL bLocalPlayerTest) override; @@ -32,9 +49,23 @@ cpptext replication { if (bNetDirty) - bUsingPermanentZedTime, ZedTimeRadius, ZedTimeBossRadius, ZedTimeHeight; + bUsingPermanentZedTime, ZedTimeRadius, ZedTimeBossRadius, ZedTimeHeight, GoompaStreak; } +simulated event PostBeginPlay() +{ + local KFGameInfo KFGI; + + super.PostBeginPlay(); + + KFGI = KFGameInfo(WorldInfo.Game); + if (KFGI != none && KFGI.OutbreakEvent != none && KFGI.OutbreakEvent.ActiveEvent.bGoompaJumpEnabled) + { + MaxGoompaStreak = KFGI.OutbreakEvent.ActiveEvent.GoompaStreakMax; + } +} + + function EnterZedTime() { local bool bNewResult; @@ -81,4 +112,99 @@ function EnterZedTime() function RecheckZedTime() { EnterZedTime(); +} + +/** + Arachnophobia Goompa Stomp Streak functions + */ +function UpdateGoompaStreak() +{ + ++GoompaStreak; + GoompaStreakBonus = GoompaStreak; + UpdateGoompaCounterWidget(GoompaStreak, MaxGoompaStreak); + GoompaStompMessage(GoompaStreak); + + if (IsTimerActive(nameof(ResetStreakInfo))) + { + ClearTimer(nameof(ResetStreakInfo)); + } +} + +function ResetGoompaStreak() +{ + local KFGameInfo KFGI; + + if (GoompaStreak > 0) + { + KFGI = KFGameInfo(WorldInfo.Game); + GoompaStreak = 0; + if(KFGI != none) + { + SetTimer(KFGI.OutbreakEvent.ActiveEvent.GoompaBonusDuration, false, nameof(ResetStreakInfo)); + } + } +} + +function ResetStreakInfo() +{ + UpdateGoompaCounterWidget(GoompaStreak, MaxGoompaStreak); + GoompaStompMessage(GoompaStreak); + GoompaStreakBonus = 0; +} + +function bool IsGoompaBonusActive() +{ + return GoompaStreakBonus > 0; +} + +reliable client function GoompaStompMessage( byte StompNum) +{ + local int i; + local AkEvent TempAkEvent; + + if( MyGFxHUD == none ) + { + return; + } + + i = StompNum; + UpdateGoompaCounterWidget( StompNum, MaxGoompaStreak ); + + if (StompNum == 0) + { + TempAkEvent = RhythmMethodSoundReset; + } + else if (StompNum == MaxGoompaStreak - 1) + { + TempAkEvent = RhythmMethodSoundHit; + } + else if (StompNum == MaxGoompaStreak) + { + TempAkEvent = RhythmMethodSoundTop; + ++i; + } + + if( TempAkEvent != none ) + { + PlayRMEffect( TempAkEvent, RhytmMethodRTPCName, i ); + } + + if (StompNum > 0 && AracnoStompSoundEvent != none) + { + PlaySoundBase(AracnoStompSoundEvent); + } +} + + +// +defaultProperties +{ + GoompaStreak = 0 + MaxGoompaStreak = -1 + GoompaStreakBonus = 0 + RhytmMethodRTPCName ="R_Method" + RhythmMethodSoundReset =AkEvent'WW_UI_PlayerCharacter.Play_R_Method_Reset' + RhythmMethodSoundHit =AkEvent'WW_UI_PlayerCharacter.Play_R_Method_Hit' + RhythmMethodSoundTop =AkEvent'WW_UI_PlayerCharacter.Play_R_Method_Top' + AracnoStompSoundEvent =AkEvent'WW_GLO_Runtime.WeeklyArcno' } \ No newline at end of file diff --git a/KFGame/Classes/KFPlayerReplicationInfo.uc b/KFGame/Classes/KFPlayerReplicationInfo.uc index d9365e4..42d81f6 100644 --- a/KFGame/Classes/KFPlayerReplicationInfo.uc +++ b/KFGame/Classes/KFPlayerReplicationInfo.uc @@ -125,6 +125,8 @@ var bool bNukeActive; var bool bConcussiveActive; /** Certain perks can supply ammo etc. We need to replicate that for the HUD */ var byte PerkSupplyLevel; +/** Number of stomps during Arachnophobia */ +var int ZedStomps; /************************************ * Not replicated Perk Data, @@ -203,7 +205,7 @@ replication RepCustomizationInfo, NetPerkIndex, ActivePerkLevel, ActivePerkPrestigeLevel, bHasSpawnedIn, CurrentPerkClass, bObjectivePlayer, Assists, PlayerHealth, PlayerHealthPercent, bExtraFireRange, bSplashActive, bNukeActive, bConcussiveActive, PerkSupplyLevel, - CharPortrait, DamageDealtOnTeam, bVOIPRegisteredWithOSS, CurrentVoiceCommsRequest,CurrentHeadShotEffectID, bCarryingCollectible; + CharPortrait, DamageDealtOnTeam, bVOIPRegisteredWithOSS, CurrentVoiceCommsRequest,CurrentHeadShotEffectID, bCarryingCollectible, ZedStomps; // sent to non owning clients if ( bNetDirty && (!bNetOwner || bDemoRecording) ) diff --git a/KFGame/Classes/KFSeasonalEventStats.uc b/KFGame/Classes/KFSeasonalEventStats.uc index 6c851be..0d65945 100644 --- a/KFGame/Classes/KFSeasonalEventStats.uc +++ b/KFGame/Classes/KFSeasonalEventStats.uc @@ -72,4 +72,5 @@ simulated function OnBossDied(); simulated event OnWaveCompleted(class GameClass, int Difficulty, int WaveNum); simulated event OnTriggerUsed(class TriggerClass); simulated event OnTryCompleteObjective(int ObjectiveIndex, int EventIndex); -simulated function OnHitTaken(); \ No newline at end of file +simulated function OnHitTaken(); +simulated function OnHitGiven(class DT); \ No newline at end of file diff --git a/KFGame/Classes/KFUnlockManager.uc b/KFGame/Classes/KFUnlockManager.uc index c588b0f..7b06a8e 100644 --- a/KFGame/Classes/KFUnlockManager.uc +++ b/KFGame/Classes/KFUnlockManager.uc @@ -28,6 +28,8 @@ enum ESharedContentUnlock SCU_MineReconstructor, SCU_FrostFang, SCU_GravityImploder, + SCU_FAMAS, + SCU_Thermite }; @@ -330,4 +332,12 @@ defaultproperties Name=KFWeap_GravityImploder, IconPath="WEP_UI_Gravity_Imploder_TEX.UI_WeaponSelect_Gravity_Imploder", ID=8778)} + SharedContentList(SCU_FAMAS)={( + Name=KFWeap_AssaultRifle_FAMAS, + IconPath="WEP_UI_Famas_TEX.UI_WeaponSelect_Famas", + ID=8934)} + SharedContentList(SCU_Thermite)={( + Name=KFWeap_RocketLauncher_ThermiteBore, + IconPath="WEP_UI_Thermite_TEX.UI_WeaponSelect_Thermite", + ID=8940)} } diff --git a/KFGame/Classes/KFVoteCollector.uc b/KFGame/Classes/KFVoteCollector.uc index d0780f5..c07e35a 100644 --- a/KFGame/Classes/KFVoteCollector.uc +++ b/KFGame/Classes/KFVoteCollector.uc @@ -468,7 +468,7 @@ function ServerStartVoteSkipTrader(PlayerReplicationInfo PRI) GetKFPRIArray(PRIs); for (i = 0; i < PRIs.Length; i++) { - PRIs[i].ShowSkipTraderVote(PRI, CurrentVoteTime, !(PRIs[i] == PRI)); + PRIs[i].ShowSkipTraderVote(PRI, CurrentVoteTime, !(PRIs[i] == PRI) && PRI.GetTeamNum() != 255); } KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', LMT_SkipTraderVoteStarted, CurrentSkipTraderVote.PlayerPRI); SetTimer( CurrentVoteTime, false, nameof(ConcludeVoteSkipTrader), self ); diff --git a/KFGame/Classes/KFWeapDef_FAMAS.uc b/KFGame/Classes/KFWeapDef_FAMAS.uc new file mode 100644 index 0000000..3f2f590 --- /dev/null +++ b/KFGame/Classes/KFWeapDef_FAMAS.uc @@ -0,0 +1,35 @@ +//============================================================================= +// KFWeapDef_FAMAS +//============================================================================= +// A lightweight container for basic weapon properties that can be safely +// accessed without a weapon actor (UI, remote clients). +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFWeapDef_FAMAS extends KFWeaponDefinition + abstract; + +defaultproperties +{ + WeaponClassPath="KFGameContent.KFWeap_AssaultRifle_FAMAS" + + BuyPrice=1200 + + AmmoPricePerMag=25 + SecondaryAmmoMagPrice=15 //13 + SecondaryAmmoMagSize=6 // Num of bullets given (not magazines) + + ImagePath="WEP_UI_Famas_TEX.UI_WeaponSelect_Famas" + + EffectiveRange=67 // @TODO: ¿?¿?¿? + + UpgradePrice[0]=700 + UpgradePrice[1]=1500 + + UpgradeSellPrice[0]=525 + UpgradeSellPrice[1]=1650 + + SharedUnlockId=SCU_FAMAS +} diff --git a/KFGame/Classes/KFWeapDef_HRG_BarrierRifle.uc b/KFGame/Classes/KFWeapDef_HRG_BarrierRifle.uc new file mode 100644 index 0000000..be48ea9 --- /dev/null +++ b/KFGame/Classes/KFWeapDef_HRG_BarrierRifle.uc @@ -0,0 +1,24 @@ +//============================================================================= +// KFWeapDef_HRG_BarrierRifle +//============================================================================= +// +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= +class KFWeapDef_HRG_BarrierRifle extends KFWeaponDefinition + abstract; + +DefaultProperties +{ + WeaponClassPath="KFGameContent.KFWeap_HRG_BarrierRifle" + + BuyPrice=2000 + AmmoPricePerMag=55 + ImagePath="wep_ui_hrg_barrierrifle_tex.UI_WeaponSelect_HRG_BarrierRifle" + + EffectiveRange=68 + + //UpgradePrice[0]=1500 + //UpgradeSellPrice[0]=1125 +} \ No newline at end of file diff --git a/KFGame/Classes/KFWeapDef_HRG_BlastBrawlers.uc b/KFGame/Classes/KFWeapDef_HRG_BlastBrawlers.uc new file mode 100644 index 0000000..e8aaabb --- /dev/null +++ b/KFGame/Classes/KFWeapDef_HRG_BlastBrawlers.uc @@ -0,0 +1,26 @@ +//============================================================================= +// KFWeapDef_HRG_BlastBrawlers +//============================================================================= +// +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= +class KFWeapDef_HRG_BlastBrawlers extends KFWeaponDefinition + abstract; + +DefaultProperties +{ + WeaponClassPath="KFGameContent.KFWeap_HRG_BlastBrawlers" + + BuyPrice=1600 + AmmoPricePerMag=30 + + ImagePath="WEP_UI_HRG_BlastBrawlers_TEX.UI_WeaponSelect_HRG_BlastBrawlers" + + EffectiveRange=15 + + UpgradePrice[0]=1500 + + UpgradeSellPrice[0]=1125 +} \ No newline at end of file diff --git a/KFGame/Classes/KFWeapDef_ThermiteBore.uc b/KFGame/Classes/KFWeapDef_ThermiteBore.uc new file mode 100644 index 0000000..3bb606b --- /dev/null +++ b/KFGame/Classes/KFWeapDef_ThermiteBore.uc @@ -0,0 +1,26 @@ +//============================================================================= +// KFWeapDef_ThermiteBore +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFWeapDef_ThermiteBore extends KFWeaponDefinition + abstract; + +DefaultProperties +{ + WeaponClassPath="KFGameContent.KFWeap_RocketLauncher_ThermiteBore" + + BuyPrice=1500 + AmmoPricePerMag=78 + ImagePath="WEP_UI_Thermite_TEX.UI_WeaponSelect_Thermite" + + EffectiveRange=78 + + UpgradePrice[0]=1500 + + UpgradeSellPrice[0]=1125 + + SharedUnlockId=SCU_Thermite +} diff --git a/KFGame/Classes/KFWeap_ScopedBase.uc b/KFGame/Classes/KFWeap_ScopedBase.uc index d0aad69..7c87d6e 100644 --- a/KFGame/Classes/KFWeap_ScopedBase.uc +++ b/KFGame/Classes/KFWeap_ScopedBase.uc @@ -43,6 +43,8 @@ var int CurrentScopeTextureSize; var(Scope) float ScopedSensitivityMod; +/** MIC Index for the scope material */ +var byte ScopeMICIndex; simulated exec function ScopeFOV( float NewFOV ) { @@ -128,7 +130,7 @@ reliable client function ClientWeaponSet(bool bOptionalSet, optional bool bDoNot ScopeLenseMIC.SetParent(ScopeLenseMICTemplate); ScopeLenseMIC.SetTextureParameterValue('ScopeTextureTarget', SniperScopeTextureTarget); ScopeLenseMIC.SetScalarParameterValue(InterpParamName, 0.0); - mesh.SetMaterial(2, ScopeLenseMIC); + mesh.SetMaterial(ScopeMICIndex, ScopeLenseMIC); } } @@ -351,4 +353,6 @@ DefaultProperties // Aim Assist AimCorrectionSize=40.f + + ScopeMICIndex=2 } \ No newline at end of file diff --git a/KFGame/Classes/KFWeapon.uc b/KFGame/Classes/KFWeapon.uc index 92b37da..18c8612 100644 --- a/KFGame/Classes/KFWeapon.uc +++ b/KFGame/Classes/KFWeapon.uc @@ -367,6 +367,9 @@ var int InitialSpareMags[2]; /** What percentage of a full single magazine capacity to give when resupplying this weapon from an ammo pickup */ var(Inventory) float AmmoPickupScale[2]; +/** */ +var(Inventory) bool bUsesSecondaryAmmoAltHUD; + enum EReloadStatus { RS_None, @@ -4396,6 +4399,11 @@ static simulated event bool UsesSecondaryAmmo() return default.MagazineCapacity[1] > 0; } +static simulated event bool UsesAltSecondaryAmmo() +{ + return default.bUsesSecondaryAmmoAltHUD; +} + /** * Returns true if this weapon uses greandes as secondary ammo */ @@ -4754,6 +4762,12 @@ simulated function int GetSecondaryAmmoForHUD() return AmmoCount[1] + SpareAmmoCount[1]; } +/** Determines the secondary spare ammo */ +simulated function int GetSecondarySpareAmmoForHUD() +{ + return -1; +} + /** Determines if we have to reload the secondary ammo of the weapon (EX: m16 grenades) */ simulated function bool HasToReloadSecondaryAmmoForHUD() { @@ -7985,5 +7999,7 @@ defaultproperties NumPellets(CUSTOM_FIREMODE)=1 bKeepIronSightsOnJump=false + + bUsesSecondaryAmmoAltHUD = false } diff --git a/KFGame/Classes/KFWeaponAttachment.uc b/KFGame/Classes/KFWeaponAttachment.uc index 36c220b..081293b 100644 --- a/KFGame/Classes/KFWeaponAttachment.uc +++ b/KFGame/Classes/KFWeaponAttachment.uc @@ -1223,6 +1223,9 @@ simulated State LoopingWeaponAction } } +/** Special event added for weap attachments. Free for use */ +function OnSpecialEvent(int Arg); + defaultproperties { Begin Object class=AnimNodeSequence Name=MeshSequenceA diff --git a/KFGame/Classes/KFWeaponSkinList.uc b/KFGame/Classes/KFWeaponSkinList.uc index b3512c4..e1e102a 100644 --- a/KFGame/Classes/KFWeaponSkinList.uc +++ b/KFGame/Classes/KFWeaponSkinList.uc @@ -3522,4 +3522,103 @@ defaultproperties //Coliseum Zweihander Skins.Add((Id=8791, Weapondef=class'KFWeapDef_Zweihander', MIC_1P=("WEP_SkinSet42_MAT.coliseum_zweihander.Coliseum_Zweihander_1P_Mint_MIC"), MIC_3P="WEP_SkinSet42_MAT.coliseum_zweihander.Coliseum_Zweihander_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet42_MAT.coliseum_zweihander.Coliseum_Zweihander_3P_Pickup_MIC")); + +//Famas Standard + Skins.Add((Id=8934, Weapondef=class'KFWeapDef_FAMAS', MIC_1P=("WEP_1P_Famas_MAT.Wep_1stP_Famas_MIC"), MIC_3P="WEP_3P_Famas_MAT.Wep_3rdP_Famas_MIC", MIC_Pickup="WEP_3P_Famas_MAT.Wep_3rdP_Famas_Pickup_MIC")); + +//Famas Flourished + Skins.Add((Id=8935, Weapondef=class'KFWeapDef_FAMAS', MIC_1P=("WEP_SkinSet45_MAT.Wep_1stP_Famas_Flourished_MIC"), MIC_3P="WEP_SkinSet45_MAT.Wep_3rdP_Famas_Flourished_MIC", MIC_Pickup="WEP_SkinSet45_MAT.Wep_3rdP_Famas_Pickup_Flourished_MIC")); + +//Famas Jagged Wars + Skins.Add((Id=8936, Weapondef=class'KFWeapDef_FAMAS', MIC_1P=("WEP_SkinSet45_MAT.Wep_1stP_Famas_JaggedWars_MIC"), MIC_3P="WEP_SkinSet45_MAT.Wep_3rdP_Famas_JaggedWars_MIC", MIC_Pickup="WEP_SkinSet45_MAT.Wep_3rdP_Famas_Pickup_JaggedWars_MIC")); + +//Famas Japped + Skins.Add((Id=8937, Weapondef=class'KFWeapDef_FAMAS', MIC_1P=("WEP_SkinSet45_MAT.Wep_1stP_Famas_Japped_MIC"), MIC_3P="WEP_SkinSet45_MAT.Wep_3rdP_Famas_Japped_MIC", MIC_Pickup="WEP_SkinSet45_MAT.Wep_3rdP_Famas_Pickup_Japped_MIC")); + +//Famas Skull Candy + Skins.Add((Id=8938, Weapondef=class'KFWeapDef_FAMAS', MIC_1P=("WEP_SkinSet45_MAT.Wep_1stP_Famas_SkullCandy_MIC"), MIC_3P="WEP_SkinSet45_MAT.Wep_3rdP_Famas_SkullCandy_MIC", MIC_Pickup="WEP_SkinSet45_MAT.Wep_3rdP_Famas_Pickup_SkullCandy_MIC")); + +//Famas Turfed + Skins.Add((Id=8939, Weapondef=class'KFWeapDef_FAMAS', MIC_1P=("WEP_SkinSet45_MAT.Wep_1stP_Famas_Turfed_MIC"), MIC_3P="WEP_SkinSet45_MAT.Wep_3rdP_Famas_Turfed_MIC", MIC_Pickup="WEP_SkinSet45_MAT.Wep_3rdP_Famas_Pickup_Turfed_MIC")); + +//Thermite Standard + Skins.Add((Id=8940, Weapondef=class'KFWeapDef_ThermiteBore', MIC_1P=("WEP_1P_Thermite_MAT.Wep_1P_Thermite_MIC"), MIC_3P="WEP_3P_Thermite_MAT.WEP_3P_Thermite_MIC", MIC_Pickup="WEP_3p_Gravity_Imploder_MAT.Wep_3rdP_Gravity_Imploder_Pickup_MIC")) + +//Thermite Japped + Skins.Add((Id=8941, Weapondef=class'KFWeapDef_ThermiteBore', MIC_1P=("WEP_SkinSet46_MAT.Wep_1stP_Thermite_Japped_MIC"), MIC_3P="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_Japped_MIC", MIC_Pickup="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_Pickup_Japped_MIC")); + +//Thermite Much Danger + Skins.Add((Id=8942, Weapondef=class'KFWeapDef_ThermiteBore', MIC_1P=("WEP_SkinSet46_MAT.Wep_1stP_Thermite_MuchDanger_MIC"), MIC_3P="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_MuchDanger_MIC", MIC_Pickup="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_Pickup_MuchDanger_MIC")); + +//Thermite Not Liandri + Skins.Add((Id=8943, Weapondef=class'KFWeapDef_ThermiteBore', MIC_1P=("WEP_SkinSet46_MAT.Wep_1stP_Thermite_NotLiandri_MIC"), MIC_3P="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_NotLiandri_MIC", MIC_Pickup="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_Pickup_NotLiandri_MIC")); + +//Thermite Rusted + Skins.Add((Id=8944, Weapondef=class'KFWeapDef_ThermiteBore', MIC_1P=("WEP_SkinSet46_MAT.Wep_1stP_Thermite_Rusted_MIC"), MIC_3P="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_Rusted_MIC", MIC_Pickup="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_Pickup_Rusted_MIC")); + +//Thermite Thunder Jaws + Skins.Add((Id=8945, Weapondef=class'KFWeapDef_ThermiteBore', MIC_1P=("WEP_SkinSet46_MAT.Wep_1stP_Thermite_ThunderJaws_MIC"), MIC_3P="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_ThunderJaws_MIC", MIC_Pickup="WEP_SkinSet46_MAT.Wep_3rdP_Thermite_Pickup_ThunderJaws_MIC")); + +//BeyondHorizon AA12 + Skins.Add((Id=8845, Weapondef=class'KFWeapDef_AA12', MIC_1P=("WEP_SkinSet43_MAT.space_aa12.Space_AA12_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_aa12.Space_AA12_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_aa12.Space_AA12_3P_Pickup_MIC")) + +//BeyondHorizon AK12 + Skins.Add((Id=8846, Weapondef=class'KFWeapDef_Ak12', MIC_1P=("WEP_SkinSet43_MAT.space_ak12.Space_AK12_1P_Mint_MIC", "WEP_SkinSet43_MAT.space_ak12.Space_AK12_Sight_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_ak12.Space_AK12_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_ak12.Space_AK12_3P_Pickup_MIC")) + +//BeyondHorizon Desert Eagle + Skins.Add((Id=8847, Weapondef=class'KFWeapDef_Deagle', MIC_1P=("WEP_SkinSet43_MAT.space_deagle.Space_Deagle_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_deagle.Space_Deagle_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_deagle.Space_Deagle_3P_Pickup_MIC")) + +//BeyondHorizon Doomstick + Skins.Add((Id=8848, Weapondef=class'KFWeapDef_ElephantGun', MIC_1P=("WEP_SkinSet43_MAT.space_quadbarrel.Space_QuadBarrel_Main_1P_Mint_MIC", "WEP_SkinSet43_MAT.space_quadbarrel.Space_QuadBarrel_Barrel_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_quadbarrel.Space_QuadBarrel_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_quadbarrel.Space_QuadBarrel_3P_Pickup_MIC")) + +//BeyondHorizon Hemoclobber + Skins.Add((Id=8849, Weapondef=class'KFWeapDef_MedicBat', MIC_1P=("WEP_SkinSet43_MAT.space_medicbat.Space_MedicBat_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_medicbat.Space_MedicBat_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_medicbat.Space_MedicBat_3P_Pickup_MIC")) + +//BeyondHorizon HMTech-501 Grenade Rifle + Skins.Add((Id=8850, Weapondef=class'KFWeapDef_MedicRifleGrenadeLauncher', MIC_1P=("WEP_SkinSet43_MAT.space_medicgrenadelauncher.Space_MedicGrenadeLauncher_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_medicgrenadelauncher.Space_MedicGrenadeLauncher_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_medicgrenadelauncher.Space_MedicGrenadeLauncher_3P_Pickup_MIC")) + +//BeyondHorizon M32 + Skins.Add((Id=8851, Weapondef=class'KFWeapDef_M32', MIC_1P=("WEP_SkinSet43_MAT.space_m32.Space_M32_1P_Mint_MIC", "WEP_SkinSet43_MAT.space_m32.Space_M32_Sight_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_m32.Space_M32_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_m32.Space_M32_3P_Pickup_MIC")) + +//BeyondHorizon MAC 10 + Skins.Add((Id=8852, Weapondef=class'KFWeapDef_Mac10', MIC_1P=("WEP_SkinSet43_MAT.space_mac10.Space_MAC10_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_mac10.Space_MAC10_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_mac10.Space_MAC10_3P_Pickup_MIC")) + +//BeyondHorizon Microwave Gun + Skins.Add((Id=8853, Weapondef=class'KFWeapDef_MicrowaveGun', MIC_1P=("WEP_SkinSet43_MAT.space_microwavegun.Space_MicrowaveGun_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_microwavegun.Space_MicrowaveGun_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_microwavegun.Space_MicrowaveGun_3P_Pickup_MIC")) + +//BeyondHorizon P90 + Skins.Add((Id=8854, Weapondef=class'KFWeapDef_P90', MIC_1P=("WEP_SkinSet43_MAT.space_p90.Space_P90_1P_Mint_MIC", "WEP_SkinSet43_MAT.space_p90.Space_P90_Sight_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.space_p90.Space_P90_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.space_p90.Space_P90_3P_Pickup_MIC")) + +//BeyondHorizon AA12 + Skins.Add((Id=8855, Weapondef=class'KFWeapDef_AA12', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_aa12.SpaceElite_AA12_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_aa12.SpaceElite_AA12_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_aa12.SpaceElite_AA12_3P_Pickup_MIC")) + +//BeyondHorizon AK12 + Skins.Add((Id=8856, Weapondef=class'KFWeapDef_Ak12', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_ak12.SpaceElite_AK12_1P_Mint_MIC", "WEP_SkinSet43_MAT.spaceelite_ak12.SpaceElite_AK12_Sight_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_ak12.SpaceElite_AK12_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_ak12.SpaceElite_AK12_3P_Pickup_MIC")) + +//BeyondHorizon Desert Eagle + Skins.Add((Id=8857, Weapondef=class'KFWeapDef_Deagle', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_deagle.SpaceElite_Deagle_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_deagle.SpaceElite_Deagle_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_deagle.SpaceElite_Deagle_3P_Pickup_MIC")) + +//BeyondHorizon Doomstick + Skins.Add((Id=8858, Weapondef=class'KFWeapDef_ElephantGun', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_quadbarrel.SpaceElite_QuadBarrel_Main_1P_Mint_MIC", "WEP_SkinSet43_MAT.spaceelite_quadbarrel.SpaceElite_QuadBarrel_Barrel_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_quadbarrel.SpaceElite_QuadBarrel_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_quadbarrel.SpaceElite_QuadBarrel_3P_Pickup_MIC")) + +//BeyondHorizon Hemoclobber + Skins.Add((Id=8859, Weapondef=class'KFWeapDef_MedicBat', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_medicbat.SpaceElite_MedicBat_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_medicbat.SpaceElite_MedicBat_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_medicbat.SpaceElite_MedicBat_3P_Pickup_MIC")) + +//BeyondHorizon HMTech-501 Grenade Rifle + Skins.Add((Id=8860, Weapondef=class'KFWeapDef_MedicRifleGrenadeLauncher', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_medicgrenadelauncher.SpaceElite_MedicGrenadeLauncher_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_medicgrenadelauncher.SpaceElite_MedicGrenadeLauncher_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_medicgrenadelauncher.SpaceElite_MedicGrenadeLauncher_3P_Pickup_MIC")) + +//BeyondHorizon M32 + Skins.Add((Id=8861, Weapondef=class'KFWeapDef_M32', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_m32.SpaceElite_M32_1P_Mint_MIC", "WEP_SkinSet43_MAT.spaceelite_m32.SpaceElite_M32_Sight_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_m32.SpaceElite_M32_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_m32.SpaceElite_M32_3P_Pickup_MIC")) + +//BeyondHorizon MAC 10 + Skins.Add((Id=8862, Weapondef=class'KFWeapDef_Mac10', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_mac10.SpaceElite_MAC10_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_mac10.SpaceElite_MAC10_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_mac10.SpaceElite_MAC10_3P_Pickup_MIC")) + +//BeyondHorizon Microwave Gun + Skins.Add((Id=8863, Weapondef=class'KFWeapDef_MicrowaveGun', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_microwavegun.SpaceElite_MicrowaveGun_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_microwavegun.SpaceElite_MicrowaveGun_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_microwavegun.SpaceElite_MicrowaveGun_3P_Pickup_MIC")) + +//BeyondHorizon P90 + Skins.Add((Id=8864, Weapondef=class'KFWeapDef_P90', MIC_1P=("WEP_SkinSet43_MAT.spaceelite_p90.SpaceElite_P90_1P_Mint_MIC", "WEP_SkinSet43_MAT.spaceelite_p90.SpaceElite_P90_Sight_1P_Mint_MIC"), MIC_3P="WEP_SkinSet43_MAT.spaceelite_p90.SpaceElite_P90_3P_Mint_MIC", MIC_Pickup="WEP_SkinSet43_MAT.spaceelite_p90.SpaceElite_P90_3P_Pickup_MIC")) + +//Scavenger AK12 + Skins.Add((Id=8921, Weapondef=class'KFWeapDef_Ak12', MIC_1P=("wep_skinset44_mat.scavenger_ak12.Scavenger_AK12_1P_Mint_MIC", "wep_skinset44_mat.scavenger_ak12.Scavenger_AK12_Scope_1P_Mint_MIC"), MIC_3P="wep_skinset44_mat.scavenger_ak12.Scavenger_AK12_3P_Mint_MIC", MIC_Pickup="wep_skinset44_mat.scavenger_ak12.Scavenger_AK12_3P_Pickup_MIC")) } \ No newline at end of file diff --git a/KFGame/KFMatchStats.uci b/KFGame/KFMatchStats.uci index 3e49d71..77260de 100644 --- a/KFGame/KFMatchStats.uci +++ b/KFGame/KFMatchStats.uci @@ -27,6 +27,7 @@ const MATCH_EVENT_HEAL_RECEIVED = 5; + const MATCH_EVENT_STOMP_GIVEN = 6; /** Match has ended */ const MATCH_EVENT_MAX_EVENTID = 0x0000FFFF; diff --git a/KFGame/KFOnlineStats.uci b/KFGame/KFOnlineStats.uci index ff34c37..1bad7c4 100644 --- a/KFGame/KFOnlineStats.uci +++ b/KFGame/KFOnlineStats.uci @@ -153,4 +153,5 @@ const STATID_ACHIEVE_DesolationCollectibles = 4055; const STATID_ACHIEVE_HellmarkStationCollectibles = 4056; const STATID_ACHIEVE_ElysiumEndlessWaveFifteen = 4057; const STATID_ACHIEVE_Dystopia2029Collectibles = 4058; +const STATID_ACHIEVE_MoonbaseCollectibles = 4059; /** `endif */ diff --git a/KFGameContent/Classes/KFDT_Ballistic_BlastBrawlersShotgun.uc b/KFGameContent/Classes/KFDT_Ballistic_BlastBrawlersShotgun.uc new file mode 100644 index 0000000..db71db0 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Ballistic_BlastBrawlersShotgun.uc @@ -0,0 +1,52 @@ +//============================================================================= +// KFDT_Ballistic_BlastBrawlersShotgun +//============================================================================= +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Ballistic_BlastBrawlersShotgun extends KFDT_Ballistic_Shotgun + abstract + hidedropdown; + +/** Allows the damage type to customize exactly which hit zones it can dismember */ +static simulated function bool CanDismemberHitZone( name InHitZoneName ) +{ + if( super.CanDismemberHitZone( InHitZoneName ) ) + { + return true; + } + + switch ( InHitZoneName ) + { + case 'lupperarm': + case 'rupperarm': + case 'chest': + case 'heart': + return true; + } + + return false; +} + +defaultproperties +{ + BloodSpread=0.4 + BloodScale=0.6 + + + KDamageImpulse=900 + KDeathUpKick=-500 + KDeathVel=350 + //KDamageImpulse=350 + //KDeathUpKick=120 + //KDeathVel=10 + + StumblePower=12 + GunHitPower=12 + + OverrideImpactEffect=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Impact' + + WeaponDef=class'KFWeapDef_HRG_BlastBrawlers' +} diff --git a/KFGameContent/Classes/KFDT_Ballistic_FAMAS_Rifle.uc b/KFGameContent/Classes/KFDT_Ballistic_FAMAS_Rifle.uc new file mode 100644 index 0000000..9ba4511 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Ballistic_FAMAS_Rifle.uc @@ -0,0 +1,27 @@ +//============================================================================= +// KFDT_Ballistic_FAMAS_Rifle +//============================================================================= +// Damage type class for the FAMAS rifle +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Ballistic_FAMAS_Rifle extends KFDT_Ballistic_AssaultRifle + abstract + hidedropdown; + +defaultproperties +{ + KDamageImpulse=900 + KDeathUpKick=-300 + KDeathVel=100 + + StumblePower=12 + GunHitPower=0 + + WeaponDef=class'KFWeapDef_FAMAS' + + ModifierPerkList(0)=class'KFPerk_Commando' + ModifierPerkList(1)=class'KFPerk_Support' +} diff --git a/KFGameContent/Classes/KFDT_Ballistic_FAMAS_Shotgun.uc b/KFGameContent/Classes/KFDT_Ballistic_FAMAS_Shotgun.uc new file mode 100644 index 0000000..a0bf84a --- /dev/null +++ b/KFGameContent/Classes/KFDT_Ballistic_FAMAS_Shotgun.uc @@ -0,0 +1,47 @@ +//============================================================================= +// KFDT_Ballistic_FAMAS_Shotgun +//============================================================================= +// Damage type class for the FAMAS shotgun alt fire +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Ballistic_FAMAS_Shotgun extends KFDT_Ballistic_Shotgun + abstract + hidedropdown; + +/** Allows the damage type to customize exactly which hit zones it can dismember */ +static simulated function bool CanDismemberHitZone( name InHitZoneName ) +{ + if( super.CanDismemberHitZone( InHitZoneName ) ) + { + return true; + } + + switch ( InHitZoneName ) + { + case 'lupperarm': + case 'rupperarm': + case 'chest': + case 'heart': + return true; + } + + return false; +} + +defaultproperties +{ + BloodSpread=0.4 + BloodScale=0.6 + + KDamageImpulse=900 + KDeathUpKick=500 + KDeathVel=350 + + StumblePower=10 + GunHitPower=15 + + WeaponDef=class'KFWeapDef_FAMAS' +} diff --git a/KFGameContent/Classes/KFDT_Ballistic_HRG_BarrierRifle.uc b/KFGameContent/Classes/KFDT_Ballistic_HRG_BarrierRifle.uc new file mode 100644 index 0000000..01caef0 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Ballistic_HRG_BarrierRifle.uc @@ -0,0 +1,26 @@ +//============================================================================= +// KFDT_Ballistic_HRG_BarrierRifle +//============================================================================= +// +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= +class KFDT_Ballistic_HRG_BarrierRifle extends KFDT_Ballistic_AssaultRifle + abstract + hidedropdown; + +defaultproperties +{ + KDamageImpulse=900 + KDeathUpKick=-300 + KDeathVel=100 + + StumblePower=20 + GunHitPower=20 + + WeaponDef=class'KFWeapDef_HRG_BarrierRifle' + + //Perk + ModifierPerkList(0)=class'KFPerk_SWAT' +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFDT_Ballistic_ThermiteBoreImpact.uc b/KFGameContent/Classes/KFDT_Ballistic_ThermiteBoreImpact.uc new file mode 100644 index 0000000..06f1697 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Ballistic_ThermiteBoreImpact.uc @@ -0,0 +1,55 @@ +//============================================================================= +// KFDT_Ballistic_ThermiteBoreImpact +//============================================================================= +// Rocket impact damage type for the Thermite rocket launcher +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Ballistic_ThermiteBoreImpact extends KFDT_Ballistic_Shell + abstract + hidedropdown; + +// Damage type to use for the burning damage over time +var class BurnDamageType; + +static simulated function bool CanDismemberHitZone(name InHitZoneName) +{ + return false; +} + +static simulated function bool CanDismemberHitZoneWhileAlive(name InHitZoneName) +{ + return false; +} + +/** Called when damage is dealt to apply additional damage type (e.g. Damage Over Time) */ +static function ApplySecondaryDamage( KFPawn Victim, int DamageTaken, optional Controller InstigatedBy ) +{ + // Overriden to specific a different damage type to do the burn damage over + // time. We do this so we don't get shotgun pellet impact sounds/fx during + // the DOT burning. + if ( default.BurnDamageType.default.DoT_Type != DOT_None ) + { + Victim.ApplyDamageOverTime(DamageTaken, InstigatedBy, default.BurnDamageType); + } +} + +defaultproperties +{ + KDamageImpulse=0 + KDeathUpKick=0 + KDeathVel=0 + + BurnPower=50 + KnockdownPower=50 + StumblePower=350 + GunHitPower=300 + + BurnDamageType=class'KFDT_Fire_ThermiteImpactDoT' + + ModifierPerkList(0)=class'KFPerk_FireBug' + + WeaponDef=class'KFWeapDef_ThermiteBore' +} diff --git a/KFGameContent/Classes/KFDT_Bludgeon_BlastBrawlers.uc b/KFGameContent/Classes/KFDT_Bludgeon_BlastBrawlers.uc new file mode 100644 index 0000000..655b8b5 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Bludgeon_BlastBrawlers.uc @@ -0,0 +1,24 @@ +//============================================================================= +// KFDT_Bludgeon_BlastBrawlers +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Bludgeon_BlastBrawlers extends KFDT_Bludgeon + abstract + hidedropdown; + +defaultproperties +{ + KDamageImpulse=2500 + KDeathUpKick=500 + KDeathVel=400 + + MeleeHitPower=100 + StunPower=0 + StumblePower=0 + + WeaponDef=class'KFWeapDef_HRG_BlastBrawlers' + ModifierPerkList(0)=class'KFPerk_Support' +} diff --git a/KFGameContent/Classes/KFDT_Bludgeon_BlastBrawlersBash.uc b/KFGameContent/Classes/KFDT_Bludgeon_BlastBrawlersBash.uc new file mode 100644 index 0000000..fb5b417 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Bludgeon_BlastBrawlersBash.uc @@ -0,0 +1,25 @@ +//============================================================================= +// KFDT_Bludgeon_BlastBrawlersBash +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Bludgeon_BlastBrawlersBash extends KFDT_Bludgeon + abstract + hidedropdown; + +defaultproperties +{ + KDamageImpulse=3500 + KDeathUpKick=800 + KDeathVel=575 + + KnockdownPower=0 + StunPower=0 + StumblePower=200 + MeleeHitPower=100 + + WeaponDef=class'KFWeapDef_HRG_BlastBrawlers' + ModifierPerkList(0)=class'KFPerk_Support' +} diff --git a/KFGameContent/Classes/KFDT_Bludgeon_BlastBrawlersHeavy.uc b/KFGameContent/Classes/KFDT_Bludgeon_BlastBrawlersHeavy.uc new file mode 100644 index 0000000..a2e77e7 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Bludgeon_BlastBrawlersHeavy.uc @@ -0,0 +1,28 @@ +//============================================================================= +// KFDT_Bludgeon_BlastBrawlersHeavy +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Bludgeon_BlastBrawlersHeavy extends KFDT_Bludgeon + abstract + hidedropdown; + +defaultproperties +{ + KDamageImpulse=3500 + KDeathUpKick=800 + KDeathVel=575 + + KnockdownPower=75 + StunPower=0 + StumblePower=150 + MeleeHitPower=150 + EMPPower=0 + + WeaponDef=class'KFWeapDef_HRG_BlastBrawlers' + ModifierPerkList(0)=class'KFPerk_Support' + + //OverrideImpactEffect=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_Static_Strikers_Impact' +} diff --git a/KFGameContent/Classes/KFDT_Bludgeon_FAMAS.uc b/KFGameContent/Classes/KFDT_Bludgeon_FAMAS.uc new file mode 100644 index 0000000..5e3706c --- /dev/null +++ b/KFGameContent/Classes/KFDT_Bludgeon_FAMAS.uc @@ -0,0 +1,15 @@ +//============================================================================= +// KFDT_Bludgeon_FAMAS +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= +class KFDT_Bludgeon_FAMAS extends KFDT_Bludgeon_RifleButt + abstract + hidedropdown; + +DefaultProperties +{ + //defaults + WeaponDef=class'KFWeapDef_FAMAS' +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFDT_Bludgeon_HRG_BarrierRifle.uc b/KFGameContent/Classes/KFDT_Bludgeon_HRG_BarrierRifle.uc new file mode 100644 index 0000000..5c8434c --- /dev/null +++ b/KFGameContent/Classes/KFDT_Bludgeon_HRG_BarrierRifle.uc @@ -0,0 +1,15 @@ +//============================================================================= +// KFDT_Bludgeon_HRG_BarrierRifle +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2016 Tripwire Interactive LLC +//============================================================================= +class KFDT_Bludgeon_HRG_BarrierRifle extends KFDT_Bludgeon_RifleButt + abstract + hidedropdown; + +DefaultProperties +{ + //defaults + WeaponDef=class'KFWeapDef_HRG_BarrierRifle' +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFDT_Bludgeon_ThermiteBore.uc b/KFGameContent/Classes/KFDT_Bludgeon_ThermiteBore.uc new file mode 100644 index 0000000..3292904 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Bludgeon_ThermiteBore.uc @@ -0,0 +1,15 @@ +//============================================================================= +// KFDT_Bludgeon_ThermiteBore +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= +class KFDT_Bludgeon_ThermiteBore extends KFDT_Bludgeon_RifleButt + abstract + hidedropdown; + +DefaultProperties +{ + //defaults + WeaponDef=class'KFWeapDef_ThermiteBore' +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFDT_Explosive_Thermite.uc b/KFGameContent/Classes/KFDT_Explosive_Thermite.uc new file mode 100644 index 0000000..0c06d0a --- /dev/null +++ b/KFGameContent/Classes/KFDT_Explosive_Thermite.uc @@ -0,0 +1,49 @@ +//============================================================================= +// KFDT_Explosive_Thermite +//============================================================================= +// Explosive damage type for the Seal Squeal +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Explosive_Thermite extends KFDT_Fire + abstract + hidedropdown; + +// Damage type to use for the burning damage over time +var class BurnDamageType; + +/** Called when damage is dealt to apply additional damage type (e.g. Damage Over Time) */ +static function ApplySecondaryDamage( KFPawn Victim, int DamageTaken, optional Controller InstigatedBy ) +{ + // Overriden to specific a different damage type to do the burn damage over + // time. We do this so we don't get shotgun pellet impact sounds/fx during + // the DOT burning. + if ( default.BurnDamageType.default.DoT_Type != DOT_None ) + { + Victim.ApplyDamageOverTime(DamageTaken, InstigatedBy, default.BurnDamageType); + } +} + +defaultproperties +{ + bShouldSpawnPersistentBlood = true + + // physics impact + RadialDamageImpulse = 2000 + GibImpulseScale = 0.15 + KDeathUpKick = 1000 + KDeathVel = 300 + + KnockdownPower = 0 + BurnPower = 50 + StumblePower = 200 + + BurnDamageType=class'KFDT_Fire_ThermiteExplosionDoT' + + //Perk + ModifierPerkList(0) = class'KFPerk_Firebug' + + WeaponDef = class'KFWeapDef_ThermiteBore' +} diff --git a/KFGameContent/Classes/KFDT_Fire_Ground_ThermiteBore.uc b/KFGameContent/Classes/KFDT_Fire_Ground_ThermiteBore.uc new file mode 100644 index 0000000..1f0d31d --- /dev/null +++ b/KFGameContent/Classes/KFDT_Fire_Ground_ThermiteBore.uc @@ -0,0 +1,33 @@ +//============================================================================= +// KFDT_Fire_Ground_ThermiteBore +//============================================================================= +// Damage type class for the thermite bore ground fire +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Fire_Ground_ThermiteBore extends KFDT_Fire_Ground + abstract; + +defaultproperties +{ + bShouldSpawnPersistentBlood=false + + // physics impact + RadialDamageImpulse=0 + KDeathUpKick=0 + KDeathVel=0 + + KnockdownPower=0 + StumblePower=100 + BurnPower=10 + + // DOT + DoT_Duration=3.0 //5.0 + DoT_Interval=0.5 + DoT_DamageScale=0.5 //0.2 + bIgnoreSelfInflictedScale=false + + WeaponDef=class'KFWeapDef_ThermiteBore' +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFDT_Fire_ThermiteExplosionDoT.uc b/KFGameContent/Classes/KFDT_Fire_ThermiteExplosionDoT.uc new file mode 100644 index 0000000..040fe17 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Fire_ThermiteExplosionDoT.uc @@ -0,0 +1,42 @@ +//============================================================================= +// KFDT_Fire_ThermiteExplosionDoT +//============================================================================= +// Damage caused by burning from being hit by a thermite bore explosion +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Fire_ThermiteExplosionDoT extends KFDT_Fire + abstract + hidedropdown; + +static function int GetKillerDialogID() +{ + return 86;//KILL_Fire +} + +static function int GetDamagerDialogID() +{ + return 102;//DAMZ_Fire +} + +static function int GetDamageeDialogID() +{ + return 116;//DAMP_Fire +} + +defaultproperties +{ + WeaponDef=class'KFWeapDef_ThermiteBore' + + DoT_Type=DOT_Fire + DoT_Duration=3.0 + DoT_Interval=0.5 + DoT_DamageScale=0.2 + + BurnPower=10 + + // Explosion DOT does not damage the instigator + bNoInstigatorDamage=true +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFDT_Fire_ThermiteImpactDoT.uc b/KFGameContent/Classes/KFDT_Fire_ThermiteImpactDoT.uc new file mode 100644 index 0000000..3d50557 --- /dev/null +++ b/KFGameContent/Classes/KFDT_Fire_ThermiteImpactDoT.uc @@ -0,0 +1,40 @@ +//============================================================================= +// KFDT_Fire_ThermiteImpactDoT +//============================================================================= +// Damage caused by burning from being hit by a thermite bore projectile +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFDT_Fire_ThermiteImpactDoT extends KFDT_Fire + abstract + hidedropdown; + +static function int GetKillerDialogID() +{ + return 86;//KILL_Fire +} + +static function int GetDamagerDialogID() +{ + return 102;//DAMZ_Fire +} + +static function int GetDamageeDialogID() +{ + return 116;//DAMP_Fire +} + +defaultproperties +{ + WeaponDef=class'KFWeapDef_ThermiteBore' + + DoT_Type=DOT_Fire + DoT_Duration=3.0 + DoT_Interval=0.5 + DoT_DamageScale=0.2 + + BurnPower=10 +} + diff --git a/KFGameContent/Classes/KFExplosion_Thermite.uc b/KFGameContent/Classes/KFExplosion_Thermite.uc new file mode 100644 index 0000000..2fad611 --- /dev/null +++ b/KFGameContent/Classes/KFExplosion_Thermite.uc @@ -0,0 +1,30 @@ +//============================================================================= +// KFExplosion_Thermite +//============================================================================= +// Used by projectiles and kismet to spawn an explosion +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFExplosion_Thermite extends KFExplosionActorLingering; + +/** Replacement particles to play when hitting surfaces at different angles */ +var() ParticleSystem LoopingParticleEffectCeiling; +var() ParticleSystem LoopingParticleEffectWall; + +DefaultProperties +{ + Interval=0.5 + MaxTime=10 + + bDoFullDamage=true + + LoopingParticleEffect=ParticleSystem'WEP_Thermite_EMIT.FX_Thermite_ground_fire_01' + + LoopingParticleEffectCeiling=ParticleSystem'WEP_Thermite_EMIT.FX_Thermite_Spread_Ceiling_01' + LoopingParticleEffectWall=ParticleSystem'WEP_Thermite_EMIT.FX_Thermite_Spread_Wall_01' + + LoopStartEvent=AkEvent'WW_WEP_SA_Flamethrower.Play_WEP_SA_Flamethrower_Residual_Fire_Loop' + LoopStopEvent=AkEvent'WW_WEP_SA_Flamethrower.Stop_WEP_SA_Flamethrower_Residual_Fire_Loop' +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFGameInfo_Endless.uc b/KFGameContent/Classes/KFGameInfo_Endless.uc index 0ae5b32..c98258b 100644 --- a/KFGameContent/Classes/KFGameInfo_Endless.uc +++ b/KFGameContent/Classes/KFGameInfo_Endless.uc @@ -170,7 +170,7 @@ function bool TrySetNextWaveSpecial() function WaveEnded(EWaveEndCondition WinCondition) { - if(!bWaveStarted) + if(!bWaveStarted && !MyKFGRI.bTraderIsOpen && WinCondition != WEC_TeamWipedOut) { return; } diff --git a/KFGameContent/Classes/KFGameInfo_Survival.uc b/KFGameContent/Classes/KFGameInfo_Survival.uc index 1bb6db6..df92749 100644 --- a/KFGameContent/Classes/KFGameInfo_Survival.uc +++ b/KFGameContent/Classes/KFGameInfo_Survival.uc @@ -937,16 +937,19 @@ function ResetAllPickups() /** Overridden to scale the number of active pickups by wave */ function ResetPickups( array PickupList, int NumPickups ) { - if(NumPickups != 0) + NumPickups *= (float(WaveNum) / float(WaveMax)); + + // make sure to have at least 1 ammo pickup in the level, and if it's wave 2 or later make sure there's + // at least one weapon pickup. Also, we need to ensure if OverrideItemPickupModifier is set to 0 we really + // don't want any item pickups. + if( NumPickups == 0 && PickupList.Length > 0 + && (WaveNum > 1 + || KFPickupFactory_Ammo(PickupList[0]) != none + || (KFPickupFactory_Item(PickupList[0]) != none && (OutbreakEvent == none || OutbreakEvent.ActiveEvent.OverrideItemPickupModifier != 0)) + ) + ) { - NumPickups *= (float(WaveNum) / float(WaveMax)); - - // make sure to have at least 1 ammo pickup in the level, and if it's wave 2 or later make sure there's - // at least one weapon pickup - if( NumPickups == 0 && PickupList.Length > 0 && (WaveNum > 1 || KFPickupFactory_Ammo(PickupList[0]) != none) ) - { - NumPickups = 1; - } + NumPickups = 1; } super.ResetPickups( PickupList, NumPickups ); } @@ -1117,8 +1120,10 @@ function WaveEnded(EWaveEndCondition WinCondition) local int i; local KFPlayerController KFPC; - if(!bWaveStarted && !MyKFGRI.bTraderIsOpen) + if(!bWaveStarted && !MyKFGRI.bTraderIsOpen && WinCondition != WEC_TeamWipedOut) + { return; + } if (WorldInfo.NetMode == NM_DedicatedServer) { diff --git a/KFGameContent/Classes/KFGameInfo_WeeklySurvival.uc b/KFGameContent/Classes/KFGameInfo_WeeklySurvival.uc index 047cbc9..15c4e78 100644 --- a/KFGameContent/Classes/KFGameInfo_WeeklySurvival.uc +++ b/KFGameContent/Classes/KFGameInfo_WeeklySurvival.uc @@ -65,6 +65,11 @@ event PreBeginPlay() super.PreBeginPlay(); OutbreakEvent.UpdateGRI(); + + if (Role == Role_Authority && MyKFGRI != none && OutbreakEvent.ActiveEvent.bUnlimitedWeaponPickups) + { + MyKFGRI.NotifyBrokenTrader(); + } } function CreateOutbreakEvent() @@ -136,6 +141,7 @@ function SetPickupItemList() ItemFactory.ItemPickups.Remove(0, ItemFactory.ItemPickups.Length); continue; } + foreach OutbreakEvent.ActiveEvent.TraderWeaponList.SaleItems(TraderItem) { for (Idx = ItemFactory.ItemPickups.Length - 1; Idx >= 0; --Idx) @@ -241,14 +247,18 @@ protected function ScoreMonsterKill( Controller Killer, Controller Monster, KFPa function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer) { local int i; + local int j; local KFPlayerController KFPC; local KFPlayerReplicationInfo DamagerKFPRI; local array DamageHistory; local array Attackers; local KFPawn_Human PawnHuman; - + local KFGameInfo KFGI; + DamageHistory = MonsterPawn.DamageHistory; - + + KFGI = KFGameInfo(WorldInfo.Game); + for ( i = 0; i < DamageHistory.Length; i++ ) { if( DamageHistory[i].DamagerController != none @@ -266,9 +276,30 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer) { PawnHuman = KFPawn_Human(KFPC.Pawn); Attackers.AddItem(KFPC); + + /* + Weekly event Aracnophobia (10): + 2 kind of heales: one for killing and another for killing by jumping on enemies. + HealByAssistance is used for the latest, no need to add extra variables. + */ + if( KFPC == Killer && KFGI != none && KFGI.OutbreakEvent.ActiveEvent.bGoompaJumpEnabled ) + { + for (j = 0; j < DamageHistory[i].DamageTypes.Length; j++) + { + if (DamageHistory[i].DamageTypes[j] == class 'KFDT_GoompaStomp') + { + PawnHuman.HealDamageForce(MonsterPawn.HealByAssistance, KFPC, class'KFDT_Healing', false, false ); + return; + } + } + + PawnHuman.HealDamageForce(MonsterPawn.HealByKill, KFPC, class'KFDT_Healing', false, false ); + return; + } + // + if( KFPC == Killer ) { - `Log("Heal by Kill: "$MonsterPawn.HealByKill); PawnHuman.HealDamageForce(MonsterPawn.HealByKill, KFPC, class'KFDT_Healing', false, false ); if( KFPawn_ZedFleshpound(MonsterPawn) != none || KFPawn_ZedScrake(MonsterPawn) != none ) @@ -278,7 +309,6 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer) } else { - `Log("Heal by Assistance: "$MonsterPawn.HealByAssistance); PawnHuman.HealDamageForce(MonsterPawn.HealByAssistance, KFPC, class'KFDT_Healing', false, false ); } } @@ -286,7 +316,6 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer) } } } - } @@ -482,6 +511,34 @@ function StartWave() SetTimer(OutbreakEvent.ActiveEvent.AdditionalBossWaveStartDelay, true, nameof(SpawnBossWave)); } + if (OutbreakEvent.ActiveEvent.bUnlimitedWeaponPickups) + { + OverridePickupList(); + } +} + +function bool OverridePickupList() +{ + local KFPickupFactory PickupFactory; + local KFPickupFactory_Item ItemFactory; + local KFGameReplicationInfo_WeeklySurvival KFGRI_WS; + + KFGRI_WS=KFGameReplicationInfo_WeeklySurvival(MyKFGRI); + if (KFGRI_WS == none) + return false; + + foreach ItemPickups(PickupFactory) + { + ItemFactory = KFPickupFactory_Item(PickupFactory); + + if (ItemFactory == none) + continue; + + KFGRI_WS.OverrideWeaponPickups(ItemFactory); + ItemFactory.OverridePickup(); + } + + return true; } function EnableGlobalDamage() @@ -614,8 +671,6 @@ function InitAllPickups() { NumWeaponPickups = ItemPickups.Length * (OutbreakEvent.ActiveEvent.OverrideItemPickupModifier >= 0.f ? OutbreakEvent.ActiveEvent.OverrideItemPickupModifier : DifficultyInfo.GetItemPickupModifier()); NumAmmoPickups = AmmoPickups.Length * (OutbreakEvent.ActiveEvent.OverrideAmmoPickupModifier >= 0.f ? OutbreakEvent.ActiveEvent.OverrideAmmoPickupModifier : DifficultyInfo.GetAmmoPickupModifier()); - `log("OutbreakEvent.ActiveEvent.OverrideItemPickupModifier"@OutbreakEvent.ActiveEvent.OverrideItemPickupModifier); - `log("NumWeaponPickups"@NumWeaponPickups); `if(`__TW_SDK_) if( BaseMutator != none ) @@ -696,6 +751,7 @@ function class GetAISpawnType(EAIType AIType) function bool AllowPrimaryWeapon(string ClassPath) { local STraderItem Item; + if (OutbreakEvent.ActiveEvent.SpawnWeaponList != none) { foreach OutbreakEvent.ActiveEvent.SpawnWeaponList.SaleItems(Item) @@ -704,8 +760,8 @@ function bool AllowPrimaryWeapon(string ClassPath) { return true; } - } - return false; + } + return true; } return true; } @@ -788,6 +844,42 @@ function DoDeathExplosion(Pawn DeadPawn, KFGameExplosion ExplosionTemplate, clas } } +simulated function AddWeaponsFromSpawnList(KFPawn P) +{ + local STraderItem Item; + + if (OutbreakEvent.ActiveEvent.SpawnWeaponList != none || OutbreakEvent.ActiveEvent.bAddSpawnListToLoadout) + { + foreach OutbreakEvent.ActiveEvent.SpawnWeaponList.SaleItems(Item) + { + P.DefaultInventory.AddItem(class(DynamicLoadObject(Item.WeaponDef.default.WeaponClassPath, class'Class'))); + } + } +} + +simulated function OverrideHumanDefaults(KFPawn_Human P) +{ + if (OutbreakEvent.ActiveEvent.JumpZ >= 0.0f) + { + P.JumpZ = OutbreakEvent.ActiveEvent.JumpZ; + } +} + +simulated function ModifyDamageGiven(out int InDamage, optional Actor DamageCauser, optional KFPawn_Monster MyKFPM, optional KFPlayerController DamageInstigator, optional class DamageType, optional int HitZoneIdx ) +{ + local KFPlayerController_WeeklySurvival KFPC; + local int Streak; + + if (OutbreakEvent.ActiveEvent.bGoompaJumpEnabled) + { + KFPC = KFPlayerController_WeeklySurvival(DamageInstigator); + if (KFPC != none) + { + Streak = KFPC.GoompaStreakBonus < KFPC.MaxGoompaStreak ? KFPC.GoompaStreakBonus : KFPC.MaxGoompaStreak; + InDamage *= (1 + OutbreakEvent.ActiveEvent.GoompaStreakDamage * Streak); + } + } +} defaultproperties { diff --git a/KFGameContent/Classes/KFGameReplicationInfo_WeeklySurvival.uc b/KFGameContent/Classes/KFGameReplicationInfo_WeeklySurvival.uc index 8b514dd..6447aba 100644 --- a/KFGameContent/Classes/KFGameReplicationInfo_WeeklySurvival.uc +++ b/KFGameContent/Classes/KFGameReplicationInfo_WeeklySurvival.uc @@ -9,6 +9,14 @@ class KFGameReplicationInfo_WeeklySurvival extends KFGameReplicationInfo; +struct SBrokeTraderPickupItem +{ + /** Weapons available for spawning */ + var() array > WeaponClasses; +}; + +var() array BrokenTraderItemPickups; + simulated function array GetKFSeqEventLevelLoadedIndices() { local array ActivateIndices; @@ -16,4 +24,262 @@ simulated function array GetKFSeqEventLevelLoadedIndices() ActivateIndices[0] = 7; return ActivateIndices; -} \ No newline at end of file +} + +simulated function OverrideWeaponPickups(out KFPickupFactory_Item ItemFactory) +{ + local int Idx; + local ItemPickup Pickup; + + if (ItemFactory == none) + return; + + if ( BrokenTraderItemPickups.Length == 0 || WaveNum > BrokenTraderItemPickups.Length ) + return; + + ItemFactory.ItemPickups.Remove(0, ItemFactory.ItemPickups.Length); + + for(Idx = 0; Idx < BrokenTraderItemPickups[WaveNum-1].WeaponClasses.Length; Idx++) + { + Pickup.ItemClass = class (DynamicLoadObject(BrokenTraderItemPickups[WaveNum-1].WeaponClasses[Idx].default.WeaponClassPath, class'Class')); + ItemFactory.ItemPickups.AddItem(Pickup); + } +} + +simulated function NotifyWaveStart() +{ + local KFPickupFactory_Item ItemFactory; + + if (WorldInfo.NetMode == NM_Client && bIsBrokenTrader) + { + foreach AllActors(class'KFPickupFactory_Item', ItemFactory) + { + OverrideWeaponPickups(ItemFactory); + ItemFactory.SetPickupMesh(); + } + } + + super.NotifyWaveStart(); +} + +DefaultProperties +{ + BrokenTraderItemPickups={( + (WeaponClasses={( + class'KFGame.KFWeapDef_9mmDual', + class'KFGame.KFWeapDef_Crovel', + class'KFGame.KFWeapDef_MB500', + class'KFGame.KFWeapDef_MedicPistol', + class'KFGame.KFWeapDef_HX25', + class'KFGame.KFWeapDef_CaulkBurn', + class'KFGame.KFWeapDef_Remington1858Dual', + class'KFGame.KFWeapDef_Winchester1894', + class'KFGame.KFWeapDef_MP7', + class'KFGame.KFWeapDef_AR15' + )}), + (WeaponClasses={( + class'KFGame.KFWeapDef_Nailgun', + class'KFGame.KFWeapDef_Katana', + class'KFGame.KFWeapDef_ChainBat', + class'KFGame.KFWeapDef_FireAxe', + class'KFGame.KFWeapDef_Bullpup', + class'KFGame.KFWeapDef_Thompson', + class'KFGame.KFWeapDef_DoubleBarrel', + class'KFGame.KFWeapDef_HZ12', + class'KFGame.KFWeapDef_DragonsBreath', + class'KFGame.KFWeapDef_MedicSMG', + class'KFGame.KFWeapDef_Healthrower_HRG', + class'KFGame.KFWeapDef_M79', + class'KFGame.KFWeapDef_FlareGunDual', + class'KFGame.KFWeapDef_Mac10', + class'KFGame.KFWeapDef_HRGScorcher', + class'KFGame.KFWeapDef_Colt1911Dual', + class'KFGame.KFWeapDef_HRGWinterbite', + class'KFGame.KFWeapDef_CenterfireMB464', + class'KFGame.KFWeapDef_Crossbow', + class'KFGame.KFWeapDef_MP5RAS' + )}), + (WeaponClasses={( + class'KFGame.KFWeapDef_Nailgun', + class'KFGame.KFWeapDef_Katana', + class'KFGame.KFWeapDef_ChainBat', + class'KFGame.KFWeapDef_FireAxe', + class'KFGame.KFWeapDef_Bullpup', + class'KFGame.KFWeapDef_Thompson', + class'KFGame.KFWeapDef_DoubleBarrel', + class'KFGame.KFWeapDef_HZ12', + class'KFGame.KFWeapDef_DragonsBreath', + class'KFGame.KFWeapDef_MedicSMG', + class'KFGame.KFWeapDef_Healthrower_HRG', + class'KFGame.KFWeapDef_M79', + class'KFGame.KFWeapDef_FlareGunDual', + class'KFGame.KFWeapDef_Mac10', + class'KFGame.KFWeapDef_HRGScorcher', + class'KFGame.KFWeapDef_Colt1911Dual', + class'KFGame.KFWeapDef_HRGWinterbite', + class'KFGame.KFWeapDef_CenterfireMB464', + class'KFGame.KFWeapDef_Crossbow', + class'KFGame.KFWeapDef_MP5RAS' + )}), + (WeaponClasses={( + class'KFGame.KFWeapDef_MedicBat', + class'KFGame.KFWeapDef_Pulverizer', + class'KFGame.KFWeapDef_Rifle_FrostShotgunAxe', + class'KFGame.KFWeapDef_AK12', + class'KFGame.KFWeapDef_MKB42', + class'KFGame.KFWeapDef_M16M203', + class'KFGame.KFWeapDef_M4', + class'KFGame.KFWeapDef_SW500Dual_HRG', + class'KFGame.KFWeapDef_MedicShotgun', + class'KFGame.KFWeapDef_Hemogoblin', + class'KFGame.KFWeapDef_Mine_Reconstructor', + class'KFGame.KFWeapDef_SealSqueal', + class'KFGame.KFWeapDef_FlameThrower', + class'KFGame.KFWeapDef_HRGIncendiaryRifle', + class'KFGame.KFWeapDef_ChiappaRhinoDual', + class'KFGame.KFWeapDef_DeagleDual', + class'KFGame.KFWeapDef_M14EBR', + class'KFGame.KFWeapDef_HRG_SonicGun', + class'KFGame.KFWeapDef_MosinNagant', + class'KFGame.KFWeapDef_P90', + class'KFGame.KFWeapDef_Nailgun_HRG', + class'KFGame.KFWeapDef_HK_UMP', + class'KFGame.KFWeapDef_FreezeThrower', + class'KFGame.KFWeapDef_HRG_Kaboomstick', + class'KFGame.KFWeapDef_FAMAS' + )}), + (WeaponClasses={( + class'KFGame.KFWeapDef_MedicBat', + class'KFGame.KFWeapDef_Rifle_FrostShotgunAxe', + class'KFGame.KFWeapDef_M16M203', + class'KFGame.KFWeapDef_M4', + class'KFGame.KFWeapDef_MedicShotgun', + class'KFGame.KFWeapDef_FlameThrower', + class'KFGame.KFWeapDef_HRGIncendiaryRifle', + class'KFGame.KFWeapDef_DeagleDual', + class'KFGame.KFWeapDef_HRG_SonicGun', + class'KFGame.KFWeapDef_MosinNagant', + class'KFGame.KFWeapDef_HK_UMP', + class'KFGame.KFWeapDef_FreezeThrower', + class'KFGame.KFWeapDef_HRG_Kaboomstick', + class'KFGame.KFWeapDef_FAMAS', + class'KFGame.KFWeapDef_Eviscerator', + class'KFGame.KFWeapDef_FNFal', + class'KFGame.KFWeapDef_MedicRifle', + class'KFGame.KFWeapDef_ElephantGun', + class'KFGame.KFWeapDef_Seeker6', + class'KFGame.KFWeapDef_HuskCannon', + class'KFGame.KFWeapDef_SW500Dual', + class'KFGame.KFWeapDef_Kriss', + class'KFGame.KFWeapDef_HRG_EMP_ArcGenerator' + )}), + (WeaponClasses={( + class'KFGame.KFWeapDef_HRGTeslauncher', + class'KFGame.KFWeapDef_Eviscerator', + class'KFGame.KFWeapDef_MaceAndShield', + class'KFGame.KFWeapDef_PowerGloves', + class'KFGame.KFWeapDef_SCAR', + class'KFGame.KFWeapDef_Stoner63A', + class'KFGame.KFWeapDef_MedicRifle', + class'KFGame.KFWeapDef_FNFal', + class'KFGame.KFWeapDef_AA12', + class'KFGame.KFWeapDef_ElephantGun', + class'KFGame.KFWeapDef_Blunderbuss', + class'KFGame.KFWeapDef_HRGIncision', + class'KFGame.KFWeapDef_HRG_Vampire', + class'KFGame.KFWeapDef_RPG7', + class'KFGame.KFWeapDef_Seeker6', + class'KFGame.KFWeapDef_HuskCannon', + class'KFGame.KFWeapDef_MicrowaveGun', + class'KFGame.KFWeapDef_SW500Dual', + class'KFGame.KFWeapDef_AF2011Dual', + class'KFGame.KFWeapDef_Pistol_DualG18', + class'KFGame.KFWeapDef_RailGun', + class'KFGame.KFWeapDef_G18', + class'KFGame.KFWeapDef_Kriss', + class'KFGame.KFWeapDef_HRG_EMP_ArcGenerator', + class'KFGame.KFWeapDef_AbominationAxe', + class'KFGame.KFWeapDef_Minigun', + class'KFGame.KFWeapDef_MedicRifleGrenadeLauncher', + class'KFGame.KFWeapDef_MicrowaveRifle', + class'KFGame.KFWeapDef_CompoundBow', + class'KFGame.KFWeapDef_M99', + class'KFGame.KFWeapDef_LazerCutter', + class'KFGame.KFWeapDef_HRG_BlastBrawlers', + class'KFGame.KFWeapDef_ThermiteBore', + class'KFGame.KFWeapDef_HRG_BarrierRifle' + )}), + (WeaponClasses={( + class'KFGame.KFWeapDef_HRGTeslauncher', + class'KFGame.KFWeapDef_Eviscerator', + class'KFGame.KFWeapDef_MaceAndShield', + class'KFGame.KFWeapDef_PowerGloves', + class'KFGame.KFWeapDef_SCAR', + class'KFGame.KFWeapDef_Stoner63A', + class'KFGame.KFWeapDef_MedicRifle', + class'KFGame.KFWeapDef_FNFal', + class'KFGame.KFWeapDef_AA12', + class'KFGame.KFWeapDef_ElephantGun', + class'KFGame.KFWeapDef_Blunderbuss', + class'KFGame.KFWeapDef_HRGIncision', + class'KFGame.KFWeapDef_HRG_Vampire', + class'KFGame.KFWeapDef_RPG7', + class'KFGame.KFWeapDef_Seeker6', + class'KFGame.KFWeapDef_HuskCannon', + class'KFGame.KFWeapDef_MicrowaveGun', + class'KFGame.KFWeapDef_SW500Dual', + class'KFGame.KFWeapDef_AF2011Dual', + class'KFGame.KFWeapDef_Pistol_DualG18', + class'KFGame.KFWeapDef_RailGun', + class'KFGame.KFWeapDef_G18', + class'KFGame.KFWeapDef_Kriss', + class'KFGame.KFWeapDef_HRG_EMP_ArcGenerator', + class'KFGame.KFWeapDef_AbominationAxe', + class'KFGame.KFWeapDef_Minigun', + class'KFGame.KFWeapDef_MedicRifleGrenadeLauncher', + class'KFGame.KFWeapDef_MicrowaveRifle', + class'KFGame.KFWeapDef_CompoundBow', + class'KFGame.KFWeapDef_M99', + class'KFGame.KFWeapDef_LazerCutter', + class'KFGame.KFWeapDef_HRG_BlastBrawlers', + class'KFGame.KFWeapDef_ThermiteBore', + class'KFGame.KFWeapDef_HRG_BarrierRifle' + )}), + (WeaponClasses={( + class'KFGame.KFWeapDef_HRGTeslauncher', + class'KFGame.KFWeapDef_Eviscerator', + class'KFGame.KFWeapDef_MaceAndShield', + class'KFGame.KFWeapDef_PowerGloves', + class'KFGame.KFWeapDef_SCAR', + class'KFGame.KFWeapDef_Stoner63A', + class'KFGame.KFWeapDef_MedicRifle', + class'KFGame.KFWeapDef_FNFal', + class'KFGame.KFWeapDef_AA12', + class'KFGame.KFWeapDef_ElephantGun', + class'KFGame.KFWeapDef_Blunderbuss', + class'KFGame.KFWeapDef_HRGIncision', + class'KFGame.KFWeapDef_HRG_Vampire', + class'KFGame.KFWeapDef_RPG7', + class'KFGame.KFWeapDef_Seeker6', + class'KFGame.KFWeapDef_HuskCannon', + class'KFGame.KFWeapDef_MicrowaveGun', + class'KFGame.KFWeapDef_SW500Dual', + class'KFGame.KFWeapDef_AF2011Dual', + class'KFGame.KFWeapDef_Pistol_DualG18', + class'KFGame.KFWeapDef_RailGun', + class'KFGame.KFWeapDef_G18', + class'KFGame.KFWeapDef_Kriss', + class'KFGame.KFWeapDef_HRG_EMP_ArcGenerator', + class'KFGame.KFWeapDef_AbominationAxe', + class'KFGame.KFWeapDef_Minigun', + class'KFGame.KFWeapDef_MedicRifleGrenadeLauncher', + class'KFGame.KFWeapDef_MicrowaveRifle', + class'KFGame.KFWeapDef_CompoundBow', + class'KFGame.KFWeapDef_M99', + class'KFGame.KFWeapDef_LazerCutter', + class'KFGame.KFWeapDef_HRG_BlastBrawlers', + class'KFGame.KFWeapDef_ThermiteBore', + class'KFGame.KFWeapDef_HRG_BarrierRifle' + )}) + )} +} diff --git a/KFGameContent/Classes/KFMeleeHelperWeaponBlastBrawlers.uc b/KFGameContent/Classes/KFMeleeHelperWeaponBlastBrawlers.uc new file mode 100644 index 0000000..c97cebb --- /dev/null +++ b/KFGameContent/Classes/KFMeleeHelperWeaponBlastBrawlers.uc @@ -0,0 +1,34 @@ +//============================================================================= +// KFMeleeHelperWeaponBlastBrawlers +//============================================================================= +// Manages melee attack related functionality for 1st person weapons +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= +class KFMeleeHelperWeaponBlastBrawlers extends KFMeleeHelperWeapon + config(Game); + +event InitWorldTraceForHitboxCollision() +{ + local KFWeap_HRG_BlastBrawlers BlastBrawlers; + + BlastBrawlers = KFWeap_HRG_BlastBrawlers(Instigator.Weapon); + if (BlastBrawlers != none) + { + BlastBrawlers.Shoot(); + } + + super.InitWorldTraceForHitboxCollision(); +} + +simulated function InitAttackSequence(EPawnOctant NewAtkDir, EMeleeAttackType NewAtkType) +{ + super.InitAttackSequence(NewAtkDir, NewAtkType); + NextAttackType = NewAtkType; +} + +defaultproperties +{ + +} diff --git a/KFGameContent/Classes/KFOutbreakEvent_Weekly.uc b/KFGameContent/Classes/KFOutbreakEvent_Weekly.uc index be0e0fb..bb2c402 100644 --- a/KFGameContent/Classes/KFOutbreakEvent_Weekly.uc +++ b/KFGameContent/Classes/KFOutbreakEvent_Weekly.uc @@ -407,6 +407,115 @@ defaultproperties )} + // Aracnophobia + SetEvents[10]={( + EventDifficulty=2, //1, + GameLength=GL_Normal, + SpawnRateMultiplier=0.75, //5.0, + bHealAfterKill = true, + bGoompaJumpEnabled = true, + GoompaJumpDamage = 550, //300, + GoompaStreakDamage = 0.1, //0.2, + GoompaJumpImpulse = 600, //1000, + GoompaStreakMax = 5, + GoompaBonusDuration=8.0f, //10.0f, + DoshOnKillGlobalModifier=1.0, + SpawnWeaponList=KFGFxObject_TraderItems'GP_Trader_ARCH.AracnophobiaWeeklySpawnList', + bAddSpawnListToLoadout=true, + WaveAICountScale=(0.6, 0.6, 0.6, 0.6, 0.6, 0.6), + JumpZ=700.f, // 650.0 by default; -1 used for not overriding. + /** HealByKill = Normal kill. HealByAssistance = Goomba stomping */ + ZedsToAdjust={( + (ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawler',HealthScale=10.0, HeadHealthScale=20.0, DamageDealtScale=0.7, InitialGroundSpeedModifierScale=0.7, HealByAssistance=10), + (ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawlerKing',HealthScale=10.0,HeadHealthScale=20.0, DamageDealtScale=0.7, InitialGroundSpeedModifierScale=0.7, HealByAssistance=20) + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Cyst',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Alpha',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_AlphaKing',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Slasher',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedSiren',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedStalker',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefast',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefastDualBlade',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloat',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedHusk',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_EMP',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Laser',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Rocket',HealByAssistance=5), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedScrake',HealByAssistance=15), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpound',HealByAssistance=15), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundMini',HealByAssistance=15), + //(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKingSubspawn',HealByAssistance=5) + )}, + SpawnReplacementList={( + (SpawnEntry=AT_Clot,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_AlphaClot,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_SlasherClot,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_Stalker,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_Bloat,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_Siren,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_Husk,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_GoreFast,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + //(SpawnEntry=AT_Scrake,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.7), + //(SpawnEntry=AT_FleshPound,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.7), + //(SpawnEntry=AT_FleshpoundMini,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.7), + (SpawnEntry=AT_EliteClot,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_EliteGoreFast,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_EDAR_EMP,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_EDAR_Laser,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_EDAR_Rocket,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=0.6), + (SpawnEntry=AT_Crawler,NewClass=(class'KFGameContent.KFPawn_ZedCrawler'),PercentChance=1.0) + )} + )} + + // Broken Trader + SetEvents[11]={( + EventDifficulty=1, + GameLength=GL_Normal, + bSpawnWeaponListAffectsSecondaryWeapons=true, + TraderWeaponList=KFGFxObject_TraderItems'GP_Trader_ARCH.BrokenTraderWeeklyTraderList', + PickupResetTime=PRS_Wave, + bDisableTraders=false, + DroppedItemLifespan=10.0f, // 300 default + DoshOnKillGlobalModifier=0.2, + //Pickup Notes for when you're modifying: + // NumPickups = Actors * OverridePickupModifer * WavePickupModifier + // Ex: 16 item pickups in the world + // * 0.9 Pickup Modifier = 14 + // * 0.5 Current wave modifier = 7 expected to spawn + // + // Ex: 16 ammo pickups in the world + // * 0.1 pickup modifier = 2 + // * 0.5 current wave modifier = 1 expected to spawn + bUnlimitedWeaponPickups=true, + OverrideItemPickupModifier=2.0, + OverrideAmmoPickupModifier=0.8, //0.5, + WaveItemPickupModifiers={( + 1.0, 1.0, 1.0, 1.0, 1.0 + )}, + WaveAmmoPickupModifiers={( + 0.5, 0.6, 0.7, 0.8, 0.9 + )}, + bUseOverrideAmmoRespawnTime=true, + OverrideAmmoRespawnTime={( + PlayersMod[0]=20.000000, + PlayersMod[1]=20.000000, + PlayersMod[2]=10.000000, + PlayersMod[3]=10.000000, + PlayersMod[4]=5.000000, + PlayersMod[5]=5.000000, + ModCap=1.000000 + )}, + bUseOverrideItemRespawnTime=true, + OverrideItemRespawnTime={( + PlayersMod[0]=10.000000, + PlayersMod[1]=10.000000, + PlayersMod[2]=5.000000, + PlayersMod[3]=5.000000, + PlayersMod[4]=2.000000, + PlayersMod[5]=2.000000, + ModCap=1.000000 + )} + )} //Test events from here down. These don't end up in the regular rotation. diff --git a/KFGameContent/Classes/KFPawn_ZedCrawlerKing.uc b/KFGameContent/Classes/KFPawn_ZedCrawlerKing.uc index 0671b30..5a19962 100644 --- a/KFGameContent/Classes/KFPawn_ZedCrawlerKing.uc +++ b/KFGameContent/Classes/KFPawn_ZedCrawlerKing.uc @@ -36,7 +36,13 @@ simulated function PlayHeadAsplode() /** Set our gib flag on the server, replicate it with bTearOff */ function bool Died(Controller Killer, class DamageType, vector HitLocation) { - if( !bPlayedDeath && DamageType != class'KFSM_PlayerCrawler_Suicide'.default.SuicideDamageType ) + local KFGameInfo_WeeklySurvival KFGI_WS; + + // Not exploding if we are in arachnophobia weekly. + KFGI_WS = KFGameInfo_WeeklySurvival(WorldInfo.Game); + + if( !bPlayedDeath && DamageType != class'KFSM_PlayerCrawler_Suicide'.default.SuicideDamageType && + (KFGI_WS == none|| !KFGI_WS.OutbreakEvent.ActiveEvent.bGoompaJumpEnabled)) { bShouldExplode = true; } diff --git a/KFGameContent/Classes/KFPawn_ZedFleshpoundKing.uc b/KFGameContent/Classes/KFPawn_ZedFleshpoundKing.uc index 50bb9f4..b5ba917 100644 --- a/KFGameContent/Classes/KFPawn_ZedFleshpoundKing.uc +++ b/KFGameContent/Classes/KFPawn_ZedFleshpoundKing.uc @@ -440,7 +440,7 @@ function AdjustDamage(out int InDamage, out vector Momentum, Controller Instigat } } -function HandleAfflictionsOnHit(Controller DamageInstigator, vector HitDir, class DamageType, Actor DamageCauser) +function HandleAfflictionsOnHit(Controller DamageInstigator, vector HitDir, class DamageType, Actor DamageCauser) { if (ShieldHealthPctByte == 0) { diff --git a/KFGameContent/Classes/KFPhysicsDamageByPawnVolume.uc b/KFGameContent/Classes/KFPhysicsDamageByPawnVolume.uc new file mode 100644 index 0000000..0c4b2d6 --- /dev/null +++ b/KFGameContent/Classes/KFPhysicsDamageByPawnVolume.uc @@ -0,0 +1,51 @@ +//============================================================================= +// KFPhysicsDamageByPawnVolume +//============================================================================= +// PhysicsVolume are, by default, used for traps on all maps. This KFPhysicsDamageByPawnVolume +// gives the ability to make different damage values for Humans and Monsters. +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +// Roberto Moreno +//============================================================================= +class KFPhysicsDamageByPawnVolume extends PhysicsVolume + placeable; + +var() float DamagePerSecMultiplierForHuman; +var() float DamagePerSecMultiplierForMonster; + +function CausePainTo(Actor Other) +{ + local float DamagePerSecModified; + + DamagePerSecModified = DamagePerSec; + + if (KFPawn_Human(Other) != None) + { + DamagePerSecModified *= DamagePerSecMultiplierForHuman; + } + else if (KFPawn_Monster(Other) != None) + { + DamagePerSecModified *= DamagePerSecMultiplierForMonster; + } + + if (DamagePerSecModified > 0) + { + if ( WorldInfo.bSoftKillZ && (Other.Physics != PHYS_Walking) ) + return; + if ( (DamageType == None) || (DamageType == class'DamageType') ) + `log("No valid damagetype ("$DamageType$") specified for "$PathName(self)); + Other.TakeDamage(DamagePerSecModified*PainInterval, DamageInstigator, Location, vect(0,0,1), DamageType,, self); + } + else + { + Other.HealDamage(-DamagePerSecModified * PainInterval, DamageInstigator, DamageType); + } +} + + +DefaultProperties +{ + DamagePerSecMultiplierForHuman=1.0 + DamagePerSecMultiplierForMonster=1.0 +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFProj_Bolt_CompoundBowCryo.uc b/KFGameContent/Classes/KFProj_Bolt_CompoundBowCryo.uc index bdae540..f524501 100644 --- a/KFGameContent/Classes/KFProj_Bolt_CompoundBowCryo.uc +++ b/KFGameContent/Classes/KFProj_Bolt_CompoundBowCryo.uc @@ -234,9 +234,9 @@ defaultproperties // Ice explosion Begin Object Class=KFGameExplosion Name=ExploTemplate0 - Damage=25 - DamageRadius=200 - DamageFalloffExponent=1.f + Damage=75 //25 + DamageRadius=250 //200 + DamageFalloffExponent=0.5f //1.f DamageDelay=0.f bIgnoreInstigator=false diff --git a/KFGameContent/Classes/KFProj_Bullet_BlastBrawlers.uc b/KFGameContent/Classes/KFProj_Bullet_BlastBrawlers.uc new file mode 100644 index 0000000..27e69d2 --- /dev/null +++ b/KFGameContent/Classes/KFProj_Bullet_BlastBrawlers.uc @@ -0,0 +1,29 @@ +//============================================================================= +// KFProj_Bullet_BlastBrawlers +//============================================================================= +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFProj_Bullet_BlastBrawlers extends KFProj_Bullet_Pellet + hidedropdown; + +defaultproperties +{ + MaxSpeed=7000.0 + Speed=7000.0 + + bWarnAIWhenFired=true + + DamageRadius=0 + + ImpactEffects = KFImpactEffectInfo'WEP_HRG_BlastBrawlers_ARCH.HRG_BlastBrawler_Projectile_Impacts' + ProjFlightTemplate=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Tracer_Instant' + ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Tracer_Instant' + //ProjFlightTemplate=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Projectile' + //ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Projectile' + + AmbientSoundPlayEvent=none + AmbientSoundStopEvent=none +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFProj_Grenade_GravityImploder.uc b/KFGameContent/Classes/KFProj_Grenade_GravityImploder.uc index b533198..eba2c15 100644 --- a/KFGameContent/Classes/KFProj_Grenade_GravityImploder.uc +++ b/KFGameContent/Classes/KFProj_Grenade_GravityImploder.uc @@ -11,13 +11,10 @@ class KFProj_Grenade_GravityImploder extends KFProj_BallisticExplosive /* Ensure it detonates */ var float DetonationTime; var float VortexDuration; - var float VortexRadius; var float VortexImpulseStrength; var protected transient bool bVortexActive; -var protected RB_RadialImpulseComponent RadialImpulseComponent; - simulated state GrenadeState { simulated event BeginState(Name PrevStateName) @@ -49,18 +46,25 @@ simulated state VortexState simulated event Tick(float DeltaTime) { - local float ImpulseModifier; + local Actor Victim; + local TraceHitInfo HitInfo; + local FracturedStaticMeshActor FracActor; if(bVortexActive && (WorldInfo.NetMode == NM_Client || WorldInfo.NetMode == NM_Standalone)) { - // ImpulseModifier = (bReduceGibImpulseOnTick) ? (1.0f - AccumulatedTime / Lifetime) : 1.0f; - ImpulseModifier = 1.0f; - - RadialImpulseComponent.ImpulseRadius = VortexRadius; - RadialImpulseComponent.ImpulseStrength = VortexImpulseStrength * ImpulseModifier; - RadialImpulseComponent.bVelChange = true; - RadialImpulseComponent.ImpulseFalloff = RIF_Constant; - RadialImpulseComponent.FireImpulse(Location); + foreach CollidingActors(class'Actor', Victim, VortexRadius, Location, true,, HitInfo) + { + if (KFPawn_Human(Victim) == none && Victim.CollisionComponent != none && !Victim.bWorldGeometry) + { + Victim.CollisionComponent.AddRadialImpulse(Location, VortexRadius, VortexImpulseStrength, RIF_Constant, true); + } + + FracActor = FracturedStaticMeshActor(Victim); + if (FracActor != none) + { + FracActor.BreakOffPartsInRadius(Location, VortexRadius, VortexImpulseStrength, true); + } + } } } } @@ -123,9 +127,9 @@ defaultproperties ProjFlightTemplate=ParticleSystem'WEP_Gravity_Imploder_EMIT.FX_Yellow_Projectile' ProjFlightTemplateZedTime=ParticleSystem'WEP_Gravity_Imploder_EMIT.FX_Yellow_Projectile_ZEDTIME' - GrenadeBounceEffectInfo=KFImpactEffectInfo'FX_Impacts_ARCH.DefaultGrenadeImpacts' + //GrenadeBounceEffectInfo=KFImpactEffectInfo'FX_Impacts_ARCH.DefaultGrenadeImpacts' ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01' - AltExploEffects=KFImpactEffectInfo'WEP_Gravity_Imploder_ARCH.Yellow_Explosion_Concussive_Force' + //AltExploEffects=KFImpactEffectInfo'WEP_Gravity_Imploder_ARCH.Yellow_Explosion_Concussive_Force' // Grenade explosion light Begin Object Class=PointLightComponent Name=ExplosionPointLight @@ -179,10 +183,4 @@ defaultproperties VortexImpulseStrength=-100 VortexDuration=0.5f bVortexActive=false - - Begin Object Class=RB_RadialImpulseComponent Name=ImpulseComponent0 - End Object - RadialImpulseComponent=ImpulseComponent0 - Components.Add(ImpulseComponent0) } - diff --git a/KFGameContent/Classes/KFProj_Rocket_ThermiteBore.uc b/KFGameContent/Classes/KFProj_Rocket_ThermiteBore.uc new file mode 100644 index 0000000..612ba29 --- /dev/null +++ b/KFGameContent/Classes/KFProj_Rocket_ThermiteBore.uc @@ -0,0 +1,368 @@ +//============================================================================= +// KFProj_Rocket_ThermiteBore +//============================================================================= +// Thermite Bore Rifle rocket launcher harpoon +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2012 Tripwire Interactive LLC +//============================================================================= +class KFProj_Rocket_ThermiteBore extends KFProjectile; + +var float FuseTime; + +/** This is the effect indicator that is played for the current user **/ +var(Projectile) ParticleSystem ProjIndicatorTemplate; +var ParticleSystemComponent ProjIndicatorEffects; + +var bool IndicatorActive; + +/** + Fire effects + */ + +var class ResidualFlameProjClass; + +var int NumResidualFlames; + +/** Cone Angle to determine residual flame directions */ +var float ResidualFlameHalfConeAngle; +/** Impulse modiffier apply to residual forces*/ +var float ResidualFlameForceMultiplier; + +simulated function TryActivateIndicator() +{ + if(!IndicatorActive && Instigator != None) + { + IndicatorActive = true; + + if(WorldInfo.NetMode == NM_Standalone || Instigator.Role == Role_AutonomousProxy || + (Instigator.Role == ROLE_Authority && WorldInfo.NetMode == NM_ListenServer && Instigator.IsLocallyControlled() )) + { + if( ProjIndicatorTemplate != None ) + { + ProjIndicatorEffects = WorldInfo.MyEmitterPool.SpawnEmitterCustomLifetime(ProjIndicatorTemplate); + } + + if(ProjIndicatorEffects != None) + { + ProjIndicatorEffects.SetAbsolute(false, false, false); + ProjIndicatorEffects.SetLODLevel(WorldInfo.bDropDetail ? 1 : 0); + ProjIndicatorEffects.bUpdateComponentInTick = true; + AttachComponent(ProjIndicatorEffects); + } + } + } +} + +/** + * Set the initial velocity and cook time + */ +simulated event PostBeginPlay() +{ + Super.PostBeginPlay(); + + if (Role == ROLE_Authority) + { + SetTimer(FuseTime, false, 'Timer_Detonate'); + } + + AdjustCanDisintigrate(); +} + +/** + * Explode after a certain amount of time + */ +function Timer_Detonate() +{ + Detonate(); +} + +/** Called when the owning instigator controller has left a game */ +simulated function OnInstigatorControllerLeft() +{ + if( WorldInfo.NetMode != NM_Client ) + { + SetTimer( 1.f + Rand(5) + fRand(), false, nameOf(Timer_Detonate) ); + } +} + +/** + * Trace down and get the location to spawn the explosion effects and decal + */ +simulated function GetExplodeEffectLocation(out vector HitLocation, out vector HitRotation, out Actor HitActor) +{ + local vector EffectStartTrace, EffectEndTrace; + local TraceHitInfo HitInfo; + + EffectStartTrace = Location + vect(0,0,1) * 4.f; + EffectEndTrace = EffectStartTrace - vect(0,0,1) * 32.f; + + // Find where to put the decal + HitActor = Trace(HitLocation, HitRotation, EffectEndTrace, EffectStartTrace, false,, HitInfo, TRACEFLAG_Bullet); + + // If the locations are zero (probably because this exploded in the air) set defaults + if (IsZero(HitLocation)) + { + HitLocation = Location; + } + + if (IsZero(HitRotation)) + { + HitRotation = vect(0,0,1); + } +} + +/** Used to check current status of StuckTo actor (to figure out if we should fall) */ +simulated event Tick(float DeltaTime) +{ + super.Tick(DeltaTime); + + StickHelper.Tick(DeltaTime); + + if (!IsZero(Velocity)) + { + SetRelativeRotation(rotator(Velocity)); + } + + TryActivateIndicator(); +} + +/** Causes charge to explode */ +function Detonate() +{ + local KFWeap_RocketLauncher_ThermiteBore WeaponOwner; + local vector ExplosionNormal; + + if (Role == ROLE_Authority) + { + WeaponOwner = KFWeap_RocketLauncher_ThermiteBore(Owner); + if (WeaponOwner != none) + { + WeaponOwner.RemoveDeployedHarpoon(, self); + } + } + + ExplosionNormal = vect(0,0,1) >> Rotation; + Explode(Location, ExplosionNormal); +} + +simulated function Explode(vector HitLocation, vector HitNormal) +{ + local vector HitVelocity; + + HitVelocity = Velocity; + + StickHelper.UnPin(); + super.Explode(HitLocation, HitNormal); + + // Spawn fire projectiles + if(Role < Role_Authority) + { + return; + } + + SpawnResidualFlames(HitLocation, HitNormal, HitVelocity); + SpawnResidualFlame(ResidualFlameProjClass, Location, HitVelocity); +} + +simulated function Disintegrate( rotator InDisintegrateEffectRotation ) +{ + local KFWeap_RocketLauncher_ThermiteBore WeaponOwner; + + if (Role == ROLE_Authority) + { + WeaponOwner = KFWeap_RocketLauncher_ThermiteBore(Owner); + if (WeaponOwner != none) + { + WeaponOwner.RemoveDeployedHarpoon(, self); + } + } + + super.Disintegrate(InDisintegrateEffectRotation); +} + +// for nukes && concussive force +simulated protected function PrepareExplosionTemplate() +{ + class'KFPerk_Demolitionist'.static.PrepareExplosive(Instigator, self); + + super.PrepareExplosionTemplate(); +} + +simulated function SyncOriginalLocation() +{ + // IMPORTANT NOTE: We aren't actually syncing to the original location (or calling the super). + // We just want to receive the original location so we can do a trace between that location and + // our current location to determine if we hit any zeds between those two locations. + // KFII-45464 + + local Actor HitActor; + local vector HitLocation, HitNormal; + local TraceHitInfo HitInfo; + + if (Role < ROLE_Authority && Instigator != none && Instigator.IsLocallyControlled()) + { + HitActor = Trace(HitLocation, HitNormal, OriginalLocation, Location,,, HitInfo, TRACEFLAG_Bullet); + if (HitActor != none) + { + StickHelper.TryStick(HitNormal, HitLocation, HitActor); + } + } +} + +simulated protected function StopSimulating() +{ + super.StopSimulating(); + + if (ProjIndicatorEffects!=None) + { + ProjIndicatorEffects.DeactivateSystem(); + } +} + +/** Spawn several projectiles that explode and linger on impact */ +function SpawnResidualFlames( vector HitLocation, vector HitNormal, vector HitVelocity ) +{ + local int i; + local vector HitVelDir; + local float HitVelMag; + local vector SpawnLoc, SpawnVel; + + HitVelMag = VSize( HitVelocity ); + HitVelDir = Normal( HitVelocity ); + + SpawnLoc = HitLocation + (HitNormal * 10.f); + + // spawn random lingering fires (rather, projectiles that cause little fires) + for( i = 0; i < NumResidualFlames; ++i ) + { + + SpawnVel = CalculateResidualFlameVelocity( HitNormal, HitVelDir, HitVelMag ); + SpawnResidualFlame( ResidualFlameProjClass, SpawnLoc, SpawnVel ); + } +} + +function vector CalculateResidualFlameVelocity( vector HitNormal, vector HitVelDir, float HitVelMag ) +{ + local vector SpawnDir; + + // apply some spread + SpawnDir = VRandCone( HitNormal, ResidualFlameHalfConeAngle * DegToRad ); +/* + // make HitVelDir parallel to contact surface by subtracting component parallel to HitNormal + SpawnDir = SpawnDir + (-(SpawnDir dot HitNormal) * HitNormal); + + // apply some more spread to get some of the flames to stick to the wall and others the ground beneath the wall + // (makes it looks kind of smeared down the wall, like a real molotov) + SpawnDir = VRandCone( SpawnDir, PI/4 ); +*/ + return SpawnDir * ResidualFlameForceMultiplier; +} + +defaultproperties +{ + ProjFlightTemplate=ParticleSystem'WEP_Thermite_EMIT.FX_Harpoon_Projectile' + ProjIndicatorTemplate=ParticleSystem'WEP_Thermite_EMIT.FX_Harpoon_Projectile_Indicator' + + bWarnAIWhenFired=true + + MaxSpeed=5000.0 //4000.0 + Speed=5000.0 //4000.0 + TerminalVelocity=5000 //4000 + + Physics=PHYS_Falling + + TossZ=0 //150 + GravityScale=0.36 //0.5//0.7 + + GlassShatterType=FMGS_ShatterAll + + bCollideComplex=true + + bIgnoreFoliageTouch=true + + bBlockedByInstigator=false + bAlwaysReplicateExplosion=true + + FuseTime=4.0 + + bNetTemporary=false + NetPriority=5 + NetUpdateFrequency=200 + + bNoReplicationToInstigator=false + bUseClientSideHitDetection=true + bUpdateSimulatedPosition=true + bSyncToOriginalLocation=true + bSyncToThirdPersonMuzzleLocation=true + + PinBoneIdx=INDEX_None + + bCanBeDamaged=true + bCanDisintegrate=true + Begin Object Name=CollisionCylinder + BlockNonZeroExtent=false + // for siren scream + CollideActors=true + End Object + + // explosion light + Begin Object Class=PointLightComponent Name=ExplosionPointLight + LightColor=(R=252,G=218,B=171,A=255) + Brightness=4.f + Radius=2000.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 // @todo: change me + Damage=150 //250 + DamageRadius=500 //600 + DamageFalloffExponent=1.f + DamageDelay=0.f + + // Damage Effects + MyDamageType=class'KFDT_Explosive_Thermite' + KnockDownStrength=0 + FractureMeshRadius=200.0 + FracturePartVel=500.0 + ExplosionEffects=KFImpactEffectInfo'WEP_Thermite_ARCH.ThermiteHarpoon_Explosion' + ExplosionSound=AkEvent'WW_WEP_SealSqueal.Play_WEP_SealSqueal_Shoot_Explode' + + // Dynamic Light + ExploLight=ExplosionPointLight + ExploLightStartFadeOutTime=0.0 + ExploLightFadeOutTime=0.2 + + // Camera Shake + CamShake=CameraShake'FX_CameraShake_Arch.Misc_Explosions.Light_Explosion_Rumble' + CamShakeInnerRadius=200 + CamShakeOuterRadius=900 + CamShakeFalloff=1.5f + bOrientCameraShakeTowardsEpicenter=true + End Object + ExplosionTemplate=ExploTemplate0 + + ExplosionActorClass=class'KFExplosionActor' + + bCanStick=true + bCanPin=true + Begin Object Class=KFProjectileStickHelper Name=StickHelper0 + End Object + StickHelper=StickHelper0 + + ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01' + + ResidualFlameProjClass=class'KFProj_ThermiteSplash' + NumResidualFlames=4 //it always spawn 1 more than this parameter, so 5 + + ResidualFlameHalfConeAngle=72 + ResidualFlameForceMultiplier=700f; //1000f; + +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFProj_ThermiteSplash.uc b/KFGameContent/Classes/KFProj_ThermiteSplash.uc new file mode 100644 index 0000000..a3593f9 --- /dev/null +++ b/KFGameContent/Classes/KFProj_ThermiteSplash.uc @@ -0,0 +1,110 @@ +//============================================================================= +// KFProj_ThermiteSplash +//============================================================================= +// Projectile class for the thermite rocket launchers +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFProj_ThermiteSplash extends KFProj_MolotovSplash; + +/* +simulated function Tick(float Delta) +{ + super.Tick(Delta); + + if (WorldInfo.NetMode != NM_Client && WorldInfo.NetMode != NM_Standalone) + { + return; + } + + // Rotate towards velocity: + if (VSizeSq(Velocity) > 0) + { + SetRotation(rotator(Normal(Velocity))); + } +} +*/ +defaultproperties +{ + Physics=PHYS_Falling + + bCollideComplex=TRUE // Ignore simple collision on StaticMeshes, and collide per poly + + // network + bNetTemporary=False + bAlwaysReplicateExplosion=true + AlwaysRelevantDistanceSquared=6250000 // 25m + + // gameplay + bBlockedByInstigator=false + GlassShatterType=FMGS_ShatterNone + + // audio + bStopAmbientSoundOnExplode=false + bAutoStartAmbientSound=true + bAmbientSoundZedTimeOnly=false + + AmbientSoundPlayEvent=AkEvent'WW_WEP_SA_Flamethrower.Play_WEP_SA_Flamethrower_Residual_Fire_Loop' + AmbientSoundStopEvent=AkEvent'WW_WEP_SA_Flamethrower.Stop_WEP_SA_Flamethrower_Residual_Fire_Loop' + + Begin Object name=AmbientAkSoundComponent + bStopWhenOwnerDestroyed=true + bForceOcclusionUpdateInterval=true + OcclusionUpdateInterval=0.25; + End Object + AmbientComponent=AmbientAkSoundComponent + Components.Add(AmbientAkSoundComponent) + + // light + Begin Object Name=FlamePointLight + LightColor=(R=245,G=190,B=140,A=255) + Brightness=2.f + Radius=300.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 Name=ExploTemplate0 + Damage=10 + DamageRadius=150 + DamageFalloffExponent=1.f + DamageDelay=0.f + // Don't burn the guy that tossed it, it's just too much damage with multiple fires, its almost guaranteed to kill the guy that tossed it + bIgnoreInstigator=true + + MomentumTransferScale=1 + + // Damage Effects + MyDamageType=class'KFDT_Fire_Ground_ThermiteBore' + KnockDownStrength=0 + FractureMeshRadius=0 + ExplosionEffects=KFImpactEffectInfo'wep_thermite_arch.Thermite_GroundFire' + + bDirectionalExplosion=true + + // Camera Shake + CamShake=none + + // Dynamic Light + ExploLight=FlamePointLight + ExploLightStartFadeOutTime=4.2 + ExploLightFadeOutTime=0.3 + End Object + ExplosionTemplate=ExploTemplate0 + + ProjFlightTemplate=ParticleSystem'WEP_Thermite_EMIT.FX_Thermite_Spread_01' + ExplosionActorClass=class'KFExplosion_Thermite' + + AssociatedPerkClass=class'KFPerk_Firebug' + + // Ground Fire Perk Skill Alternative FX + AltExploEffects=KFImpactEffectInfo'WEP_Thermite_ARCH.GroundFire_Splash_Impacts' +} diff --git a/KFGameContent/Classes/KFSeasonalEventStats_Summer2021.uc b/KFGameContent/Classes/KFSeasonalEventStats_Summer2021.uc new file mode 100644 index 0000000..a4fea34 --- /dev/null +++ b/KFGameContent/Classes/KFSeasonalEventStats_Summer2021.uc @@ -0,0 +1,137 @@ +//============================================================================= +// KFSeasonalEventStats_Summer2021 +//============================================================================= +// Tracks event-specific challenges/accomplishments for Summer 2021 +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= +class KFSeasonalEventStats_Summer2021 extends KFSeasonalEventStats; + +var transient private const int ZedsStompRequired, LaserKillsRequired, JumpKillsRequired, EndlessWaveRequired; + +private event Initialize(string MapName) +{ + local string CapsMapName; + CapsMapName = Caps(MapName); + + bObjectiveIsValidForMap[0] = 1; // Stomp on 50 Zeds + bObjectiveIsValidForMap[1] = 0; // Complete the Weekly on Moonbase + bObjectiveIsValidForMap[2] = 0; // Use the laser trap to kill 20 Zeds on Moonbase + bObjectiveIsValidForMap[3] = 0; // Kill 300 Zeds while jumping in the air on Moonbase + bObjectiveIsValidForMap[4] = 0; // Complete wave 15 on Endless Hard or higher difficulty on Moonbase + + if (CapsMapName == "KF-MOONBASE") + { + bObjectiveIsValidForMap[1] = 1; + bObjectiveIsValidForMap[2] = 1; + bObjectiveIsValidForMap[3] = 1; + bObjectiveIsValidForMap[4] = 1; + } + + SetSeasonalEventStatsMax(ZedsStompRequired, 0, LaserKillsRequired, JumpKillsRequired, 0); +} + +private event GrantEventItems() +{ + if (Outer.IsEventObjectiveComplete(0) && + Outer.IsEventObjectiveComplete(1) && + Outer.IsEventObjectiveComplete(2) && + Outer.IsEventObjectiveComplete(3) && + Outer.IsEventObjectiveComplete(4)) + { + // @TODO: Set Proper Reward ID + // + GrantEventItem(8844); + } +} + +simulated event OnGameWon(class GameClass, int Difficulty, int GameLength, bool bCoOp) +{ + // Moonbase weekly + if (bObjectiveIsValidForMap[1] != 0) + { + if (GameClass == class'KFGameInfo_WeeklySurvival') + { + FinishedObjective(SEI_Summer, 1); + } + } +} + +simulated function OnZedKilled(class MonsterClass, int Difficulty, class DT) +{ + local int ObjIdx; + local KFPlayerController KFPC; + local KFPawn_Human KFP; + + // Laser Kills + ObjIdx = 2; + if (bObjectiveIsValidForMap[ObjIdx] != 0) + { + if (ClassIsChildOf(DT, class'KFDT_EMPTrap')) + { + IncrementSeasonalEventStat(ObjIdx, 1); + if (Outer.GetSeasonalEventStatValue(ObjIdx) >= LaserKillsRequired) + { + FinishedObjective(SEI_SUMMER, ObjIdx); + } + } + } + + ObjIdx = 3; + if (bObjectiveIsValidForMap[ObjIdx] != 0) + { + KFPC = Outer.MyKFPC; + if (KFPC != none) + { + KFP = KFPawn_Human(KFPC.Pawn); + if (KFP != none && KFP.Physics == PHYS_Falling) + { + IncrementSeasonalEventStat(ObjIdx, 1); + if (Outer.GetSeasonalEventStatValue(ObjIdx) >= JumpKillsRequired) + { + FinishedObjective(SEI_SUMMER, ObjIdx); + } + } + } + } +} + +simulated function OnHitGiven(class DT) +{ + local int ObjIdx; + ObjIdx = 0; + + // Stomps + if (ClassIsChildOf(DT, class'DmgType_Crushed')) + { + IncrementSeasonalEventStat(ObjIdx, 1); + if (Outer.GetSeasonalEventStatValue(ObjIdx) >= ZedsStompRequired) + { + FinishedObjective(SEI_SUMMER, ObjIdx); + } + } +} + +simulated event OnWaveCompleted(class GameClass, int Difficulty, int WaveNum) +{ + local int ObjIdx; + + // Waves in Endless hard + ObjIdx = 4; + if (bObjectiveIsValidForMap[ObjIdx] != 0) + { + if (WaveNum >= EndlessWaveRequired && GameClass == class'KFGameInfo_Endless' && Difficulty >= `DIFFICULTY_HARD) + { + FinishedObjective(SEI_Summer, ObjIdx); + } + } +} + +defaultproperties +{ + ZedsStompRequired=50 + LaserKillsRequired=20 + JumpKillsRequired=300 + EndlessWaveRequired=15 +} diff --git a/KFGameContent/Classes/KFWeapAttach_FAMAS.uc b/KFGameContent/Classes/KFWeapAttach_FAMAS.uc new file mode 100644 index 0000000..46e5fd0 --- /dev/null +++ b/KFGameContent/Classes/KFWeapAttach_FAMAS.uc @@ -0,0 +1,231 @@ +//============================================================================= +// KFWeapAttach_FAMAS +//============================================================================= +// +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFWeapAttach_FAMAS extends KFWeaponAttachment; + +const SecondaryFireAnim = 'Shoot_Secondary'; +const SecondaryFireIronAnim = 'Shoot_Secondary_Iron'; +const SecondaryFireAnimLast = 'Shoot_Secondary_Last'; +const SecondaryFireIronAnimLast = 'Shoot_Secondary_Iron_Last'; +const SecondaryFireBodyAnim = 'ADD_Shoot_Secondary'; +const SecondaryFireBodyAnimCH = 'ADD_Shoot_Secondary_CH'; +const SecondaryFireBodyAnimIron = 'ADD_Shoot_Secondary_Iron'; +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'; + +var protected transient KFMuzzleFlash ShotgunMuzzleFlash; + + +/** Play a 3rd person reload animation */ +simulated function PlayReloadMagazineAnim(EWeaponState NewWeaponState, KFPawn P) +{ + local name AnimName; + + if(NewWeaponState == WEP_ReloadSecondary || NewWeaponState == WEP_ReloadSecondary_Elite) + { + switch (NewWeaponState) + { + case WEP_ReloadSecondary: + AnimName = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryReloadAnimEmpty : SecondaryReloadAnimHalf; + break; + case WEP_ReloadSecondary_Elite: + AnimName = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryReloadAnimEliteEmpty : SecondaryReloadAnimEliteHalf; + break; + } + + PlayCharacterMeshAnim(P, AnimName, true); + } + else + { + Super.PlayReloadMagazineAnim(NewWeaponState, P); + } +} + +simulated function CauseMuzzleFlash(byte FiringMode) +{ + if ( FiringMode == 1 ) // AltFire + { + if (ShotgunMuzzleFlash == None) + { + AttachMuzzleFlash(); + } + + if (ShotgunMuzzleFlash != None ) + { + ShotgunMuzzleFlash.CauseMuzzleFlash(FiringMode); + if ( ShotgunMuzzleFlash.bAutoActivateShellEject ) + { + ShotgunMuzzleFlash.CauseShellEject(); + } + } + } + else + { + Super.CauseMuzzleFlash(FiringMode); + } +} + +/** Added second weapon */ +simulated function AttachMuzzleFlash() +{ + Super.AttachMuzzleFlash(); + + if ( WeapMesh != none && ShotgunMuzzleFlash == None ) + { + ShotgunMuzzleFlash = new(self) Class'KFMuzzleFlash'(class'KFWeap_AssaultRifle_FAMAS'.default.ShotgunMuzzleFlashTemplate); + ShotgunMuzzleFlash.AttachMuzzleFlash(WeapMesh, ShotgunMuzzleSocket,); + } +} + +/** Plays fire animation on weapon mesh */ +simulated function PlayFireAnim(KFPawn P) +{ + local float Duration; + local name Anim; + local KFPawn OwnerPawn; + + OwnerPawn = KFPawn(Owner); + + if ( Instigator.bIsWalking ) // IronSight anims + { + if (OwnerPawn.FiringMode == 0) // DEFAULT FIRE MODE (Rifle) + { + Anim = WeaponIronFireAnim; + } + else if (OwnerPawn.FiringMode == 1) // ALT FIRE MODE (Shotgun) + { + // Anim = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryFireIronAnimLast : SecondaryFireIronAnim; + Anim = SecondaryFireIronAnim; + + } + } + else // Normal anims + { + if (Pawn(Owner).FiringMode == 0) // DEFAULT FIRE MODE (Rifle) + { + Anim = WeaponFireAnim; + } + else if (Pawn(Owner).FiringMode == 1) // ALT FIRE MODE (Shotgun) + { + // Anim = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryFireAnimLast : SecondaryFireAnim; + Anim = SecondaryFireAnim; + } + } + + Duration = WeapMesh.GetAnimLength( Anim ); + WeapMesh.PlayAnim( Anim, Duration / ThirdPersonAnimRate,, true ); +} + +simulated function bool ThirdPersonFireEffects( vector HitLocation, KFPawn P, byte ThirdPersonAnimRateByte ) +{ + local EAnimSlotStance AnimType; + + if (P.FiringMode == 1) // AltFire + { + SpawnTracer(GetAltMuzzleLocation(), HitLocation); + } + else + { + SpawnTracer(GetMuzzleLocation(), HitLocation); + } + + // Effects below this point are culled based on visibility and distance + if ( !ActorEffectIsRelevant(P, false, MaxFireEffectDistance) ) + { + return false; + } + + DecodeThirdPersonAnimRate( ThirdPersonAnimRateByte ); + + // Weapon shoot anims + if( !bWeapMeshIsPawnMesh ) + { + PlayFireAnim(P); + } + + if( P.IsDoingSpecialMove() && P.SpecialMoves[P.SpecialMove].bAllowFireAnims ) + { + AnimType = EAS_Additive; + } + else + { + AnimType = EAS_FullBody; + } + + // Character shoot anims + if ( !P.IsDoingSpecialMove() || AnimType == EAS_Additive ) + { + PlayPawnFireAnim( P, AnimType ); + + // interrupt other weapon action anims (e.g. Reload) + if( !P.IsDoingSpecialMove() ) + { + P.StopBodyAnim(P.bIsCrouched ? EAS_CH_UpperBody : EAS_UpperBody, 0.1f); + } + + if ( OnWeaponStateChanged != None ) + { + OnWeaponStateChanged(true); + } + } + + CauseMuzzleFlash(P.FiringMode); + return true; +} + +/** Plays fire animation on pawn */ +simulated function PlayPawnFireAnim( KFPawn P, EAnimSlotStance AnimType ) +{ + if (P.FiringMode == 0) + { + super.PlayPawnFireAnim(P, AnimType); + } + else if (P.FiringMode == 1) + { + if ( P.bIsCrouched ) + { + P.PlayBodyAnim(SecondaryFireBodyAnimCH, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime); + } + else if ( P.bIsWalking ) + { + P.PlayBodyAnim(SecondaryFireBodyAnimIron, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime); + } + else + { + P.PlayBodyAnim(SecondaryFireBodyAnim, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime); + } + } +} + +simulated function vector GetAltMuzzleLocation(optional byte MuzzleID) +{ + local vector SocketLocation; + + if (ShotgunMuzzleFlash == None && MuzzleFlashTemplate != None) + { + AttachMuzzleFlash(); + } + + if( ShotgunMuzzleFlash != none ) + { + WeapMesh.GetSocketWorldLocationAndRotation(ShotgunMuzzleFlash.GetSocketName(), SocketLocation); + return SocketLocation; + } + + return Super.GetMuzzleLocation(MuzzleID); +} + + +defaultproperties +{ + +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFWeapAttach_HRG_BarrierRifle.uc b/KFGameContent/Classes/KFWeapAttach_HRG_BarrierRifle.uc new file mode 100644 index 0000000..f090cb0 --- /dev/null +++ b/KFGameContent/Classes/KFWeapAttach_HRG_BarrierRifle.uc @@ -0,0 +1,102 @@ +//============================================================================= +// KFWeapAttach_HRG_BarrierRifle +//============================================================================= +// +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFWeapAttach_HRG_BarrierRifle extends KFWeaponAttachment; + +`define BARRIERRIFLE_MIC_SHIELD_INDEX 0 + +/** Indicates wheter we are activating/deactivating the shield fx */ +var protected transient bool bActivatingShield; +var protected transient float FXDelta; +var protected transient float ShieldFXDuration; +var protected transient float OverlayDelta; +var protected transient float OverlayMax; +var protected transient float OverlayMin; +var protected transient float ShieldBlockVFXDuration; + +simulated event PreBeginPlay() +{ + Super.PreBeginPlay(); + + if ( WorldInfo.NetMode == NM_DedicatedServer ) + { + return; + } + + ShieldFXDuration = class'KFWeap_HRG_BarrierRifle'.default.ShieldFXDuration; + OverlayMax = class'KFWeap_HRG_BarrierRifle'.default.RedOverlayMax; + OverlayMin = class'KFWeap_HRG_BarrierRifle'.default.RedOverlayMin; + ShieldBlockVFXDuration = class'KFWeap_HRG_BarrierRifle'.default.ShieldBlockVFXDuration; + + UpdateShieldFXValue(0.0f); +} + +simulated function UpdateShieldFXValue(float Value) +{ + if ( WeaponMIC == None && WeapMesh != None ) + { + WeaponMIC = WeapMesh.CreateAndSetMaterialInstanceConstant(`BARRIERRIFLE_MIC_SHIELD_INDEX); + } + + WeaponMIC.SetScalarParameterValue('Opacity', Value); +} + +unreliable client function SetShieldActive(bool bActive) +{ + bActivatingShield = bActive; +} + +/** Special event added for weap attachments. Free for use */ +function OnSpecialEvent(int Arg) +{ + if (Arg < 2) + { + SetShieldActive(Arg == 1 ? True : False); + } + else if (Arg == 3) + { + UpdateShieldBlockVFX(OverlayMax); + OverlayDelta = OverlayMax; + } +} + +simulated function UpdateShieldBlockVFX(float Value) +{ + if ( WeaponMIC == None && WeapMesh != None ) + { + WeaponMIC = WeapMesh.CreateAndSetMaterialInstanceConstant(`BARRIERRIFLE_MIC_SHIELD_INDEX); + } + WeaponMIC.SetScalarParameterValue('RedOverlay', Value); +} + +simulated event Tick(float DeltaTime) +{ + // Update Shield visuals + if (bActivatingShield && FXDelta < class'KFWeap_HRG_BarrierRifle'.default.ShieldFXDuration) + { + FXDelta = FMin(FXDelta + DeltaTime, ShieldFXDuration); + UpdateShieldFXValue(FXDelta / ShieldFXDuration); + } + else if (!bActivatingShield && FXDelta > 0.0f) + { + FXDelta = FMax(FXDelta - DeltaTime, 0.0f); + UpdateShieldFXValue(FXDelta / ShieldFXDuration); + } + + if (OverlayDelta > 0.0f) + { + OverlayDelta = FMax(OverlayDelta - DeltaTime, OverlayMin); + UpdateShieldBlockVFX(OverlayMax * (OverlayDelta / ShieldBlockVFXDuration)); + } +} + +defaultproperties +{ + OverlayDelta=0.0f +} diff --git a/KFGameContent/Classes/KFWeapAttach_HRG_BlastBrawlers.uc b/KFGameContent/Classes/KFWeapAttach_HRG_BlastBrawlers.uc new file mode 100644 index 0000000..40519ed --- /dev/null +++ b/KFGameContent/Classes/KFWeapAttach_HRG_BlastBrawlers.uc @@ -0,0 +1,142 @@ +//============================================================================= +// KFWeapAttach_HRG_BlastBrawlers +//============================================================================= +// +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= +class KFWeapAttach_HRG_BlastBrawlers extends KFWeapAttach_DualBase; + +var protected transient bool bUsingLeftWeapon; +var protected transient name ReloadAnimName; +var protected transient float ReloadAnimRateMod; + +/** Overrides to prevent weapon animation */ +simulated function PlayWeaponFireAnim(); + +/** Caching reload anim name */ +simulated event PreBeginPlay() +{ + Super.PreBeginPlay(); + + ReloadAnimName = class'KFWeap_HRG_BlastBrawlers'.default.ReloadAnimation; + ReloadAnimRateMod = class'KFWeap_HRG_BlastBrawlers'.default.ReloadAnimRateModifier; +} + +/** Overriding to avoid interrupting meleen anims with fire anims */ +simulated function bool ThirdPersonFireEffects( vector HitLocation, KFPawn P, byte ThirdPersonAnimRateByte ) +{ + SpawnTracer(GetMuzzleLocation(), HitLocation); + + // Effects below this point are culled based on visibility and distance + if ( !ActorEffectIsRelevant(P, false, MaxFireEffectDistance) ) + { + return false; + } + + CauseMuzzleFlash(P.FiringMode); + P.LastWeaponFireTime = -1.f; + + return true; +} + +simulated function vector GetMuzzleLocation(optional byte MuzzleID) +{ + local vector SocketLocation; + + if ( bUsingLeftWeapon) + { + if (LeftMuzzleFlash == None && MuzzleFlashTemplate != None) + { + AttachMuzzleFlash(); + } + + if( LeftMuzzleFlash != none ) + { + LeftWeapMesh.GetSocketWorldLocationAndRotation(LeftMuzzleFlash.GetSocketName(), SocketLocation); + return SocketLocation; + } + } + + return Super.GetMuzzleLocation(MuzzleID); +} + +/** Added second weapon */ +simulated function CauseMuzzleFlash(byte FiringMode) +{ + if ( bUsingLeftWeapon ) + { + if (LeftMuzzleFlash == None && MuzzleFlashTemplate != None) + { + AttachMuzzleFlash(); + } + + if (LeftMuzzleFlash != None ) + { + LeftMuzzleFlash.CauseMuzzleFlash(FiringMode); + if ( LeftMuzzleFlash.bAutoActivateShellEject ) + { + LeftMuzzleFlash.CauseShellEject(); + } + } + } + else + { + Super.CauseMuzzleFlash(FiringMode); + bUsingLeftWeapon = true; + } +} + +simulated function UpdateThirdPersonWeaponAction(EWeaponState NewWeaponState, KFPawn P, byte ThirdPersonAnimRateByte ) +{ + // Reset + bUsingLeftWeapon=false; + super.UpdateThirdPersonWeaponAction(NewWeaponState, P, ThirdPersonAnimRateByte); +} + +simulated function PlayReloadMagazineAnim(EWeaponState NewWeaponState, KFPawn P) +{ + PlayCharacterMeshAnim(P, ReloadAnimNAme, true); +} + +simulated function PlayWeaponMeshAnim(name AnimName, AnimNodeSlot SyncNode, bool bLoop) +{ + local float Duration; + + /** Only reload animation could be played */ + if ( !IsAnimationValid(AnimName) ) + return; + + // Weapon shoot anims + if( !bWeapMeshIsPawnMesh ) + { + Duration = WeapMesh.GetAnimLength(AnimName); + + if (AnimName == ReloadAnimName) + { + Duration *= ReloadAnimRateMod; + } + + WeapMesh.PlayAnim(AnimName, Duration / ThirdPersonAnimRate, bLoop); + + // syncronize this with the character anim + if ( SyncNode != None ) + { + bSynchronizeWeaponAnim = true; + SyncPawnNode = SyncNode; + SyncAnimName = AnimName; + bSyncAnimCheckRelevance = false; + } + } +} + +simulated function bool IsAnimationValid(name AnimName) +{ + return AnimName == ReloadAnimName; +} + +defaultproperties +{ + bUsingLeftWeapon=false +} diff --git a/KFGameContent/Classes/KFWeap_AssaultRifle_FAMAS.uc b/KFGameContent/Classes/KFWeap_AssaultRifle_FAMAS.uc new file mode 100644 index 0000000..b8878a5 --- /dev/null +++ b/KFGameContent/Classes/KFWeap_AssaultRifle_FAMAS.uc @@ -0,0 +1,682 @@ +//============================================================================= +// 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)); + + 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 false; + } + + /** 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 ); +} + +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]=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' + 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)=25.0 + PenetrationPower(DEFAULT_FIREMODE)=2.0 + FireInterval(ALTFIRE_FIREMODE)=+1.2 //0.5 //0.7 //85 RPM + NumPellets(ALTFIRE_FIREMODE)=6 + Spread(ALTFIRE_FIREMODE)=0.12 //0.07 + 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 +} \ No newline at end of file diff --git a/KFGameContent/Classes/KFWeap_AssaultRifle_LazerCutter.uc b/KFGameContent/Classes/KFWeap_AssaultRifle_LazerCutter.uc index 614cee1..e178831 100644 --- a/KFGameContent/Classes/KFWeap_AssaultRifle_LazerCutter.uc +++ b/KFGameContent/Classes/KFWeap_AssaultRifle_LazerCutter.uc @@ -1142,7 +1142,7 @@ defaultproperties BonesToLockOnEmpty=(RW_Magazine1, RW_BatteryContactLeft, RW_BatteryContactRight) // Weapon Upgrade stat boosts - WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.2f), (Stat=EWUS_Damage1, Scale=1.2f), (Stat=EWUS_Weight, Add=1))) + WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.0f), (Stat=EWUS_Damage1, Scale=1.0f), (Stat=EWUS_Weight, Add=0))) MuzzleFlashEffectL1=ParticleSystem'WEP_Laser_Cutter_EMIT.FX_Laser_Cutter_Beam_Muzzleflash_01' MuzzleFlashEffectL2=ParticleSystem'WEP_Laser_Cutter_EMIT.FX_Laser_Cutter_Beam_Muzzleflash_02' diff --git a/KFGameContent/Classes/KFWeap_Bow_CompoundBow.uc b/KFGameContent/Classes/KFWeap_Bow_CompoundBow.uc index 5e2164b..7b2e1a9 100644 --- a/KFGameContent/Classes/KFWeap_Bow_CompoundBow.uc +++ b/KFGameContent/Classes/KFWeap_Bow_CompoundBow.uc @@ -727,9 +727,9 @@ defaultproperties // Ammo MagazineCapacity[0]=1 - SpareAmmoCapacity[0]=30 - InitialSpareMags[0]=10 - AmmoPickupScale[0]=3.0 // 3 arrows + SpareAmmoCapacity[0]=35 //30 + InitialSpareMags[0]=11 //10 + AmmoPickupScale[0]=4.0 //3.0 // Recoil maxRecoilPitch=200 diff --git a/KFGameContent/Classes/KFWeap_HRG_BarrierRifle.uc b/KFGameContent/Classes/KFWeap_HRG_BarrierRifle.uc new file mode 100644 index 0000000..f99f3c0 --- /dev/null +++ b/KFGameContent/Classes/KFWeap_HRG_BarrierRifle.uc @@ -0,0 +1,731 @@ +//============================================================================= +// KFWeap_HRG_BarrierRifle +//============================================================================= +// A modified version of the Stoner63A rifle. +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= +class KFWeap_HRG_BarrierRifle extends KFWeap_LMG_Stoner63A; + +`define BARRIERRIFLE_MIC_SHIELD_INDEX 4 + +/** Amount of shield charge that is consumed per second */ +var (Shield) float ShieldConsumptionPerSecond; + +/** Amount of shield chared that is recharged per second */ +var (Shield) float ShieldRechargePerSecond; + +/** Cooldown to apply after the shield is destroyed */ +var (Shield) float CooldownAfterShieldDepleted; + +/** Cooldown to apply after the shield depleted the charge */ +var (Shield) float CooldownAfterShieldDestroyed; + +/** VFX and SFX for blocking damage */ +var (Shield) AkBaseSoundObject BlockSound; +var (Shield) ParticleSystem BlockParticleSystem; +var (Shield) name BlockEffectsSocketName; + +/** Blocking information per damage type */ +var (Shield) array BlockDamageTypes; + +/** Modifier applied to the damage received by the character */ +var (Shield) float BlockDamageModifier; + +/** Modifier applied to the damager that will affect the shield charge */ +var (Shield) float ShieldDamageAbsorbtionModifier; + +/** Angle to block with the shield */ +var (Shield) float BlockingAngle; + +/** Turn ON/OFF VFX duration */ +var (Shield) float ShieldFXDuration; + +/** Shield Block VFX duration */ +var (Shield) float ShieldBlockVFXDuration; + +/** Is shield active */ +var protected transient bool bIsShieldActive; + +/** Was shield charge depleted */ +var protected transient bool bWasShieldDepleted; + +/** Was the shield destroyed */ +var protected transient bool bWasShielDestroyed; + +/** Self explanatory */ +var protected transient bool bCanRechargeShield; + +/** float containing the shield charge to not be lost in the next frame + due to int conversion. + */ +var protected transient float ShieldRechargeIncrement; +var protected transient float ShieldConsumptionIncrement; + +/** Cos of the blocking angle (Rads) */ +var protected transient float BlockingAngleCos; + +/** Wether the timer for activating the shield has expired (using the fire interval) */ +var protected transient bool bShieldActionAvailable; + +/** Indicates wheter we are activating/deactivating the shield fx */ +var protected bool bActivatingShield; +var protected bool bDeactivatingShield; +var protected transient float FXDelta; + +var transient float RedOverlayMax; +var transient float RedOverlayMin; +var protected transient float OverlayDelta; + +var WeaponFireSndInfo ShieldActivateSound; +var WeaponFireSndInfo ShieldDeactivateSound; +var (Shield) AkBaseSoundObject ShieldEndSound; + +var repnotify byte ShieldAmmo; + +replication +{ + if (bNetDirty && Role == ROLE_Authority) + bActivatingShield, bDeactivatingShield; + + if (bNetDirty && Role == ROLE_Authority && bAllowClientAmmoTracking) + ShieldAmmo; +} + +simulated event ReplicatedEvent(name VarName) +{ + if (VarName == nameof(ShieldAmmo)) + { + AmmoCount[ALTFIRE_FIREMODE] = ShieldAmmo; + } + else + { + Super.ReplicatedEvent(VarName); + } +} + +simulated event PostBeginPlay() +{ + super.PostBeginPlay(); + BlockingAngleCos = cos((BlockingAngle / 2.f) * DegToRad); +} + +simulated function Activate() +{ + super.Activate(); + + if (WorldInfo.NetMode != NM_DedicatedServer) + { + UpdateShieldFXValue(0.0f); + } +} + +simulated function UpdateShieldFXValue(float Value) +{ + if( WeaponMICs.Length > `BARRIERRIFLE_MIC_SHIELD_INDEX ) + { + WeaponMICs[`BARRIERRIFLE_MIC_SHIELD_INDEX].SetScalarParameterValue('Opacity', Value); + } +} + +/** + * Instead of a toggle, just immediately fire alternate fire. + */ +simulated function AltFireMode() +{ + // LocalPlayer Only + if ( !Instigator.IsLocallyControlled() ) + { + return; + } + + if( Role < Role_Authority ) + { + // if we're a client, synchronize server + UseShield(); + } + + CustomFire(); +} + +reliable server function UseShield() +{ + CustomFire(); +} + +/** Shield deploying */ +simulated function CustomFire() +{ + if (bWasShieldDepleted || bWasShielDestroyed || !bShieldActionAvailable || AmmoCount[ALTFIRE_FIREMODE] == 0) + { + return; + } + + bIsShieldActive ? DeactivateShield() : ActivateShield(); + bIsShieldActive = !bIsShieldActive; + + bShieldActionAvailable = false; +} + +simulated function ActivateShield() +{ + PlaySoundBase(ShieldActivateSound.FirstPersonCue); + bActivatingShield = true; + bDeactivatingShield = false; + bNetDirty = true; + NotifyShieldActive(true); + SetTimer(FireInterval[ALTFIRE_FIREMODE], false, nameof(ShieldActivationCompleted)); +} + +simulated function DeactivateShield() +{ + PlaySoundBase(ShieldDeactivateSound.FirstPersonCue); + bDeactivatingShield = true; + bActivatingShield = false; + bCanRechargeShield = false; + bNetDirty=true; + NotifyShieldActive(false); + SetTimer(FireInterval[ALTFIRE_FIREMODE], false, nameof(ShieldDeactivatedTimerCompleted)); +} + +simulated function ShieldActivationCompleted() +{ + bShieldActionAvailable = true; +} + +simulated function ShieldDeactivatedTimerCompleted() +{ + bShieldActionAvailable = true; + bCanRechargeShield = true; +} + +/** Update shield charge - client and server */ +simulated event Tick(float DeltaTime) +{ + // Update Shield visuals + if (WorldInfo.NetMode != NM_DedicatedServer) + { + if (bActivatingShield && FXDelta < ShieldFXDuration) + { + FXDelta = FMin(FXDelta + DeltaTime, ShieldFXDuration); + UpdateShieldFXValue(FXDelta / ShieldFXDuration); + if (FXDelta == ShieldFXDuration) + { + bActivatingShield = false; + } + } + else if (bDeactivatingShield && FXDelta > 0.0f) + { + FXDelta = FMax(FXDelta - DeltaTime, 0.0f); + UpdateShieldFXValue(FXDelta / ShieldFXDuration); + if (FXDelta == 0.0f) + { + bDeactivatingShield = false; + } + } + } + + if (OverlayDelta > RedOverlayMin) + { + OverlayDelta = FMax(OverlayDelta - DeltaTime, RedOverlayMin); + UpdateShieldBlockVFX(RedOverlayMax * (OverlayDelta / ShieldBlockVFXDuration)); + } + + if ( Role == Role_Authority ) + { + // If shield is active it needs to consume charge, otherwise it recharges itself. + if (bIsShieldActive) + { + ConsumeShield(DeltaTime); + } + else if (bCanRechargeShield && AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE]) + { + RechargeShield(DeltaTime); + } + } + + Super.Tick(DeltaTime); +} + +simulated function ConsumeShield(float DeltaTime) +{ + local int Charge; + + if (Role == ROLE_Authority) + { + ShieldRechargeIncrement = 0.0f; + + ShieldConsumptionIncrement += ShieldConsumptionPerSecond * DeltaTime; + + if (ShieldConsumptionIncrement >= 1.0f && AmmoCount[ALTFIRE_FIREMODE] > 0) + { + Charge = int(ShieldConsumptionIncrement); + AmmoCount[ALTFIRE_FIREMODE] = Max(AmmoCount[ALTFIRE_FIREMODE] - Charge, 0); + ShieldConsumptionIncrement -= Charge; + + ShieldAmmo = AmmoCount[ALTFIRE_FIREMODE]; + + if (AmmoCount[ALTFIRE_FIREMODE] == 0) + { + OnShieldDepleted(); + } + } + } +} + +simulated function RechargeShield(float DeltaTime) +{ + local int Charge; + + if (Role == ROLE_Authority) + { + ShieldConsumptionIncrement = 0.0f; + ShieldRechargeIncrement += ShieldRechargePerSecond * DeltaTime; + if (ShieldRechargeIncrement >= 1.0f && AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE]) + { + Charge = int(ShieldRechargeIncrement); + AmmoCount[ALTFIRE_FIREMODE] = Min(AmmoCount[ALTFIRE_FIREMODE] + Charge, MagazineCapacity[ALTFIRE_FIREMODE]); + ShieldRechargeIncrement -= Charge; + + ShieldAmmo = AmmoCount[ALTFIRE_FIREMODE]; + } + } +} + +/** Shield consumed all the charge by itself */ +simulated function OnShieldDepleted() +{ + bWasShieldDepleted = true; + bActivatingShield = false; + bDeactivatingShield = true; + bCanRechargeShield = false; + bIsShieldActive = false; + ShieldAmmo = 0; + bNetDirty = true; + NotifyShieldActive(false); + PlaySoundBase(ShieldEndSound); + SetTimer(CooldownAfterShieldDepleted, false, nameof(ShieldRepletedTimerCompleted)); +} + +simulated function ShieldRepletedTimerCompleted() +{ + bWasShieldDepleted = false; + bCanRechargeShield = true; +} + +/** Shield was destroyed by attacks */ +simulated function OnShieldDestroyed() +{ + bWasShielDestroyed = true; + bActivatingShield = false; + bDeactivatingShield = true; + bCanRechargeShield = false; + bIsShieldActive = false; + ShieldAmmo = 0; + bNetDirty = true; + NotifyShieldActive(false); + PlaySoundBase(ShieldEndSound); + SetTimer(CooldownAfterShieldDestroyed, false, nameof(ShieldDestroyedTimerCompleted)); +} + +simulated function ShieldDestroyedTimerCompleted() +{ + bWasShielDestroyed = false; + bCanRechargeShield = true; +} + +/** Update HUD ammo icon for shield */ +simulated function int GetSecondaryAmmoForHUD() +{ + return AmmoCount[ALTFIRE_FIREMODE]; +} + +simulated function ShieldAbsorbDamage(int DamageBase) +{ + local int Damage; + // Use the carried shield reduction by time + ShieldConsumptionIncrement += DamageBase*ShieldDamageAbsorbtionModifier; + Damage = int(ShieldConsumptionIncrement); + AmmoCount[ALTFIRE_FIREMODE] = Max(AmmoCount[ALTFIRE_FIREMODE] - Damage, 0); + ShieldConsumptionIncrement -= Damage; + + // Check if shield is destroyed. + if (AmmoCount[ALTFIRE_FIREMODE] == 0) + { + OnShieldDestroyed(); + } +} + +/** + Reduce the damage received and apply it to the shield + */ +function AdjustDamage(out int InDamage, class DamageType, Actor DamageCauser) +{ + local KFPerk InstigatorPerk; + local byte BlockTypeIndex; + local float DmgCauserDot; + + if (!bIsShieldActive) + { + return; + } + + // Don't apply block effects for teammates + if (Instigator.IsSameTeam(DamageCauser.Instigator)) + { + return; + } + + if (CanBlockDamageType(DamageType, BlockTypeIndex)) + { + if (ClassIsChildOf(DamageCauser.class, class'Projectile')) + { + // Projectile might be beyond/behind player, resulting in bad dot + // Projectile won't have a velocity to check against, either + // Assume velocity is the vector between projectile and instigator + DmgCauserDot = Normal(DamageCauser.Instigator.Location - DamageCauser.Location) dot vector(Instigator.Rotation); + } + else + { + DmgCauserDot = Normal(DamageCauser.Location - Instigator.Location) dot vector(Instigator.Rotation); + } + + if (DmgCauserDot > BlockingAngleCos) + { + ShieldAbsorbDamage(InDamage); + InDamage *= BlockDamageModifier; + + ClientPlayBlockEffects(BlockTypeIndex); + NotifyShieldBlockActive(true); + SetTimer(0.1f, false, nameof(ResetShieldBlockVFX)); + + InstigatorPerk = GetPerk(); + if (InstigatorPerk != none) + { + InstigatorPerk.SetSuccessfullBlock(); + } + } + } +} + +/** Only DT added to BlockDamageTypes can be blocked. Check if the current one is in the list. */ +function bool CanBlockDamageType(class DamageType, optional out byte out_Idx) +{ + local int Idx; + + for (Idx = 0; Idx < BlockDamageTypes.length; ++Idx) + { + if (ClassIsChildOf(DamageType, BlockDamageTypes[Idx].DmgType)) + { + out_Idx = Idx; + return true; + } + } + + out_Idx = INDEX_NONE; + return false; +} + +unreliable client function ClientPlayBlockEffects(optional byte BlockDTIndex=255) +{ + local AkBaseSoundObject Sound; + local ParticleSystem PSTemplate; + + GetBlockEffects(BlockDTIndex, Sound, PSTemplate); + PlayLocalBlockEffects(Sound, PSTemplate); + UpdateShieldBlockVFX(RedOverlayMax); + OverlayDelta = ShieldBlockVFXDuration; +} + +/** Called on the client when successfully block/parry an attack */ +simulated function PlayLocalBlockEffects(AKBaseSoundObject Sound, ParticleSystem PSTemplate) +{ + local vector Loc; + local rotator Rot; + local ParticleSystemComponent PSC; + + if (Sound != None) + { + PlaySoundBase(Sound, true); + } + + if (PSTemplate != None) + { + if (MySkelMesh.GetSocketWorldLocationAndRotation(BlockEffectsSocketName, Loc, Rot)) + { + PSC = WorldInfo.MyEmitterPool.SpawnEmitter(PSTemplate, Loc, Rot); + PSC.SetDepthPriorityGroup(SDPG_Foreground); + } + else + { + `log(self@GetFuncName()@"missing BlockEffects Socket!"); + } + } +} + +/** Returns sound and particle system overrides using index into BlockDamageTypes array */ +simulated function GetBlockEffects(byte BlockDTIndex, out AKBaseSoundObject outSound, out ParticleSystem outParticleSys) +{ + outSound = BlockSound; + outParticleSys = BlockParticleSystem; + + if (BlockDTIndex != 255) + { + if (BlockDamageTypes[BlockDTIndex].BlockSound != None) + { + outSound = BlockDamageTypes[BlockDTIndex].BlockSound; + } + if (BlockDamageTypes[BlockDTIndex].BlockParticleSys != None) + { + outParticleSys = BlockDamageTypes[BlockDTIndex].BlockParticleSys; + } + } +} + +/** + Should replicate to 3P to show the shield effects + */ +simulated function NotifyShieldActive(bool bActive) +{ + local KFPawn KFP; + + if (WorldInfo.NetMode != NM_Client) + { + KFP = KFPawn(Instigator); + KFP.OnWeaponSpecialAction(bActive ? 1 : 0); + } +} + +simulated function NotifyShieldBlockActive(bool bActive) +{ + local KFPawn KFP; + + if (WorldInfo.NetMode != NM_Client) + { + KFP = KFPawn(Instigator); + KFP.OnWeaponSpecialAction(bActive ? 3 : 2); + } +} + +/********************************************************************************************* + * State WeaponEquipping + * The Weapon is in this state while transitioning from Inactive to Active state. + * Typically, the weapon will remain in this state while its selection animation is being played. + * While in this state, the weapon cannot be fired. +*********************************************************************************************/ + +simulated state WeaponEquipping +{ + simulated function BeginState(Name PreviousStateName) + { + bShieldActionAvailable = true; + super.BeginState(PreviousStateName); + } +} + +/********************************************************************************************* + * State WeaponPuttingDown + * Putting down weapon in favor of a new one. + * Weapon is transitioning to the Inactive state. +*********************************************************************************************/ + +simulated state WeaponPuttingDown +{ + simulated event EndState(Name NextStateName) + { + UpdateShieldFXValue(0.0f); + + // Reset Values + bIsShieldActive = false; + bWasShieldDepleted = false; + bWasShielDestroyed = false; + bCanRechargeShield = true; + bShieldActionAvailable = false; + bActivatingShield = false; + bDeactivatingShield = false; + FXDelta = 0.0f; + bNetDirty=true; + + super.EndState(NextStateName); + } +} + +simulated function UpdateShieldBlockVFX(float Value) +{ + if( WeaponMICs.Length > `BARRIERRIFLE_MIC_SHIELD_INDEX ) + { + WeaponMICs[`BARRIERRIFLE_MIC_SHIELD_INDEX].SetScalarParameterValue('RedOverlay', Value); + } +} + +function ResetShieldBlockVFX() +{ + NotifyShieldBlockActive(false); +} + +/** Shield doesn't count as ammo for purposes of inventory management (e.g. switching) */ +simulated function bool HasAnyAmmo() +{ + return AmmoCount[0] > 0 || SpareAmmoCount[0] > 0; +} + +defaultproperties +{ + // Shooting Animations + FireSightedAnims[0]=Shoot_Iron + FireSightedAnims[1]=Shoot_Iron2 + FireSightedAnims[2]=Shoot_Iron3 + + // FOV + MeshFOV=75 + MeshIronSightFOV=35 + PlayerIronSightFOV=70 + + // Depth of field + DOF_FG_FocalRadius=85 + DOF_FG_MaxNearBlurSize=2.5 + + // Content + PackageKey="HRG_BarrierRifle" + FirstPersonMeshName="WEP_1P_HRG_BarrierRifle_MESH.WEP_1stP_HRG_BarrielRifle_Rig" + FirstPersonAnimSetNames(0)="WEP_1P_HRG_BarrierRifle_ANIM.Wep_1stP_HRG_BarrierRifle_Anim" + PickupMeshName="WEP_3P_HRG_BarrierRifle_MESH.Wep_3rdP_HRG_BarrierRifle_Pickup" + AttachmentArchetypeName="WEP_HRG_BarrierRifle_ARCH.Wep_HRG_BarrierRifle_3P" + MuzzleFlashTemplateName="WEP_HRG_BarrierRifle_ARCH.Wep_HRG_BarrierRifle_MuzzleFlash" + + // Zooming/Position + PlayerViewOffset=(X=4.0,Y=8,Z=-4) + IronSightPosition=(X=8.5,Y=0,Z=0) + + // Ammo + MagazineCapacity[0]=60 + SpareAmmoCapacity[0]=540 //480 + InitialSpareMags[0]=2 + bCanBeReloaded=true + bReloadFromMagazine=true + + // Shield "Ammo" + MagazineCapacity[1]=100 + SpareAmmoCapacity[1]=0 + bCanRefillSecondaryAmmo=false + + // Recoil + maxRecoilPitch=110 //120 + minRecoilPitch=70 //70 + maxRecoilYaw=80 //130 + minRecoilYaw=-80 //-130 + RecoilRate=0.045 //0.08 + RecoilMaxYawLimit=500 + RecoilMinYawLimit=65035 + RecoilMaxPitchLimit=900 + RecoilMinPitchLimit=65035 + RecoilISMaxYawLimit=75 + RecoilISMinYawLimit=65460 + RecoilISMaxPitchLimit=375 + RecoilISMinPitchLimit=65460 + RecoilViewRotationScale=0.4 //0.25 + IronSightMeshFOVCompensationScale=2.3 + HippedRecoilModifier=1.5 + //WalkingRecoilModifier=1.1 + //JoggingRecoilModifier=1.2 + + // Inventory / Grouping + InventorySize=7 + GroupPriority=125 + WeaponSelectTexture=Texture2D'wep_ui_hrg_barrierrifle_tex.UI_WeaponSelect_HRG_BarrierRifle' + AssociatedPerkClasses(0)=class'KFPerk_SWAT' + + // DEFAULT_FIREMODE + FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletAuto' + FiringStatesArray(DEFAULT_FIREMODE)=WeaponFiring + WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit + WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_AssaultRifle' + InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_HRG_BarrierRifle' + FireInterval(DEFAULT_FIREMODE)=+0.066 // 900 RPM + Spread(DEFAULT_FIREMODE)=0.025 //0.0085 + InstantHitDamage(DEFAULT_FIREMODE)=33.0 //35.0 + FireOffset=(X=30,Y=4.5,Z=-5) + + // ALT_FIREMODE + FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletAuto' + WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Custom + AmmoCost(ALTFIRE_FIREMODE)=0 + FireInterval(ALTFIRE_FIREMODE)=0.01f + SecondaryAmmoTexture=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity' + + // BASH_FIREMODE + InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HRG_BarrierRifle' + InstantHitDamage(BASH_FIREMODE)=26 + + // Fire Effects + WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Stoner.Play_WEP_Stoner_Fire_3P_Loop', FirstPersonCue=AkEvent'WW_WEP_Stoner.Play_WEP_Stoner_Fire_1P_Loop') + WeaponFireLoopEndSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Stoner.Play_WEP_Stoner_Fire_3P_EndLoop', FirstPersonCue=AkEvent'WW_WEP_Stoner.Play_WEP_Stoner_Fire_1P_EndLoop') + WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_L85A2.Play_WEP_SA_L85A2_Handling_DryFire' + EjectedShellForegroundDuration=0.8f + + // Advanced (High RPM) Fire Effects + bLoopingFireAnim(DEFAULT_FIREMODE)=true + bLoopingFireSnd(DEFAULT_FIREMODE)=true + + // Attachments + bHasIronSights=true + bHasFlashlight=false + + // Ammo belt + AmmoBeltBulletBonePrefix="RW_Bullets" + NumAmmoBeltBullets=14 + LastAmmoCount=-1 + + bIsShieldActive=false + bWasShieldDepleted=false + bWasShielDestroyed=false + bCanRechargeShield=true + ShieldRechargeIncrement=0.0f; + ShieldConsumptionIncrement=0.0f + + ShieldConsumptionPerSecond=3.0f //10.0f + ShieldRechargePerSecond=8.0f //10.0f //15.0f + CooldownAfterShieldDepleted=3.0f //3.0f + CooldownAfterShieldDestroyed=3.0f //5.0f + + ShieldActivateSound=(DefaultCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_On', FirstPersonCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_On') + ShieldDeactivateSound=(DefaultCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Off', FirstPersonCue=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Off') + ShieldEndSound=AKEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_End'; + + BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact' + BlockParticleSystem=ParticleSystem'FX_Impacts_EMIT.FX_Block_melee_01' + BlockEffectsSocketName=BlockEffect + + RedOverlayMax=1.0f + RedOverlayMin=0.0f + OverlayDelta=0.0f + ShieldBlockVFXDuration=0.5f + + BlockDamageTypes.Add((DmgType=class'KFDT_Bludgeon', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_Slashing', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_Fire_HuskFireball', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_Fire_HuskFlamethrower')) + BlockDamageTypes.Add((DmgType=class'KFDT_BloatPuke')) + BlockDamageTypes.Add((DmgType=class'KFDT_EvilDAR_Rocket', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_EvilDAR_Laser', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_DAR_EMPBlast', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_Ballistic_PatMinigun', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_Explosive_PatMissile', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_Ballistic_HansAK12', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_EMP_MatriarchTeslaBlast', BlockSound=AkEvent'WW_WEP_HRG_BarrierRifle.Play_WEP_HRG_BarrierRifle_1P_Shield_Impact')) + BlockDamageTypes.Add((DmgType=class'KFDT_EMP_MatriarchPlasmaCannon')) + BlockDamageTypes.Add((DmgType=class'KFDT_FleshpoundKing_ChestBeam')) + BlockDamageModifier=0.3f //0.4f + ShieldDamageAbsorbtionModifier=1.2f //0.8f //0.8 = equal to base damage + BlockingAngle=180.f // Adjust with visuals. + bShieldActionAvailable=true + bActivatingShield=false + bDeactivatingShield=false + FXDelta=0.0f + ShieldFXDuration=0.15f + bAllowClientAmmoTracking=true + NumBloodMapMaterials=5 + + WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.0f), (Stat=EWUS_Weight, Add=0))) +} diff --git a/KFGameContent/Classes/KFWeap_HRG_BlastBrawlers.uc b/KFGameContent/Classes/KFWeap_HRG_BlastBrawlers.uc new file mode 100644 index 0000000..4c55d51 --- /dev/null +++ b/KFGameContent/Classes/KFWeap_HRG_BlastBrawlers.uc @@ -0,0 +1,482 @@ +//============================================================================= +// 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 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; +} + +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]=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)=36.0 //30.0 + AmmoCost(CUSTOM_FIREMODE)=0 + NumPellets(CUSTOM_FIREMODE)=5 + Spread(CUSTOM_FIREMODE)=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 + 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.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))) +} diff --git a/KFGameContent/Classes/KFWeap_Rifle_Hemogoblin.uc b/KFGameContent/Classes/KFWeap_Rifle_Hemogoblin.uc index 7637b49..250276d 100644 --- a/KFGameContent/Classes/KFWeap_Rifle_Hemogoblin.uc +++ b/KFGameContent/Classes/KFWeap_Rifle_Hemogoblin.uc @@ -42,7 +42,7 @@ simulated function ProcessInstantHitEx(byte FiringMode, ImpactInfo Impact, optio defaultproperties { //Healing - HealAmount=20 + HealAmount=25 //20 HealFullRechargeSeconds=10 // Inventory / Grouping @@ -84,7 +84,7 @@ defaultproperties // Ammo MagazineCapacity[0]=7 - SpareAmmoCapacity[0]=98 + SpareAmmoCapacity[0]=112 //98 InitialSpareMags[0]=4 bCanBeReloaded=true bReloadFromMagazine=true @@ -119,7 +119,7 @@ defaultproperties FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_Hemogoblin' - InstantHitDamage(DEFAULT_FIREMODE)=100.0 + InstantHitDamage(DEFAULT_FIREMODE)=120.0 //100.0 InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_Hemogoblin' FireInterval(DEFAULT_FIREMODE)=0.25 PenetrationPower(DEFAULT_FIREMODE)=0.0 //2.0 diff --git a/KFGameContent/Classes/KFWeap_RocketLauncher_ThermiteBore.uc b/KFGameContent/Classes/KFWeap_RocketLauncher_ThermiteBore.uc new file mode 100644 index 0000000..b924ad0 --- /dev/null +++ b/KFGameContent/Classes/KFWeap_RocketLauncher_ThermiteBore.uc @@ -0,0 +1,324 @@ +//============================================================================= +// KFWeap_RocketLauncher_ThermiteBore +//============================================================================= +// Impale, burn, repeat +//============================================================================= +// Killing Floor 2 +// Copyright (C) 2021 Tripwire Interactive LLC +//============================================================================= + +class KFWeap_RocketLauncher_ThermiteBore extends KFWeap_GrenadeLauncher_Base; + +/** List of spawned harpoons (will be detonated oldest to youngest) */ +var array DeployedHarpoons; + +/** Same as DeployedHarpoons.Length, but replicated because harpoons are only tracked on server */ +var int NumDeployedHarpoons; + +/** Reduction for the amount of damage dealt to the weapon owner (including damage by the explosion) */ +var float SelfDamageReductionValue; + +var(Animations) const editconst name DetonateAnim; +var(Animations) const editconst name DetonateAnimLast; +var(Animations) const editconst name DetonateAnimIron; +var(Animations) const editconst name DetonateAnimIronLast; + +replication +{ + if( bNetDirty ) + NumDeployedHarpoons; +} + +/** + * Toggle between DEFAULT and ALTFIRE + */ +simulated function AltFireMode() +{ + // skip super + + if (!Instigator.IsLocallyControlled()) + { + return; + } + + StartFire(ALTFIRE_FIREMODE); +} + +/** Overridded to add spawned charge to list of spawned charges */ +simulated function Projectile ProjectileFire() +{ + local Projectile P; + local KFProj_Rocket_ThermiteBore Harpoon; + + P = super.ProjectileFire(); + + Harpoon = KFProj_Rocket_ThermiteBore(P); + if (Harpoon != none) + { + DeployedHarpoons.AddItem(Harpoon); + NumDeployedHarpoons = DeployedHarpoons.Length; + bForceNetUpdate = true; + } + + return P; +} + +/** Returns animation to play based on reload type and status */ +simulated function name GetReloadAnimName(bool bTacticalReload) +{ + // magazine relaod + if (AmmoCount[0] > 0) + { + return (bTacticalReload) ? ReloadNonEmptyMagEliteAnim : ReloadNonEmptyMagAnim; + } + else + { + return (bTacticalReload) ? ReloadEmptyMagEliteAnim : ReloadEmptyMagAnim; + } +} + +function AdjustDamage(out int InDamage, class DamageType, Actor DamageCauser) +{ + super.AdjustDamage(InDamage, DamageType, DamageCauser); + + if (Instigator != none && DamageCauser != none && DamageCauser.Instigator == Instigator) + { + InDamage *= SelfDamageReductionValue; + } +} + +/********************************************************************************************* + * State WeaponDetonating + * The weapon is in this state while detonating a charge +*********************************************************************************************/ + +simulated function GotoActiveState(); + +simulated state WeaponDetonating +{ + ignores AllowSprinting; + + simulated event BeginState( name PreviousStateName ) + { + PrepareAndDetonate(); + } + + simulated function GotoActiveState() + { + GotoState('Active'); + } +} + +// GrenadeLaunchers determine ShouldPlayFireLast based on the spare ammo +// overriding to use the base KFWeapon version since that uses the current ammo in the mag +simulated function bool ShouldPlayFireLast(byte FireModeNum) +{ + return Super(KFWeapon).ShouldPlayFireLast(FireModeNum); +} + +simulated function PrepareAndDetonate() +{ + local name SelectedAnim; + local float AnimDuration; + local bool bInSprintState; + + // choose the detonate animation based on whether it is in ironsights and whether it is the last harpoon + if (bUsingSights) + { + SelectedAnim = ShouldPlayFireLast(DEFAULT_FIREMODE) ? DetonateAnimIronLast : DetonateAnimIron; + } + else + { + SelectedAnim = ShouldPlayFireLast(DEFAULT_FIREMODE) ? DetonateAnimLast : DetonateAnim; + } + + AnimDuration = MySkelMesh.GetAnimLength(SelectedAnim); + bInSprintState = IsInState('WeaponSprinting'); + + if (WorldInfo.NetMode != NM_DedicatedServer) + { + if (bInSprintState) + { + AnimDuration *= 0.25f; + PlayAnimation(SelectedAnim, AnimDuration); + } + else + { + PlayAnimation(SelectedAnim); + } + } + + if (Role == ROLE_Authority) + { + Detonate(); + } + + //AnimDuration value here representes the ALTFIRE FireInterval + AnimDuration = 0.75f; //1.f; + if (bInSprintState) + { + SetTimer(AnimDuration * 0.8f, false, nameof(PlaySprintStart)); + } + else + { + SetTimer(AnimDuration * 0.5f, false, nameof(GotoActiveState)); + } +} + +/** Detonates all the harpoons */ +simulated function Detonate() +{ + local int i; + + // auto switch weapon when out of ammo and after detonating the last deployed charge + if (Role == ROLE_Authority) + { + for (i = DeployedHarpoons.Length - 1; i >= 0; i--) + { + DeployedHarpoons[i].Detonate(); + } + + if (!HasAnyAmmo() && NumDeployedHarpoons == 0) + { + if (CanSwitchWeapons()) + { + Instigator.Controller.ClientSwitchToBestWeapon(false); + } + } + } +} + +/** Removes a charge from the list using either an index or an actor and updates NumDeployedHarpoons */ +function RemoveDeployedHarpoon(optional int HarpoonIndex = INDEX_NONE, optional Actor HarpoonActor) +{ + if (HarpoonIndex == INDEX_NONE) + { + if (HarpoonActor != none) + { + HarpoonIndex = DeployedHarpoons.Find(HarpoonActor); + } + } + + if (HarpoonIndex != INDEX_NONE) + { + DeployedHarpoons.Remove(HarpoonIndex, 1); + NumDeployedHarpoons = DeployedHarpoons.Length; + bForceNetUpdate = true; + } +} + +/** 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); +} + +defaultproperties +{ + // Content + PackageKey="Thermite" + FirstPersonMeshName="wep_1p_thermite_mesh.WEP_1stP_Thermite_Rig" + FirstPersonAnimSetNames(0)="wep_1p_thermite_anim.WEP_1stP_Thermite_Anim" + PickupMeshName="WEP_3P_Thermite_MESH.WEP_Thermite_Pickup" //@TODO: Replace me + AttachmentArchetypeName="wep_thermite_arch.Wep_Thermite_3P" + MuzzleFlashTemplateName="wep_thermite_arch.Wep_Thermite_MuzzleFlash" //@TODO: Replace me + + // Inventory / Grouping + InventorySize=7 + GroupPriority=100 + WeaponSelectTexture=Texture2D'WEP_UI_Thermite_TEX.UI_WeaponSelect_Thermite' + AssociatedPerkClasses(0)=class'KFPerk_Firebug' + + // FOV + MeshFOV=75 + MeshIronSightFOV=40 + PlayerIronSightFOV=65 + + // Depth of field + DOF_FG_FocalRadius=50 + DOF_FG_MaxNearBlurSize=3.5 + + // Ammo + MagazineCapacity[0]=6 + SpareAmmoCapacity[0]=36 //42 + InitialSpareMags[0]=1 + bCanBeReloaded=true + bReloadFromMagazine=true + + // Zooming/Position + PlayerViewOffset=(X=11.0,Y=8,Z=-2) + IronSightPosition=(X=10,Y=0,Z=0) + + // AI warning system + bWarnAIWhenAiming=true + AimWarningDelay=(X=0.4f, Y=0.8f) + AimWarningCooldown=0.0f + + // Recoil + maxRecoilPitch=500 + minRecoilPitch=400 + maxRecoilYaw=150 + minRecoilYaw=-150 + 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 + + // DEFAULT_FIREMODE + FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletSingle' + FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring + WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile + WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Rocket_ThermiteBore' + InstantHitDamage(DEFAULT_FIREMODE)=150 + InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_ThermiteBoreImpact' + FireInterval(DEFAULT_FIREMODE)=0.8 //100 RPM + Spread(DEFAULT_FIREMODE)=0 + PenetrationPower(DEFAULT_FIREMODE)=0 + FireOffset=(X=25,Y=3.0,Z=-2.5) + + // ALTFIRE_FIREMODE (remote detonate) + FiringStatesArray(ALTFIRE_FIREMODE)=WeaponDetonating + WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Custom + AmmoCost(ALTFIRE_FIREMODE)=0 + + // BASH_FIREMODE + InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_ThermiteBore' + InstantHitDamage(BASH_FIREMODE)=26 + + // Custom animations + FireSightedAnims=(Shoot_Iron) + BonesToLockOnEmpty=(RW_Exhaust, RW_BoltAssembly1, RW_BoltAssembly2, RW_BoltAssembly3) + bHasFireLastAnims=true + + // Fire Effects + WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Thermite.Play_WEP_Thermite_Thermite_Shoot_3P', FirstPersonCue=AkEvent'WW_WEP_Thermite.Play_WEP_Thermite_Thermite_Shoot_1P') + WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_Thermite.Play_WEP_Thermite_Dry_Fire' + EjectedShellForegroundDuration=1.5f + + // Attachments + bHasIronSights=true + bHasFlashlight=false + + WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Medium_Recoil' + + WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.125f), (Stat=EWUS_Weight, Add=1))) + + SelfDamageReductionValue=0.05f //0.25f + + DetonateAnim=Alt_Fire + DetonateAnimLast=Alt_Fire_Last + DetonateAnimIron=Alt_Fire_Iron + DetonateAnimIronLast=Alt_Fire_Iron_Last +} diff --git a/OnlineSubsystemDingo/Classes/OnlineMarketplaceInterfaceDingo.uc b/OnlineSubsystemDingo/Classes/OnlineMarketplaceInterfaceDingo.uc index fdf733e..af8a253 100644 --- a/OnlineSubsystemDingo/Classes/OnlineMarketplaceInterfaceDingo.uc +++ b/OnlineSubsystemDingo/Classes/OnlineMarketplaceInterfaceDingo.uc @@ -348,7 +348,7 @@ cpptext defaultproperties { - // as of February 2021 + // as of May 2021 ConsumablesCount=80 - DurablesCount=60 + DurablesCount=66 } \ No newline at end of file