//============================================================================= // 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 TouchingHumans; var array 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 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" }