658 lines
19 KiB
Ucode
658 lines
19 KiB
Ucode
//=============================================================================
|
|
// KFMapObjective_EscortPawns
|
|
//=============================================================================
|
|
// Objective type for escorting pawns. Pawns can be spawned in sequence or at
|
|
// the same time and need to be defended.
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2018 Tripwire Interactive LLC
|
|
//=============================================================================
|
|
|
|
class KFMapObjective_EscortPawns extends KFMapObjective_ActorBase;
|
|
|
|
// Scripted pawn spawners that will spawn the escorts related to this objective
|
|
var() array<KFScriptedPawnSpawner> EscortPawnSpawners;
|
|
/** How many escorts need to be escorted successfully for the objective to be completed. */
|
|
var() int NumEscortsRequired;
|
|
var int NumEscortsAccomplished;
|
|
var int NumEscortsFinished;
|
|
var float Progress;
|
|
var repnotify transient Actor ActiveEscortActor;
|
|
var float CompletionPct;
|
|
|
|
// Sound to play when escort is 100% done and in perfect health
|
|
var() AkEvent ProgressSoundEvent100pctPerfect;
|
|
// Sound to play when escort is 100% done
|
|
var() AkEvent ProgressSoundEvent100pct;
|
|
// Sound to play when escort is 100% done and in poor health
|
|
var() AkEvent ProgressSoundEvent100pctPoor;
|
|
// Sound to play when escort is 85% done and in perfect health
|
|
var() AkEvent ProgressSoundEvent85pctPerfect;
|
|
// Sound to play when escort is 85% done
|
|
var() AkEvent ProgressSoundEvent85pct;
|
|
// Sound to play when escort is 85% done and in poor health
|
|
var() AkEvent ProgressSoundEvent85pctPoor;
|
|
// Sound to play when escort is 50% done and in perfect health
|
|
var() AkEvent ProgressSoundEvent50pctPerfect;
|
|
// Sound to play when escort is 50% done
|
|
var() AkEvent ProgressSoundEvent50pct;
|
|
// Sound to play when escort is 50% done and in poor health
|
|
var() AkEvent ProgressSoundEvent50pctPoor;
|
|
// Sound to play when escort is 25% done and in perfect health
|
|
var() AkEvent ProgressSoundEvent25pctPerfect;
|
|
// Sound to play when escort is 25% done
|
|
var() AkEvent ProgressSoundEvent25pct;
|
|
// Sound to play when escort is 25% done and in poor health
|
|
var() AkEvent ProgressSoundEvent25pctPoor;
|
|
// Percentage of escort health considered to be "poor," used for the "poor" progress sound events
|
|
var() float PoorHealthPctThreshold;
|
|
|
|
// Sound to play when escort takes damage
|
|
var() AkEvent EscortPawnTakeDamageEvent;
|
|
// Cooldown period for the "take damage" sound event
|
|
var() float EscortPawnTakeDamageEventCooldown;
|
|
// Sound to play to remind players that escort is in critical condition
|
|
var() AkEvent EscortPawnCriticalReminderEvent;
|
|
// How frequently to remind players that escort is in critical condition
|
|
var() float EscortPawnCriticalReminderEventInterval;
|
|
|
|
var repnotify int CompletionProgressIdx, HealthProgressIdx;
|
|
|
|
replication
|
|
{
|
|
if (bNetDirty)
|
|
Progress, ActiveEscortActor, CompletionPct, CompletionProgressIdx, HealthProgressIdx;
|
|
}
|
|
|
|
simulated function ReplicatedEvent(name VarName)
|
|
{
|
|
switch (VarName)
|
|
{
|
|
case nameof(ActiveEscortActor):
|
|
UpdateTrailActor();
|
|
break;
|
|
|
|
case nameof(CompletionProgressIdx):
|
|
TriggerCompletionPctProgress();
|
|
break;
|
|
|
|
case nameof(HealthProgressIdx):
|
|
TriggerHealthPctProgress();
|
|
break;
|
|
|
|
default:
|
|
super.ReplicatedEvent(VarName);
|
|
};
|
|
}
|
|
|
|
function CheckCompletionPctProgress(float PrevCompletionPct, float CurrCompletionPct)
|
|
{
|
|
local int PrevCompletionProgressIdx, GenEvtIdx, i;
|
|
local KFSeqEvent_EscortPawnsCompletionPct GenEvt;
|
|
|
|
PrevCompletionProgressIdx = CompletionProgressIdx;
|
|
|
|
// check the first applicable generated event (assumes all applicable events are identical)
|
|
for (GenEvtIdx = 0; GenEvtIdx < GeneratedEvents.Length; GenEvtIdx++)
|
|
{
|
|
GenEvt = KFSeqEvent_EscortPawnsCompletionPct(GeneratedEvents[GenEvtIdx]);
|
|
if (GenEvt != None)
|
|
{
|
|
for (i = 0; i < GenEvt.ProgressThresholds.Length; i++)
|
|
{
|
|
if (PrevCompletionPct < GenEvt.ProgressThresholds[i] &&
|
|
CurrCompletionPct >= GenEvt.ProgressThresholds[i])
|
|
{
|
|
CompletionProgressIdx = GenEvt.ProgressOutputStartIndex + i;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CompletionProgressIdx != PrevCompletionProgressIdx)
|
|
{
|
|
TriggerCompletionPctProgress();
|
|
}
|
|
}
|
|
|
|
simulated function TriggerCompletionPctProgress()
|
|
{
|
|
local int GenEvtIdx;
|
|
local KFSeqEvent_EscortPawnsCompletionPct GenEvt;
|
|
local array<int> ActivateIndices;
|
|
|
|
ActivateIndices.AddItem(CompletionProgressIdx);
|
|
|
|
// notify all applicable generated events (assumes all applicable events are identical)
|
|
for (GenEvtIdx = 0; GenEvtIdx < GeneratedEvents.Length; GenEvtIdx++)
|
|
{
|
|
GenEvt = KFSeqEvent_EscortPawnsCompletionPct(GeneratedEvents[GenEvtIdx]);
|
|
if (GenEvt != None)
|
|
{
|
|
GenEvt.Reset();
|
|
GenEvt.CheckActivate(self, self,, ActivateIndices);
|
|
}
|
|
}
|
|
}
|
|
|
|
function CheckHealthPctProgress(float PrevHealthPct, float CurrHealthPct)
|
|
{
|
|
local int PrevHealthProgressIdx, GenEvtIdx, i;
|
|
local KFSeqEvent_EscortPawnsHealthPct GenEvt;
|
|
|
|
PrevHealthProgressIdx = HealthProgressIdx;
|
|
|
|
// check the first applicable generated event (assumes all applicable events are identical)
|
|
for (GenEvtIdx = 0; GenEvtIdx < GeneratedEvents.Length; GenEvtIdx++)
|
|
{
|
|
GenEvt = KFSeqEvent_EscortPawnsHealthPct(GeneratedEvents[GenEvtIdx]);
|
|
if (GenEvt != None)
|
|
{
|
|
if (GenEvt.bUseReverseProgress)
|
|
{
|
|
for (i = 0; i < GenEvt.ProgressThresholds.Length; i++)
|
|
{
|
|
if (PrevHealthPct >= GenEvt.ProgressThresholds[i] &&
|
|
CurrHealthPct < GenEvt.ProgressThresholds[i])
|
|
{
|
|
// set idx negative for reverse progress
|
|
// add 1 to keep idx from being 0, since 0 is ambiguous
|
|
HealthProgressIdx = -(GenEvt.ProgressOutputStartIndex + i + 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < GenEvt.ProgressThresholds.Length; i++)
|
|
{
|
|
if (PrevHealthPct < GenEvt.ProgressThresholds[i] &&
|
|
CurrHealthPct >= GenEvt.ProgressThresholds[i])
|
|
{
|
|
// add 1 to keep idx from being 0, since 0 is ambiguous
|
|
HealthProgressIdx = GenEvt.ProgressOutputStartIndex + i + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (HealthProgressIdx != PrevHealthProgressIdx)
|
|
{
|
|
TriggerHealthPctProgress();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function TriggerHealthPctProgress()
|
|
{
|
|
local int GenEvtIdx;
|
|
local KFSeqEvent_EscortPawnsHealthPct GenEvt;
|
|
local array<int> ActivateIndices;
|
|
|
|
// subtract the 1 that we added in CheckHealthPctProgress
|
|
ActivateIndices.AddItem(Max(HealthProgressIdx, -HealthProgressIdx) - 1);
|
|
|
|
// notify all applicable generated events (assumes all applicable events are identical)
|
|
for (GenEvtIdx = 0; GenEvtIdx < GeneratedEvents.Length; GenEvtIdx++)
|
|
{
|
|
GenEvt = KFSeqEvent_EscortPawnsHealthPct(GeneratedEvents[GenEvtIdx]);
|
|
if (GenEvt != None)
|
|
{
|
|
if ((GenEvt.bUseReverseProgress && HealthProgressIdx < 0) ||
|
|
(!GenEvt.bUseReverseProgress && HealthProgressIdx > 0))
|
|
{
|
|
GenEvt.Reset();
|
|
GenEvt.CheckActivate(self, self,, ActivateIndices);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Interface functions
|
|
|
|
simulated function ActivateObjective()
|
|
{
|
|
local KFScriptedPawnSpawner EscortPawnStart;
|
|
|
|
super.ActivateObjective();
|
|
|
|
if (Role == ROLE_Authority)
|
|
{
|
|
bIsActive = true;
|
|
NumEscortsAccomplished = 0;
|
|
NumEscortsFinished = 0;
|
|
|
|
// set delegates to help keep track of objective progress
|
|
foreach EscortPawnSpawners(EscortPawnStart)
|
|
{
|
|
EscortPawnStart.Delegate_OnPawnStartedRoute = OnEscortStarted;
|
|
EscortPawnStart.Delegate_OnPawnReachedRouteMarker = OnEscortReachedRouteMarker;
|
|
EscortPawnStart.Delegate_OnPawnReachedGoal = OnEscortReachedGoal;
|
|
EscortPawnStart.Delegate_OnPawnEndedRoute = OnEscortEndedRoute;
|
|
|
|
// reset progress goals if this has already been completed once
|
|
if (EscortPawnStart.bReachedGoal)
|
|
{
|
|
EscortPawnStart.bReachedStart = false;
|
|
EscortPawnStart.bReachedGoal = false;
|
|
EscortPawnStart.RouteDistTraversed = 0;
|
|
}
|
|
|
|
// make sure to set up any scripted pawns that were spawned before the objective started
|
|
if (EscortPawnStart.Pawn != none && EscortPawnStart.bReachedStart)
|
|
{
|
|
OnEscortStarted(EscortPawnStart.Pawn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function DeactivateObjective()
|
|
{
|
|
local KFPawn_Human KFPH;
|
|
|
|
super.DeactivateObjective();
|
|
|
|
if (Role == ROLE_Authority)
|
|
{
|
|
bIsActive = false;
|
|
|
|
if (NumEscortsAccomplished >= NumEscortsRequired)
|
|
{
|
|
foreach WorldInfo.AllPawns(class'KFPawn_Human', KFPH)
|
|
{
|
|
GrantReward(KFPlayerReplicationInfo(KFPH.PlayerReplicationInfo), KFPlayerController(KFPH.Controller));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FailureSoundEvent != none)
|
|
{
|
|
PlaySoundBase(FailureSoundEvent, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (WorldInfo.NetMode != NM_DedicatedServer)
|
|
{
|
|
if (TrailActor != none)
|
|
{
|
|
TrailActor.Destroy();
|
|
TrailActor = none;
|
|
}
|
|
|
|
if (ActiveEscortActor != none)
|
|
{
|
|
KFPawn_Scripted(ActiveEscortActor).RemoveEscortPawnOnHud();
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function bool IsActive()
|
|
{
|
|
return bIsActive;
|
|
}
|
|
|
|
simulated function bool UsesProgress()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
simulated function bool IsBonus();
|
|
|
|
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 float GetProgress()
|
|
{
|
|
return FClamp(Progress, 0.f, 1.f);
|
|
}
|
|
|
|
simulated function bool IsComplete()
|
|
{
|
|
return GetProgress() >= 1.f;
|
|
}
|
|
|
|
simulated function float GetActivationPctChance()
|
|
{
|
|
return 1.f;
|
|
}
|
|
|
|
simulated function string GetProgressText()
|
|
{
|
|
return int(GetProgress() * 100) $ "%";
|
|
}
|
|
|
|
simulated function string GetLocalizedRequirements()
|
|
{
|
|
return "";
|
|
}
|
|
|
|
simulated function GetLocalizedStatus(out string statusMessage, out int bWarning, out int bNotification)
|
|
{
|
|
local KFPawn_Scripted ActiveScriptedPawn;
|
|
|
|
statusMessage = "";
|
|
if (GetProgress() >= 1.f)
|
|
{
|
|
statusMessage = Localize("Objectives", "KillRemainingZeds", LocalizationPackageName);
|
|
bWarning = 0;
|
|
bNotification = 0;
|
|
return;
|
|
}
|
|
|
|
ActiveScriptedPawn = KFPawn_Scripted(ActiveEscortActor);
|
|
if (ActiveScriptedPawn != none)
|
|
{
|
|
if (ActiveScriptedPawn.GetHealthPercent() <= 0.01f)
|
|
{
|
|
statusMessage = Localize("Objectives", "NeedsRepair", LocalizationPackageName);
|
|
bWarning = 1;
|
|
return;
|
|
}
|
|
else if (ActiveScriptedPawn.GetHealthPercent() <= 0.25f)
|
|
{
|
|
statusMessage = Localize("Objectives", "LowHealth", LocalizationPackageName);
|
|
bWarning = 1;
|
|
return;
|
|
}
|
|
|
|
if (ActiveScriptedPawn.SpeedScalarForObstacles <= 0.0f)
|
|
{
|
|
statusMessage = Localize("Objectives", "Stopped", LocalizationPackageName);
|
|
bWarning = 1;
|
|
return;
|
|
}
|
|
|
|
if (ActiveScriptedPawn.IsBlockedByZed())
|
|
{
|
|
statusMessage = Localize("Objectives", "Blocked", LocalizationPackageName);
|
|
bWarning = 1;
|
|
return;
|
|
}
|
|
|
|
if (ActiveScriptedPawn.WasAttackedRecently())
|
|
{
|
|
statusMessage = Localize("Objectives", "BeingAttacked", LocalizationPackageName);
|
|
bWarning = 1;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function bool ShouldDrawIcon(){}
|
|
|
|
simulated function Vector GetIconLocation(){}
|
|
|
|
simulated function Texture2D GetIcon()
|
|
{
|
|
if (ActiveEscortActor != none)
|
|
{
|
|
return KFPawn_Scripted(ActiveEscortActor).GetStateIconTexture();
|
|
}
|
|
return DefaultIcon;
|
|
}
|
|
|
|
// Non-interface functions
|
|
|
|
function OnEscortStarted(KFPawn_Scripted StartedPawn)
|
|
{
|
|
ActiveEscortActor = StartedPawn;
|
|
StartedPawn.SetActive(true);
|
|
UpdateTrailActor();
|
|
|
|
StartedPawn.Delegate_OnTakeDamage = OnEscortTakeDamage;
|
|
StartedPawn.Delegate_OnHealDamage = OnEscortHealDamage;
|
|
StartedPawn.Delegate_OnChangeState = OnEscortChangeState;
|
|
|
|
OnEscortChangeState(0, 0);
|
|
}
|
|
|
|
function OnEscortReachedRouteMarker(int MarkerIdx, SplineActor Marker, int SubIdx)
|
|
{
|
|
local float PawnsProgress;
|
|
local KFScriptedPawnSpawner EscortPawnSpawner;
|
|
local float ActivePawnHealthPct;
|
|
|
|
foreach EscortPawnSpawners(EscortPawnSpawner)
|
|
{
|
|
PawnsProgress += EscortPawnSpawner.GetProgress() / float(EscortPawnSpawners.Length);
|
|
}
|
|
|
|
ActivePawnHealthPct = float(KFPawn_Scripted(ActiveEscortActor).Health) / float(KFPawn_Scripted(ActiveEscortActor).HealthMax);
|
|
|
|
CheckCompletionPctProgress(Progress, PawnsProgress);
|
|
|
|
CompletionPct = ActivePawnHealthPct;
|
|
|
|
if (Progress < 0.25 && PawnsProgress >= 0.25)
|
|
{
|
|
if (ActivePawnHealthPct > 0.99 && ProgressSoundEvent25pctPerfect != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent25pctPerfect, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
else if (ActivePawnHealthPct > PoorHealthPctThreshold && ProgressSoundEvent25pct != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent25pct, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
else if (ProgressSoundEvent25pctPoor != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent25pctPoor, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
}
|
|
else if (Progress < 0.5 && PawnsProgress >= 0.5)
|
|
{
|
|
if (ActivePawnHealthPct > 0.99 && ProgressSoundEvent50pctPerfect != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent50pctPerfect, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
else if (ActivePawnHealthPct > PoorHealthPctThreshold && ProgressSoundEvent50pct != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent50pct, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
else if (ProgressSoundEvent50pctPoor != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent50pctPoor, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
}
|
|
else if (Progress < 0.85 && PawnsProgress >= 0.85)
|
|
{
|
|
if (ActivePawnHealthPct > 0.99 && ProgressSoundEvent85pctPerfect != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent85pctPerfect, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
else if (ActivePawnHealthPct > PoorHealthPctThreshold && ProgressSoundEvent85pct != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent85pct, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
else if (ProgressSoundEvent85pctPoor != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent85pctPoor, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
}
|
|
else if (Progress < 1.0 && PawnsProgress >= 1.0)
|
|
{
|
|
if (ActivePawnHealthPct > 0.99 && ProgressSoundEvent100pctPerfect != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent100pctPerfect, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
else if (ActivePawnHealthPct > PoorHealthPctThreshold && ProgressSoundEvent100pct != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent100pct, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
else if (ProgressSoundEvent100pctPoor != none)
|
|
{
|
|
PlaySoundBase(ProgressSoundEvent100pctPoor, false, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
}
|
|
|
|
Progress = PawnsProgress;
|
|
}
|
|
|
|
function OnEscortReachedGoal()
|
|
{
|
|
OnEscortEndedRoute(true);
|
|
}
|
|
|
|
function OnEscortEndedRoute(bool bSuccess)
|
|
{
|
|
local KFGameReplicationInfo KFGRI;
|
|
|
|
++NumEscortsFinished;
|
|
|
|
if (bSuccess)
|
|
{
|
|
++NumEscortsAccomplished;
|
|
TriggerObjectiveProgressEvent();
|
|
}
|
|
|
|
if ((NumEscortsAccomplished >= NumEscortsRequired) ||
|
|
(NumEscortsFinished == EscortPawnSpawners.Length) ||
|
|
(((EscortPawnSpawners.Length - NumEscortsFinished) + NumEscortsAccomplished) < NumEscortsRequired))
|
|
{
|
|
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
|
|
if (KFGRI != none)
|
|
{
|
|
Progress = 1.0f; // ensure this is set to completed
|
|
KFGRI.DeactivateObjective();
|
|
}
|
|
}
|
|
|
|
ActiveEscortActor = none;
|
|
UpdateTrailActor();
|
|
|
|
ClearTimer(nameof(Timer_EscortPawnTakeDamageEventCooldown));
|
|
ClearTimer(nameof(Timer_EscortPawnCriticalReminderEventInterval));
|
|
}
|
|
|
|
function OnEscortTakeDamage(int Damage)
|
|
{
|
|
local KFPawn_Scripted KFPS;
|
|
local float PrevHealthPct, CurrHealthPct;
|
|
|
|
if (EscortPawnTakeDamageEvent != none && !IsTimerActive(nameof(Timer_EscortPawnTakeDamageEventCooldown)))
|
|
{
|
|
PlaySoundBase(EscortPawnTakeDamageEvent,, WorldInfo.NetMode == NM_DedicatedServer);
|
|
SetTimer(EscortPawnTakeDamageEventCooldown, false, nameof(Timer_EscortPawnTakeDamageEventCooldown));
|
|
}
|
|
|
|
KFPS = KFPawn_Scripted(ActiveEscortActor);
|
|
PrevHealthPct = float(KFPS.Health + Damage) / float(KFPS.HealthMax);
|
|
CurrHealthPct = float(KFPS.Health) / float(KFPS.HealthMax);
|
|
|
|
CheckHealthPctProgress(PrevHealthPct, CurrHealthPct);
|
|
}
|
|
|
|
function Timer_EscortPawnTakeDamageEventCooldown()
|
|
{
|
|
// this function is just here to allow us to set a timer, which we check the activity of
|
|
}
|
|
|
|
function OnEscortHealDamage(int HealAmount)
|
|
{
|
|
local KFPawn_Scripted KFPS;
|
|
local float PrevHealthPct, CurrHealthPct;
|
|
|
|
KFPS = KFPawn_Scripted(ActiveEscortActor);
|
|
PrevHealthPct = float(KFPS.Health - HealAmount) / float(KFPS.HealthMax);
|
|
CurrHealthPct = float(KFPS.Health) / float(KFPS.HealthMax);
|
|
|
|
CheckHealthPctProgress(PrevHealthPct, CurrHealthPct);
|
|
}
|
|
|
|
function OnEscortChangeState(int CurrState, int PrevState)
|
|
{
|
|
if (KFPawn_Scripted(ActiveEscortActor).IsInCriticalCondition())
|
|
{
|
|
if (EscortPawnCriticalReminderEvent != none && !IsTimerActive(nameof(Timer_EscortPawnCriticalReminderEventInterval)))
|
|
{
|
|
SetTimer(EscortPawnCriticalReminderEventInterval, true, nameof(Timer_EscortPawnCriticalReminderEventInterval));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ClearTimer(nameof(Timer_EscortPawnCriticalReminderEventInterval));
|
|
}
|
|
}
|
|
|
|
function Timer_EscortPawnCriticalReminderEventInterval()
|
|
{
|
|
PlaySoundBase(EscortPawnCriticalReminderEvent,, WorldInfo.NetMode == NM_DedicatedServer);
|
|
}
|
|
|
|
simulated function UpdateTrailActor()
|
|
{
|
|
if (bUseTrailToObjective && WorldInfo.NetMode != NM_DedicatedServer)
|
|
{
|
|
if (TrailActor == none)
|
|
{
|
|
TrailActor = class'WorldInfo'.static.GetWorldInfo().Spawn(class'KFReplicatedShowPathActor', none);
|
|
TrailActor.SetEmitterTemplate(ParticleSystem'FX_Gameplay_EMIT.FX_Objective_White_Trail');
|
|
}
|
|
|
|
TrailActor.SetPathTarget(ActiveEscortActor);
|
|
}
|
|
}
|
|
|
|
simulated function bool GetIsMissionCritical()
|
|
{
|
|
return bIsMissionCriticalObjective;
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
bIsMissionCriticalObjective=true
|
|
LocalizationKey="EscortPawnsObjective"
|
|
DescriptionLocKey="EscortPawnsDescription"
|
|
NameShortLocKey="EscortPawnsObjective"
|
|
DescriptionShortLocKey="EscortPawnsDescriptionShort"
|
|
|
|
bAlwaysRelevant=true
|
|
RemoteRole=ROLE_SimulatedProxy
|
|
|
|
Begin Object Class=SpriteComponent Name=Sprite
|
|
Sprite=Texture2D'EditorResources.S_Actor'
|
|
HiddenGame=True
|
|
AlwaysLoadOnClient=False
|
|
AlwaysLoadOnServer=False
|
|
End Object
|
|
Components.Add(Sprite)
|
|
|
|
GameModeBlacklist.Add(class'KFGameInfo_Endless')
|
|
GameModeBlacklist.Add(class'KFGameInfo_WeeklySurvival')
|
|
|
|
PerPlayerSpawnRateMod=(1.f, 1.f, 1.f, 1.f, 1.f, 1.f)
|
|
|
|
DefaultIcon=Texture2D'Objectives_UI.UI_Objectives_ObjectiveMode'
|
|
|
|
PoorHealthPctThreshold=0.5
|
|
|
|
LocalizationPackageName="KFGame"
|
|
|
|
CompletionProgressIdx=999
|
|
HealthProgressIdx=999
|
|
|
|
SupportedEvents.Add(class'KFSeqEvent_EscortPawnsCompletionPct')
|
|
SupportedEvents.Add(class'KFSeqEvent_EscortPawnsHealthPct')
|
|
} |