1
0
KF2-Dev-Scripts/KFGame/Classes/KFMapObjective_VolumeBase.uc
2020-12-13 18:01:13 +03:00

512 lines
13 KiB
Ucode

//=============================================================================
// KFMapObjective_VolumeBase
//=============================================================================
// Parent class for all volume-based objectives
//=============================================================================
// Killing Floor 2
// Copyright (C) 2018 Tripwire Interactive LLC
//=============================================================================
class KFMapObjective_VolumeBase extends Volume
implements(KFInterface_MapObjective)
placeable
abstract;
//=============================================================================
// Common objective variables
//=============================================================================
`include(KFMapObjective_CommonVars.uci)
//=============================================================================
// KFMapObjective_VolumeBase variables
//=============================================================================
var repnotify bool bActive;
/** Whether or not to use the trader trail to lead players to the zone */
var() bool bUseTrailToVolume;
/** Emitter to use to visually define the area the players should hold out.
Note: This is going to be removed in favor of a static mesh setup at some
point in the near future.
*/
var() array<Emitter> ZoneBoundariesEmitter;
/** Meshes used to define the outer boundary of the objective area. */
var() array<DynamicSMActor> ZoneBoundaryMeshes;
/** Splines used to define the boundary of the objective area. */
var() array<SplineLoftActor> ZoneBoundarySplines;
/** Name of the param that sets on/off state of danger colors of the mesh array */
var() name ZoneDangerMaterialParamName;
/** Max reward if users (theoretically) did the objective perfectly */
var() const array<int> DoshRewards;
/** XP reward if user compeletes the objective. */
var const array<int> XPRewards;
/** Multipliers for the Max XP/Vosh/Dosh Amount given at the end of an objective*/
var const array<float> DoshDifficultyScalars;
var const array<float> XPDifficultyScalars;
/** Modifies the Dosh value gained for killing zeds while this objective is active*/
var() const float DoshValueModifier;
replication
{
if (bNetDirty)
bActive;
}
simulated event PostBeginPlay()
{
local int i, j, k;
Super.PostBeginPlay();
if (WorldInfo.NetMode != NM_DedicatedServer)
{
for (i = 0; i < ZoneBoundaryMeshes.Length; ++i)
{
if (ZoneBoundaryMeshes[i] != none)
{
ZoneBoundaryMeshes[i].StaticMeshComponent.SetHidden(true);
j = 0;
while (ZoneBoundaryMeshes[i].StaticMeshComponent.GetMaterial(j) != none)
{
ZoneBoundaryMeshes[i].StaticMeshComponent.CreateAndSetMaterialInstanceConstant(j);
++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)
{
ZoneBoundarySplines[i].SplineMeshComps[j].SetHidden(true);
k = 0;
while (ZoneBoundarySplines[i].SplineMeshComps[j].GetMaterial(k) != none)
{
ZoneBoundarySplines[i].SplineMeshComps[j].CreateAndSetMaterialInstanceConstant(k);
++k;
}
}
}
}
}
}
}
//=============================================================================
// KFInterface_MapObjective functions
//=============================================================================
simulated function PlayActivationSoundEvent()
{
if (Role == ROLE_AUTHORITY)
{
if (ActivationSoundEvent != none)
{
PlaySoundBase(ActivationSoundEvent, false, WorldInfo.NetMode == NM_DedicatedServer);
}
}
}
simulated function ActivateBoundarySplines()
{
local int i, j;
if (WorldInfo.NetMode != NM_DedicatedServer)
{
for (i = 0; i < ZoneBoundariesEmitter.Length; ++i)
{
if (ZoneBoundariesEmitter[i] != none)
{
ZoneBoundariesEmitter[i].ParticleSystemComponent.ActivateSystem();
ZoneBoundariesEmitter[i].bCurrentlyActive = true;
}
}
for (i = 0; i < ZoneBoundaryMeshes.Length; ++i)
{
if (ZoneBoundaryMeshes[i] != none)
{
ZoneBoundaryMeshes[i].StaticMeshComponent.SetHidden(false);
}
}
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)
{
ZoneBoundarySplines[i].SplineMeshComps[j].SetHidden(false);
}
}
}
}
}
}
// Status
simulated function ActivateObjective()
{
local int i;
local KFSeqEvent_MapObjectiveActivated ActivationEvent;
bActive = true;
for (i = 0; i < GeneratedEvents.Length; i++)
{
ActivationEvent = KFSeqEvent_MapObjectiveActivated(GeneratedEvents[i]);
if (ActivationEvent != none)
{
ActivationEvent.NotifyActivation(self, self);
}
}
ActivateBoundarySplines();
// delay this sound event by a little bit so that the unreliable RPC doesn't get lost
SetTimer(1.0f, false, nameof(PlayActivationSoundEvent));
}
simulated function DeactivateObjective()
{
local int i, j;
local KFSeqEvent_MapObjectiveActivated ActivationEvent;
bActive = false;
for (i = 0; i < GeneratedEvents.Length; i++)
{
ActivationEvent = KFSeqEvent_MapObjectiveActivated(GeneratedEvents[i]);
if (ActivationEvent != none)
{
ActivationEvent.NotifyDeactivation(self, self);
}
}
if (WorldInfo.NetMode != NM_DedicatedServer)
{
for (i = 0; i < ZoneBoundariesEmitter.Length; ++i)
{
if (ZoneBoundariesEmitter[i] != none)
{
ZoneBoundariesEmitter[i].ParticleSystemComponent.DeactivateSystem();
ZoneBoundariesEmitter[i].bCurrentlyActive = false;
}
}
for (i = 0; i < ZoneBoundaryMeshes.Length; ++i)
{
if (ZoneBoundaryMeshes[i] != none)
{
ZoneBoundaryMeshes[i].StaticMeshComponent.SetHidden(true);
}
}
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)
{
ZoneBoundarySplines[i].SplineMeshComps[j].SetHidden(true);
}
}
}
}
}
}
simulated function GrantReward(KFPlayerReplicationInfo KFPRI, KFPlayerController KFPC)
{
if (KFPRI == none)
{
return;
}
if (KFPRI.bOnlySpectator)
{
return;
}
KFPRI.AddDosh(GetDoshReward());
if (KFPC != none)
{
// @todo: hook up seasonal event here if/when desired
KFPC.ClientMapObjectiveCompleted(GetXPReward());
}
}
simulated function int GetMaxXPReward()
{
local KFGameReplicationInfo KFGRI;
local int ArrayEnd;
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
if (KFGRI != none)
{
// Since we're using a static array for rewards, we need to know the true end of the array.
ArrayEnd = Clamp(KFGRI.WaveMax - 2, 0, XPRewards.Length - 1);
return XPRewards[Clamp(KFGRI.WaveNum - 1, 0, ArrayEnd)] * XPDifficultyScalars[KFGRI.GameDifficulty];
}
if (XPRewards.Length > 0)
{
return XPRewards[0];
}
return 0;
}
simulated function int GetMaxDoshReward()
{
local KFGameReplicationInfo KFGRI;
local int ArrayEnd;
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
if (KFGRI != none)
{
// Since we're using a static array for rewards, we need to know the true end of the array.
ArrayEnd = Clamp(KFGRI.WaveMax - 2, 0, DoshRewards.Length - 1);
return DoshRewards[Clamp(KFGRI.WaveNum - 1, 0, ArrayEnd)] * DoshDifficultyScalars[KFGRI.GameDifficulty];
}
if (DoshRewards.Length > 0)
{
return DoshRewards[0];
}
return 0;
}
simulated function int GetMaxVoshReward()
{
local KFGameReplicationInfo KFGRI;
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
if (KFGRI != none)
{
return class'KFOnlineStatsWrite'.static.GetMapObjectiveVoshReward(KFGRI.GameDifficulty, KFGRI.WaveNum);
}
return 0;
}
simulated function int GetDoshReward()
{
return GetMaxDoshReward();
}
simulated function int GetVoshReward()
{
local int MaxVosh;
MaxVosh = GetMaxVoshReward();
if (MaxVosh == 0)
{
return MaxVosh;
}
return int(MaxVosh * GetProgress());
}
simulated function int GetXPReward()
{
local int MaxXP;
MaxXP = GetMaxXPReward();
if (MaxXP == 0)
{
return MaxXP;
}
return int(MaxXP * GetProgress());
}
simulated function string GetLocalizedName()
{
if (LocalizationKey != "")
{
return Localize("Objectives", LocalizationKey, LocalizationPackageName);
}
return "";
}
simulated function string GetLocalizedShortName()
{
if (NameShortLocKey != "")
{
return Localize("Objectives", NameShortLocKey, LocalizationPackageName);
}
return "";
}
simulated function string GetLocalizedDescription()
{
if (DescriptionLocKey != "")
{
return Localize("Objectives", DescriptionLocKey, LocalizationPackageName);
}
return "";
}
simulated function string GetLocalizedShortDescription()
{
if (DescriptionShortLocKey != "")
{
return Localize("Objectives", DescriptionShortLocKey, LocalizationPackageName);
}
return "";
}
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;
}
}
simulated function float GetSpawnRateMod()
{
local KFGameReplicationInfo KFGRI;
local int NumPlayersAlive;
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
if (KFGRI != none)
{
NumPlayersAlive = Clamp(KFGRI.GetNumPlayersAlive(), 1, PerPlayerSpawnRateMod.length) - 1;
if (NumPlayersAlive >= 0 && NumPlayersAlive < PerPlayerSpawnRateMod.Length)
{
return PerPlayerSpawnRateMod[NumPlayersAlive];
}
}
return 1.f;
}
simulated function bool HasFailedObjective()
{
return GetLivingPlayerCount() <= 0;
}
simulated function int GetLivingPlayerCount()
{
local KFGameReplicationInfo KFGRI;
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
if (KFGRI != none)
{
return KFGRI.GetNumPlayersAlive();
}
return 0;
}
simulated function bool IsActive() { return bActive; }
simulated function bool UsesProgress();
simulated function bool IsBonus();
function bool CanActivateObjective();
simulated function float GetProgress();
simulated function bool IsComplete();
simulated function float GetActivationPctChance();
simulated function string GetProgressText();
simulated function bool GetProgressTextIsDosh() { return false; }
simulated function string GetLocalizedRequirements();
simulated function bool GetIsMissionCritical();
simulated function float GetDoshValueModifier() { return DoshValueModifier; }
function NotifyZedKilled(Controller Killer, Pawn KilledPawn, bool bIsBoss);
simulated function NotifyObjectiveSelected();
// HUD
simulated function bool ShouldDrawIcon();
simulated function Vector GetIconLocation();
simulated function DrawHUD(KFHUDBase hud, Canvas drawCanvas);
simulated function bool HasObjectiveDrawDistance() { return true; }
simulated function bool ShouldShowObjectiveHUD() { return true; }
simulated function bool ShouldShowObjectiveContainer() { return true; }
simulated function Texture2D GetIcon()
{
return ObjectiveIcon;
}
simulated function color GetIconColor()
{
return ObjectiveIconColor;
}
// Kismet
simulated function TriggerObjectiveProgressEvent(optional int EventType = -1, optional float ProgressMade = -1.f)
{
local int i, j;
local array<int> OutputLinksToActivate;
local KFSeqEvent_ObjectiveProgress ProgressEvent;
if (EventType >= 0)
{
OutputLinksToActivate.AddItem(EventType);
}
for (i = 0; i < GeneratedEvents.Length; i++)
{
ProgressEvent = KFSeqEvent_ObjectiveProgress(GeneratedEvents[i]);
if (ProgressEvent != none)
{
if (ProgressMade >= 0.0f)
{
for (j = 0; j < ProgressEvent.ProgressThresholds.Length; j++)
{
if (ProgressEvent.ProgressThresholds[j] == ProgressMade)
{
OutputLinksToActivate.AddItem(ProgressEvent.ProgressOutputStartIndex + j);
break;
}
}
}
ProgressEvent.Reset();
ProgressEvent.CheckActivate(self, self, , OutputLinksToActivate);
}
}
}
defaultproperties
{
SupportedEvents.Add(class'KFSeqEvent_MapObjectiveActivated')
XPDifficultyScalars=(1.0f,1.3f,1.75f,2.0f)
DoshDifficultyScalars=(1.2f,1.0f,1.0f,0.9f)
DoshRewards = (200,250,300,350,400,450,500,500,500,500,500)
XPRewards = (100,100,150,150,200,200,250,250,300,300,300)
DoshValueModifier=1.0f
ObjectiveIcon=Texture2D'Objectives_UI.UI_Objectives_ObjectiveMode'
ObjectiveIconColor=(R=170, G=0, B=255, A=255);
}