1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFMapObjective_AreaDefense.uc
2022-09-01 18:58:51 +03:00

377 lines
8.6 KiB
Ucode

//=============================================================================
// 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;
}
simulated function bool CanActivateObjectiveByWeekly()
{
if (Role == Role_Authority)
{
if (KFGameInfo(WorldInfo.Game).OutbreakEvent != none)
{
if (KFGameInfo(WorldInfo.Game).OutbreakEvent.ActiveEvent.bGunGameMode)
{
return false;
}
if (KFGameInfo(WorldInfo.Game).OutbreakEvent.ActiveEvent.bVIPGameMode)
{
return false;
}
}
}
else
{
if (KFGameReplicationInfo(WorldInfo.GRI) != none && KFGameReplicationInfo(WorldInfo.GRI).bIsWeeklyMode)
{
if (KFGameReplicationInfo(WorldInfo.GRI).CurrentWeeklyIndex == 16)
{
return false;
}
if (KFGameReplicationInfo(WorldInfo.GRI).CurrentWeeklyIndex == 17)
{
return false;
}
}
}
return true;
}
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"
}