2020-12-13 15:01:13 +00:00
|
|
|
//=============================================================================
|
|
|
|
// KFMapObjective_AreaDefense
|
|
|
|
//=============================================================================
|
|
|
|
// Base class for all map objectives that require the players to hold a volume.
|
|
|
|
//=============================================================================
|
|
|
|
// Killing Floor 2
|
|
|
|
// Copyright (C) 2018 Tripwire Interactive LLC
|
|
|
|
//=============================================================================
|
|
|
|
class KFMapObjective_AreaDefense extends KFMapObjective_VolumeBase
|
|
|
|
abstract;
|
|
|
|
|
|
|
|
/** List of touching humans maintained by touch/untouch events */
|
|
|
|
var array<KFPawn_Human> TouchingHumans;
|
|
|
|
var array<KFPawn_Monster> TouchingZeds;
|
|
|
|
|
|
|
|
/** Per-player thresholds for amount of players needed in the volume */
|
|
|
|
var() const int PlayerThresholds[6];
|
|
|
|
|
|
|
|
/** Per-player count thresholds for amount of zeds allowed in volume */
|
|
|
|
var() const int ZedThresholds[6];
|
|
|
|
|
|
|
|
/** Whether or not the zone is in the danger state */
|
|
|
|
var() repnotify bool bDangerState;
|
|
|
|
var repnotify bool bTooFewPlayers;
|
|
|
|
var repnotify bool bTooManyZeds;
|
|
|
|
|
|
|
|
/** Current reward amount */
|
|
|
|
var float CurrentRewardAmount;
|
|
|
|
|
|
|
|
/** Win thresholds - Named to match the VO tracks*/
|
|
|
|
var float JustWinThreshold;
|
|
|
|
var float StandardWinThreshold;
|
|
|
|
var float GoodWinThreshold;
|
|
|
|
|
|
|
|
replication
|
|
|
|
{
|
|
|
|
if (Role == ROLE_Authority)
|
|
|
|
CurrentRewardAmount, bDangerState, bTooFewPlayers, bTooManyZeds;
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated event ReplicatedEvent(name VarName)
|
|
|
|
{
|
|
|
|
if (VarName == 'bDangerState')
|
|
|
|
{
|
|
|
|
UpdateMeshArrayState();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
super.ReplicatedEvent(VarName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Volume
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
event Touch(Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal)
|
|
|
|
{
|
|
|
|
super.Touch(Other, OtherComp, HitLocation, HitNormal);
|
|
|
|
|
|
|
|
if (KFPawn_Human(Other) != none && TouchingHumans.Find(Other) == INDEX_NONE)
|
|
|
|
{
|
|
|
|
TouchingHumans.AddItem(KFPawn_Human(Other));
|
|
|
|
}
|
|
|
|
else if (IsValidZed(Other) && TouchingZeds.Find(Other) == INDEX_NONE)
|
|
|
|
{
|
|
|
|
TouchingZeds.AddItem(KFPawn_Monster(Other));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
event UnTouch(Actor Other)
|
|
|
|
{
|
|
|
|
super.UnTouch(Other);
|
|
|
|
|
|
|
|
if (TouchingHumans.Find(Other) != INDEX_NONE)
|
|
|
|
{
|
|
|
|
TouchingHumans.RemoveItem(Other);
|
|
|
|
}
|
|
|
|
else if (TouchingZeds.Find(Other) != INDEX_NONE)
|
|
|
|
{
|
|
|
|
TouchingZeds.RemoveItem(Other);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Status
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
simulated function UpdateMeshArrayState()
|
|
|
|
{
|
|
|
|
local int i, j, k;
|
|
|
|
|
|
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
|
|
{
|
|
|
|
for (i = 0; i < ZoneBoundaryMeshes.Length; ++i)
|
|
|
|
{
|
|
|
|
j = 0;
|
|
|
|
while (ZoneBoundaryMeshes[i].StaticMeshComponent.GetMaterial(j) != none)
|
|
|
|
{
|
|
|
|
MaterialInstance(ZoneBoundaryMeshes[i].StaticMeshComponent.GetMaterial(j)).SetScalarParameterValue(ZoneDangerMaterialParamName, bDangerState ? 1.f : 0.f);
|
|
|
|
++j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ZoneBoundarySplines.length; ++i)
|
|
|
|
{
|
|
|
|
if (ZoneBoundarySplines[i] != none)
|
|
|
|
{
|
|
|
|
for (j = 0; j < ZoneBoundarySplines[i].SplineMeshComps.length; ++j)
|
|
|
|
{
|
|
|
|
if (ZoneBoundarySplines[i].SplineMeshComps[j] != none)
|
|
|
|
{
|
|
|
|
k = 0;
|
|
|
|
while (ZoneBoundarySplines[i].SplineMeshComps[j].GetMaterial(k) != none)
|
|
|
|
{
|
|
|
|
MaterialInstance(ZoneBoundarySplines[i].SplineMeshComps[j].GetMaterial(k)).SetScalarParameterValue(ZoneDangerMaterialParamName, bDangerState ? 1.f : 0.f);
|
|
|
|
++k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function bool IsValidZed(Actor PotentialZed)
|
|
|
|
{
|
|
|
|
local KFPawn_Monster KFPM;
|
|
|
|
|
|
|
|
KFPM = KFPawn_Monster(PotentialZed);
|
|
|
|
if (KFPM == none)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (KFPM.Health <= 0 || KFPM.IsHeadless())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function ActivateObjective()
|
|
|
|
{
|
|
|
|
super.ActivateObjective();
|
|
|
|
|
|
|
|
if (Role == ROLE_Authority)
|
|
|
|
{
|
|
|
|
bActive = true;
|
|
|
|
CurrentRewardAmount = GetMaxDoshReward();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
|
|
{
|
|
|
|
UpdateMeshArrayState();
|
|
|
|
|
|
|
|
if (bUseTrailToVolume)
|
|
|
|
{
|
|
|
|
if (TrailActor == none)
|
|
|
|
{
|
|
|
|
TrailActor = class'WorldInfo'.static.GetWorldInfo().Spawn(class'KFReplicatedShowPathActor', none);
|
|
|
|
}
|
|
|
|
if (TrailActor != none)
|
|
|
|
{
|
|
|
|
TrailActor.SetEmitterTemplate(ParticleSystem'FX_Gameplay_EMIT.FX_Objective_White_Trail');
|
|
|
|
TrailActor.SetPathTarget(self, self, VCT_NotInVolume);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function DeactivateObjective()
|
|
|
|
{
|
|
|
|
super.DeactivateObjective();
|
|
|
|
|
|
|
|
if (Role == ROLE_Authority)
|
|
|
|
{
|
|
|
|
bActive = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
|
|
{
|
|
|
|
UpdateMeshArrayState();
|
|
|
|
|
|
|
|
if (bUseTrailToVolume && TrailActor != none)
|
|
|
|
{
|
|
|
|
TrailActor.Destroy();
|
|
|
|
TrailActor = none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function bool IsActive()
|
|
|
|
{
|
|
|
|
return bActive;
|
|
|
|
}
|
|
|
|
|
2022-05-11 15:13:25 +00:00
|
|
|
simulated function bool CanActivateObjectiveByWeekly()
|
|
|
|
{
|
|
|
|
if (Role == Role_Authority)
|
|
|
|
{
|
2022-09-01 15:58:51 +00:00
|
|
|
if (KFGameInfo(WorldInfo.Game).OutbreakEvent != none)
|
2022-05-11 15:13:25 +00:00
|
|
|
{
|
2023-09-21 19:31:11 +00:00
|
|
|
if (KFGameInfo(WorldInfo.Game).OutbreakEvent.ActiveEvent.bBossRushMode)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-01 15:58:51 +00:00
|
|
|
if (KFGameInfo(WorldInfo.Game).OutbreakEvent.ActiveEvent.bGunGameMode)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (KFGameInfo(WorldInfo.Game).OutbreakEvent.ActiveEvent.bVIPGameMode)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2023-09-21 19:31:11 +00:00
|
|
|
|
|
|
|
if (KFGameInfo(WorldInfo.Game).OutbreakEvent.ActiveEvent.bBountyHunt)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2022-05-11 15:13:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-09-01 15:58:51 +00:00
|
|
|
if (KFGameReplicationInfo(WorldInfo.GRI) != none && KFGameReplicationInfo(WorldInfo.GRI).bIsWeeklyMode)
|
2022-05-11 15:13:25 +00:00
|
|
|
{
|
2023-09-21 19:31:11 +00:00
|
|
|
if (KFGameReplicationInfo(WorldInfo.GRI).CurrentWeeklyIndex == 14)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-01 15:58:51 +00:00
|
|
|
if (KFGameReplicationInfo(WorldInfo.GRI).CurrentWeeklyIndex == 16)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (KFGameReplicationInfo(WorldInfo.GRI).CurrentWeeklyIndex == 17)
|
2023-09-21 19:31:11 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (KFGameReplicationInfo(WorldInfo.GRI).CurrentWeeklyIndex == 20)
|
2022-09-01 15:58:51 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2022-05-11 15:13:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-12-13 15:01:13 +00:00
|
|
|
function bool CanActivateObjective()
|
|
|
|
{
|
|
|
|
return !IsCurrentGameModeBlacklisted();
|
|
|
|
}
|
|
|
|
|
|
|
|
function bool IsCurrentGameModeBlacklisted()
|
|
|
|
{
|
|
|
|
local class<KFGameInfo> CurrGameClass;
|
|
|
|
|
|
|
|
foreach GameModeBlacklist(CurrGameClass)
|
|
|
|
{
|
|
|
|
if (CurrGameClass == WorldInfo.GRI.GameClass)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function bool UsesProgress()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function float GetProgress();
|
|
|
|
|
|
|
|
simulated function bool IsComplete()
|
|
|
|
{
|
|
|
|
return GetProgress() >= 1.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function float GetActivationPctChance()
|
|
|
|
{
|
|
|
|
return 1.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function bool IsBonus()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function int GetPlayersInObjective()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Rewards
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
simulated function int GetVoshReward()
|
|
|
|
{
|
|
|
|
local int MaxDoshReward;
|
|
|
|
|
|
|
|
MaxDoshReward = GetMaxDoshReward();
|
|
|
|
if (MaxDoshReward == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GetMaxVoshReward() * float(GetDoshReward()) / float(MaxDoshReward);
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function int GetXPReward()
|
|
|
|
{
|
|
|
|
local int MaxDoshReward;
|
|
|
|
|
|
|
|
MaxDoshReward = GetMaxDoshReward();
|
|
|
|
if (MaxDoshReward == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GetMaxXPReward() * float(GetDoshReward()) / float(MaxDoshReward);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// HUD
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
simulated function bool ShouldDrawIcon()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function Vector GetIconLocation()
|
|
|
|
{
|
|
|
|
return Location;
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function string GetLocalizedRequirements();
|
|
|
|
|
|
|
|
simulated function GetLocalizedStatus(out string statusMessage, out int bWarning, out int bNotification)
|
|
|
|
{
|
|
|
|
statusMessage = "";
|
|
|
|
|
|
|
|
if (GetProgress() >= 1.f)
|
|
|
|
{
|
|
|
|
statusMessage = Localize("Objectives", "KillRemainingZeds", LocalizationPackageName);
|
|
|
|
bWarning = 0;
|
|
|
|
bNotification = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bTooFewPlayers)
|
|
|
|
{
|
|
|
|
statusMessage = Localize("Objectives", "TooFewPlayers", LocalizationPackageName);
|
|
|
|
bWarning = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (bTooManyZeds)
|
|
|
|
{
|
|
|
|
statusMessage = Localize("Objectives", "TooManyZeds", LocalizationPackageName);
|
|
|
|
bWarning = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
simulated function string GetProgressText();
|
|
|
|
|
|
|
|
simulated function bool GetIsMissionCritical()
|
|
|
|
{
|
|
|
|
return bIsMissionCriticalObjective;
|
|
|
|
}
|
|
|
|
|
|
|
|
defaultproperties
|
|
|
|
{
|
|
|
|
bStatic=false
|
|
|
|
bAlwaysRelevant=true
|
|
|
|
RemoteRole=ROLE_SimulatedProxy
|
|
|
|
|
|
|
|
ZoneDangerMaterialParamName="Danger"
|
|
|
|
|
|
|
|
PerPlayerSpawnRateMod=(1.f, 1.f, 1.f, 1.f, 1.f, 1.f)
|
|
|
|
|
|
|
|
//These are basically range caps. For example:
|
|
|
|
// Just win would be 0% - 25%
|
|
|
|
// Standard win would be 25% - 50%
|
|
|
|
// Good win would be 50% - 85%
|
|
|
|
// Perfect win then assumes everything above good win
|
|
|
|
JustWinThreshold=0.25
|
|
|
|
StandardWinThreshold=0.5
|
|
|
|
GoodWinThreshold=0.85
|
|
|
|
LocalizationPackageName="KFGame"
|
|
|
|
}
|