//============================================================================= // KFMapObjective_ActivateTrigger //============================================================================= // Objective for Biodome for Airship. The player has to activate a trigger n // times for the objective to be complete. Zeds in the volume will stop the // trigger from being activated. //============================================================================= // Killing Floor 2 // Copyright (C) 2018 Tripwire Interactive LLC //============================================================================= class KFMapObjective_ActivateTrigger extends KFMapObjective_AreaDefense; /** How many times the players have pulled the trigger. */ var repnotify int TriggerPulls; /** How many times a trigger has to be pulled until the objective is complete, per number of players */ var() const int TriggerPullsRequiredForPlayerCount[6]; /** How many times a trigger has to be pulled until the objective is complete. */ var int TriggerPullsRequired; /** Reference to the trigger that we may need to override. */ var() KFTrigger_ObjectiveLever ObjectiveLever; /** A delay from the the start of an objective, so the player can't automatically pull the lever. */ var() float ActivationDelay; /** A sound to play when the trigger is ready to be triggered (e.g. after activation delay or trigger reset delay) */ var() array TriggerReadySoundEvents; /** A sound to play when the trigger is pulled */ var() array TriggerPulledSoundEvents; /** A sound to play when the objective is fully complete */ var() AkEvent SuccessSoundEvent100pct; /** A sound to play when the objective is mostly complete */ var() AkEvent SuccessSoundEvent85pct; /** A sound to play when the objective is adequately complete */ var() AkEvent SuccessSoundEvent50pct; /** A sound to play when the objective is barely complete */ var() AkEvent SuccessSoundEvent25pct; /** Sound event to play when players are engaged with too many zeds in the zone */ var() AkEvent TooManyZedsSoundEvent; /** Sound event to play when too few players are in the zone */ var() AkEvent TooFewPlayersSoundEvent; /** How often to remind players about the objective if they aren't engaged in completing it */ var() float RemindPlayersTime; /** A sound to play when enough players are in the zone, few enough zeds are in the zone, and players are still not pulling the readied trigger */ var() array TriggerReminderSoundEvents; /** How often to remind players that the trigger is ready to be pulled */ var() float ReadyTriggerReminderTime; var transient bool bObjectiveLeverActiveBefore; var transient bool bObjectiveLeverBlessedBefore; /** Incremented whenever the lever gets activated, used to kick off a kismet node */ var repnotify int nNumLeversActivated; /** Set to true whenever the lever is ready to be pulled */ var bool bLeverReady; /** Whether any players are on the objective */ var repnotify bool bNoPlayers; /** Color for the objective progress icon when it is ready/not ready */ var const color ReadyIconColor; var const color NotReadyIconColor; /** Whether the trigger is allowed to be interacted with */ var bool bInteractable; replication { if(bNetDirty) TriggerPulls, TriggerPullsRequired, nNumLeversActivated, bNoPlayers, bInteractable; } simulated event ReplicatedEvent(name VarName) { if (VarName == nameof(TriggerPulls)) { if (TriggerPulls != 0) { TriggerObjectiveProgressEvent(EActivateTriggerProgressEvent_TriggerPulled, float(TriggerPulls)/float(TriggerPullsRequired)); bLeverReady = false; } } else if (VarName == nameof(nNumLeversActivated)) { TriggerObjectiveProgressEvent(EActivateTriggerProgressEvent_TriggerReady); bLeverReady = true; } else { super.ReplicatedEvent(VarName); } } simulated function ActivateObjective() { local int PlayerCount; if (ObjectiveLever != none) { ObjectiveLever.OwningObjective = self; } super.ActivateObjective(); if (Role == ROLE_Authority) { TriggerPulls = 0; PlayerCount = Clamp(KFGameInfo(WorldInfo.Game).GetLivingPlayerCount(), 1, 6) - 1; TriggerPullsRequired = TriggerPullsRequiredForPlayerCount[PlayerCount]; `log(self @ "-" @ GetFuncName() @ "- ActivationDelay:" @ ActivationDelay); if (ObjectiveLever != none) { ObjectiveLever.SetFathersBlessing(false); } bInteractable = false; if (ActivationDelay > 0.f) { SetTimer(ActivationDelay, false, 'ActivateTrigger'); } else { ActivateTrigger(); } CurrentRewardAmount = 0; bObjectiveLeverActiveBefore = false; bObjectiveLeverBlessedBefore = false; // don't allow "too few players" reminder to be played right away SetTimer(RemindPlayersTime, false, nameof(Timer_TooFewPlayersReminderCooldown)); } if (WorldInfo.NetMode != NM_DedicatedServer) { CheckTriggerActivation(); } } simulated function DeactivateObjective() { local KFPlayerController KFPC; local KFPawn_Human KFPH; super.DeactivateObjective(); if (Role == ROLE_Authority) { ClearTimer('Timer_CheckObjective'); bInteractable = false; if (ObjectiveLever != none) { // Lever should work as trap outside of objective. ObjectiveLever.SetFathersBlessing(true); } if (CurrentRewardAmount > 0) { foreach WorldInfo.AllPawns(class'KFPawn_Human', KFPH) { GrantReward(KFPlayerReplicationInfo(KFPH.PlayerReplicationInfo), KFPlayerController(KFPH.Controller)); } } PlayDeactivationDialog(); } KFPC = KFPlayerController(GetALocalPlayerController()); if (KFPC != none && KFPC.MyGFxHUD != none) { KFPC.MyGFxHUD.WaveInfoWidget.ObjectiveContainer.SetFailState(CurrentRewardAmount <= 0); } } function PlayDeactivationDialog() { if (CurrentRewardAmount <= 0) { PlaySoundBase(FailureSoundEvent, false, WorldInfo.NetMode == NM_DedicatedServer); BroadcastLocalizedMessage(class'KFLocalMessage_Priority', GMT_ObjectiveLost); } else { if (GetProgress() <= JustWinThreshold) { PlaySoundBase(SuccessSoundEvent25pct, false, WorldInfo.NetMode == NM_DedicatedServer); } else if (GetProgress() <= StandardWinThreshold) { PlaySoundBase(SuccessSoundEvent50pct, false, WorldInfo.NetMode == NM_DedicatedServer); } else if (GetProgress() <= GoodWinThreshold) { PlaySoundBase(SuccessSoundEvent85pct, false, WorldInfo.NetMode == NM_DedicatedServer); } else { PlaySoundBase(SuccessSoundEvent100pct, false, WorldInfo.NetMode == NM_DedicatedServer); } } } simulated function ActivateTrigger() { local int PlayerCount; `log(self @ "-" @ GetFuncName()); bInteractable = true; if (ObjectiveLever != none) { PlayerCount = Clamp(KFGameInfo(WorldInfo.Game).GetLivingPlayerCount(), 1, 6) - 1; ObjectiveLever.SetFathersBlessing(TouchingZeds.length < ZedThresholds[PlayerCount] && TouchingHumans.Length >= PlayerThresholds[PlayerCount]); } nNumLeversActivated++; TriggerObjectiveProgressEvent(EActivateTriggerProgressEvent_TriggerReady); SetTimer(0.25f, true, 'Timer_CheckObjective'); // don't allow "trigger ready" reminder to play right away SetTimer(ReadyTriggerReminderTime, false, nameof(Timer_TriggerReadyReminderCooldown)); } //----------------------------------------------------------------------------- // Volume //----------------------------------------------------------------------------- event Touch(Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal) { local int PlayerCount; super.Touch(Other, OtherComp, HitLocation, HitNormal); PlayerCount = Clamp(KFGameInfo(WorldInfo.Game).GetLivingPlayerCount(), 1, 6) - 1; if (TouchingZeds.Length >= ZedThresholds[PlayerCount]) { if (ObjectiveLever != none && bActive && bInteractable) { ObjectiveLever.SetFathersBlessing(false); CheckTriggerActivation(); } } else if (TouchingHumans.Length >= PlayerThresholds[PlayerCount]) { if (ObjectiveLever != none && bActive && bInteractable) { ObjectiveLever.SetFathersBlessing(true); CheckTriggerActivation(); } } } event UnTouch(Actor Other) { local int PlayerCount; super.UnTouch(Other); PlayerCount = Clamp(KFGameInfo(WorldInfo.Game).GetLivingPlayerCount(), 1, 6) - 1; if (TouchingHumans.Length < PlayerThresholds[PlayerCount]) { if (ObjectiveLever != none && bActive && bInteractable) { ObjectiveLever.SetFathersBlessing(false); CheckTriggerActivation(); } } else if (TouchingZeds.Length < ZedThresholds[PlayerCount]) { if (ObjectiveLever != none && bActive && bInteractable) { ObjectiveLever.SetFathersBlessing(true); CheckTriggerActivation(); } } } simulated function Timer_CheckObjective() { local int i, PlayerCount; for (i = 0; i < TouchingZeds.length; i++) { if (!IsValidZed(TouchingZeds[i])) { TouchingZeds.Remove(i, 1); } } PlayerCount = Clamp(KFGameInfo(WorldInfo.Game).GetLivingPlayerCount(), 1, 6) - 1; if (bActive && bInteractable && ObjectiveLever != none) { ObjectiveLever.SetFathersBlessing(TouchingZeds.length < ZedThresholds[PlayerCount] && TouchingHumans.Length >= PlayerThresholds[PlayerCount]); CheckTriggerActivation(); } if(ObjectiveLever != none && ObjectiveLever.bAllowActivation && !bObjectiveLeverActiveBefore) { // reset reminder when the lever becomes ready again SetTimer(ReadyTriggerReminderTime, false, nameof(Timer_TriggerReadyReminderCooldown)); if (TriggerReadySoundEvents.Length > TriggerPulls) { PlaySoundBase(TriggerReadySoundEvents[TriggerPulls], , WorldInfo.NetMode == NM_DedicatedServer); } } bObjectiveLeverActiveBefore = ObjectiveLever.bAllowActivation; if (Role == ROLE_Authority) { bNoPlayers = TouchingHumans.Length <= 0; if (bActive && bInteractable) { PlayerCount = Clamp(KFGameInfo(WorldInfo.Game).GetLivingPlayerCount(), 1, 6) - 1; if (TouchingHumans.Length < PlayerThresholds[PlayerCount]) { if (!IsTimerActive(nameof(Timer_TooFewPlayersReminderCooldown))) { // trigger sound event if (TooFewPlayersSoundEvent != none) { PlaySoundBase(TooFewPlayersSoundEvent, , WorldInfo.NetMode == NM_DedicatedServer); } SetTimer(RemindPlayersTime, false, nameof(Timer_TooFewPlayersReminderCooldown)); } } if (TouchingZeds.Length > ZedThresholds[PlayerCount]) { if (!IsTimerActive(nameof(Timer_TooManyZedsReminderCooldown))) { if (TooManyZedsSoundEvent != none) { PlaySoundBase(TooManyZedsSoundEvent, , WorldInfo.NetMode == NM_DedicatedServer); } SetTimer(RemindPlayersTime, false, nameof(Timer_TooManyZedsReminderCooldown)); } } bTooFewPlayers = TouchingHumans.Length < PlayerThresholds[PlayerCount]; bTooManyZeds = TouchingZeds.Length > ZedThresholds[PlayerCount]; if (ObjectiveLever != none && ObjectiveLever.bAllowActivation) { if (TriggerPulls < TriggerReminderSoundEvents.Length && TriggerReminderSoundEvents[TriggerPulls] != none && !IsTimerActive(nameof(Timer_TriggerReadyReminderCooldown))) { if (TriggerReminderSoundEvents[TriggerPulls] != none) { PlaySoundBase(TriggerReminderSoundEvents[TriggerPulls], , WorldInfo.NetMode == NM_DedicatedServer); } SetTimer(ReadyTriggerReminderTime, false, nameof(Timer_TriggerReadyReminderCooldown)); } } } } } // These timer functions don't definitions, they just need to exist for SetTimer simulated function Timer_TooFewPlayersReminderCooldown(); simulated function Timer_TooManyZedsReminderCooldown(); simulated function Timer_TriggerReadyReminderCooldown(); simulated function OnTriggerActivated() { local KFGameReplicationInfo KFGRI; if (!bActive || !bInteractable) { return; } TriggerPulls++; TriggerObjectiveProgressEvent(EActivateTriggerProgressEvent_TriggerPulled, float(TriggerPulls) / float(TriggerPullsRequired)); if (Role == ROLE_Authority) { CurrentRewardAmount = GetMaxDoshReward() * GetProgress(); if (TriggerPulls <= TriggerPulledSoundEvents.Length) { PlaySoundBase(TriggerPulledSoundEvents[TriggerPulls-1],, WorldInfo.NetMode == NM_DedicatedServer); } } if (GetProgress() >= 1.f) { KFGRI = KFGameReplicationInfo(WorldInfo.GRI); if (KFGRI != none) { KFGRI.DeactivateObjective(); } } } simulated function OnTriggerReactivated() { CheckTriggerActivation(); nNumLeversActivated++; TriggerObjectiveProgressEvent(EActivateTriggerProgressEvent_TriggerReady); } simulated function CheckTriggerActivation() { bDangerState = false; if (ObjectiveLever != none) { bDangerState = !ObjectiveLever.bFathersBlessing; UpdateMeshArrayState(); ObjectiveLever.BroadcastInteractionMessages(); } } simulated function float GetProgress() { if (TriggerPullsRequired == 0) { return 0; } return float(TriggerPulls) / float(TriggerPullsRequired); } simulated function bool IsComplete() { return GetProgress() >= 1.f; } simulated function string GetLocalizedRequirements() { return Localize("Objectives", default.RequirementsLocKey, "KFGame") @ TriggerPullsRequired; } simulated function string GetProgressText() { if (!bActive) { return ""; } return TriggerPulls $ "/" $ TriggerPullsRequired; } simulated function GetLocalizedStatus(out string statusMessage, out int bWarning, out int bNotification) { statusMessage = ""; super.GetLocalizedStatus(statusMessage, bWarning, bNotification); if (statusMessage == "") { if (ObjectiveLever.ReadyToActivate() || bLeverReady) { statusMessage = Localize("Objectives", "Ready", LocalizationPackageName); bNotification = 1; bWarning = 0; return; } else { statusMessage = Localize("Objectives", "NotReady", LocalizationPackageName); bNotification = 0; bWarning = 1; return; } } } simulated function color GetIconColor() { // want to show the not ready color if stopped for some reason if (bTooManyZeds || (bTooFewPlayers && !bNoPlayers)) { return NotReadyIconColor; } // but want to show the normal color if exactly zero players on the objective if ((ROLE == ROLE_Authority && TouchingHumans.Length <= 0) || bNoPlayers) { return ObjectiveIconColor; } //otherwise if the lever is ready, choose that color if (ObjectiveLever.ReadyToActivate() || bLeverReady) { return ReadyIconColor; } return ObjectiveIconColor; } defaultproperties { DescriptionLocKey="DescriptionActivateTrigger" DescriptionShortLocKey = "DescriptionActivateTriggerShort" RequirementsLocKey="RequiredActivateTrigger" LocalizationKey="ActivateTrigger" NameShortLocKey="ActivateTrigger" GameModeBlacklist.Add(class'KFGameInfo_Endless') GameModeBlacklist.Add(class'KFGameInfo_WeeklySurvival') SupportedEvents.Add(class'KFSeqEvent_ActivateTriggerProgress') TriggerPullsRequired=6 ActivationDelay=5.f PlayerThresholds[0]=1 PlayerThresholds[1]=1 PlayerThresholds[2]=2 PlayerThresholds[3]=2 PlayerThresholds[4]=3 PlayerThresholds[5]=3 ZedThresholds[0]=6 ZedThresholds[1]=5 ZedThresholds[2]=4 ZedThresholds[3]=3 ZedThresholds[4]=2 ZedThresholds[5]=1 RemindPlayersTime=30.f ObjectiveIcon=Texture2D'Objectives_UI.UI_Objectives_ObjectiveMode' ReadyIconColor=(R=0, G=255, B=0, A=255); NotReadyIconColor=(R=255, G=0, B=0, A=255); }