1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFMapObjective_RepairActors.uc

565 lines
14 KiB
Ucode
Raw Normal View History

2020-12-13 15:01:13 +00:00
//=============================================================================
// KFMapObjective_RepairActors
//=============================================================================
// Objective type for the repair panels. Player must weld n number of actors in
// order to repair them. After one actor is repaired, another will break.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2018 Tripwire Interactive LLC
//=============================================================================
class KFMapObjective_RepairActors extends KFMapObjective_ActorBase;
/** How many actors needs to be repaired for the objective to be completed, per number of players */
var() const int ActivationsRequiredForPlayerCount[6];
/** A delay from the the start of an objective, so the player can't automatically repair the first actor */
var() float ActivationDelay;
/** A sound to play when each repair actor is activated */
var() array<AkEvent> ActorActivationSoundEvents;
/** A sound to play when each repair actor is repaired */
var() array<AkEvent> ActorRepairedSoundEvents;
/** How many actors needs to be repaired for the objective to be completed. */
var int ActivationsRequired;
/** How many actors have been repaired. */
var repnotify int ActorsRepaired;
/** List of all the actors that must be repaired by the user. */
var() array<KFRepairableActor> RepairableActors;
/** List of Repairable Actors we haven't repaired yet. This will ensure we cycle through all actors before repeating. */
var array<KFRepairableActor> UnusedRepairableActors;
/** Reference to last actor repaired so we don't fix the same actor one after the other. */
var KFRepairableActor LastRepairedActor;
/** Current Actor that needs to be repaired. */
var repnotify KFRepairableActor CurrentActorToRepair;
/** How long until the next repairable actor can be activated. */
var() float TimeUntilNextActivation;
/** 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;
/** Win thresholds - Named to match the VO tracks*/
var float JustWinThreshold;
var float StandardWinThreshold;
var float GoodWinThreshold;
/** Whether the sequence of repairables should be randomized */
var() bool bRandomSequence;
replication
{
if(bNetDirty)
CurrentActorToRepair, ActorsRepaired, ActivationsRequired;
}
simulated event ReplicatedEvent(name VarName)
{
if (VarName == nameof(CurrentActorToRepair))
{
UpdateTrailActor();
}
else if (VarName == nameof(ActorsRepaired))
{
if (ActorsRepaired != 0)
{
TriggerObjectiveProgressEvent(, float(ActorsRepaired)/float(ActivationsRequired));
}
}
else
{
super.ReplicatedEvent(VarName);
}
}
simulated function ActivateObjective()
{
local int PlayerCount;
local KFRepairableActor CurrActor;
super.ActivateObjective();
foreach RepairableActors(CurrActor)
{
CurrActor.OnRepairCompelete = OnActorRepaired;
}
if (WorldInfo.NetMode != NM_DedicatedServer)
{
if (bUseTrailToObjective)
{
TrailActor = class'WorldInfo'.static.GetWorldInfo().Spawn(class'KFReplicatedShowPathActor', none);
TrailActor.SetEmitterTemplate(ParticleSystem'FX_Gameplay_EMIT.FX_Objective_White_Trail');
}
}
if (Role == ROLE_Authority)
{
PlayerCount = Clamp(KFGameInfo(WorldInfo.Game).GetLivingPlayerCount(), 1, 6) - 1;
ActivationsRequired = ActivationsRequiredForPlayerCount[PlayerCount];
ActorsRepaired = 0;
bIsActive = true;
if (ActivationDelay > 0.f)
{
SetTimer(ActivationDelay, false, 'ActivateNextRepairableActor');
}
else
{
ActivateNextRepairableActor();
}
}
}
simulated function DeactivateObjective()
{
local KFPlayerController KFPC;
local KFPawn_Human KFPH;
local KFRepairableActor CurrActor;
super.DeactivateObjective();
if(Role == ROLE_Authority)
{
bIsActive = false;
if (!HasFailedObjective())
{
foreach WorldInfo.AllPawns(class'KFPawn_Human', KFPH)
{
GrantReward(KFPlayerReplicationInfo(KFPH.PlayerReplicationInfo), KFPlayerController(KFPH.Controller));
if (KFPlayerController(KFPH.Controller) != none)
{
if (GetTotalProgress() >= 1.0f)
{
// @todo: hook up seasonal event here if/when desired
}
}
}
}
else
{
`log("objective failed");
}
PlayDeactivationDialog();
ClearTimer(nameof(ActivateNextRepairableActor));
}
foreach RepairableActors(CurrActor)
{
CurrActor.Reset();
}
if(WorldInfo.NetMode != NM_DedicatedServer)
{
if (TrailActor != none)
{
TrailActor.Destroy();
TrailActor = none;
}
}
KFPC = KFPlayerController(GetALocalPlayerController());
if (KFPC != none && KFPC.MyGFxHUD != none)
{
KFPC.MyGFxHUD.WaveInfoWidget.ObjectiveContainer.SetFailState(HasFailedObjective());
}
}
function PlayDeactivationDialog()
{
if (GetTotalProgress() <= 0.0f)
{
PlaySoundBase(FailureSoundEvent, false, WorldInfo.NetMode == NM_DedicatedServer);
BroadcastLocalizedMessage(class'KFLocalMessage_Priority', GMT_ObjectiveLost);
}
else
{
if (GetTotalProgress() <= JustWinThreshold)
{
PlaySoundBase(SuccessSoundEvent25pct, false, WorldInfo.NetMode == NM_DedicatedServer);
}
else if (GetTotalProgress() <= StandardWinThreshold)
{
PlaySoundBase(SuccessSoundEvent50pct, false, WorldInfo.NetMode == NM_DedicatedServer);
}
else if (GetTotalProgress() <= GoodWinThreshold)
{
PlaySoundBase(SuccessSoundEvent85pct, false, WorldInfo.NetMode == NM_DedicatedServer);
}
else
{
PlaySoundBase(SuccessSoundEvent100pct, false, WorldInfo.NetMode == NM_DedicatedServer);
}
}
}
function ActivateNextRepairableActor()
{
if(Role == ROLE_Authority)
{
LastRepairedActor = CurrentActorToRepair;
CurrentActorToRepair = ChooseNextActorToRepair();
if (CurrentActorToRepair != none)
{
CurrentActorToRepair.PlayDestroyed();
}
if (ActorsRepaired < ActorActivationSoundEvents.Length)
{
PlaySoundBase(ActorActivationSoundEvents[ActorsRepaired], false, WorldInfo.NetMode == NM_DedicatedServer);
}
}
UpdateTrailActor();
}
simulated function UpdateTrailActor()
{
if (WorldInfo.NetMode != NM_DedicatedServer)
{
if (TrailActor != none)
{
TrailActor.SetPathTarget(CurrentActorToRepair.RepairTrigger);
}
}
}
function KFRepairableActor ChooseNextActorToRepair()
{
local int ChosenActorIndex;
local KFRepairableActor ChosenActor;
local array<KFRepairableActor> ValidActors;
if (RepairableActors.length == 0)
{
return none;
}
if (UnusedRepairableActors.length == 0)
{
UnusedRepairableActors = RepairableActors;
}
ValidActors = UnusedRepairableActors;
if(ValidActors.length > 1)
{
ValidActors.RemoveItem(LastRepairedActor);
}
if (bRandomSequence)
{
ChosenActorIndex = RandRange(0, ValidActors.length - 1);
}
else
{
// if not random choose the next actor in the sequence
ChosenActorIndex = 0;
}
ChosenActor = ValidActors[ChosenActorIndex];
UnusedRepairableActors.Remove(ChosenActorIndex, 1);
return ChosenActor;
}
function OnActorRepaired(KFRepairableActor RepairedActor)
{
local KFGameReplicationInfo KFGRI;
if (!bIsActive)
{
return;
}
if (Role == ROLE_Authority)
{
if (ActorsRepaired < ActorRepairedSoundEvents.Length)
{
PlaySoundBase(ActorRepairedSoundEvents[ActorsRepaired], false, WorldInfo.NetMode == NM_DedicatedServer);
}
}
ActorsRepaired++;
TriggerObjectiveProgressEvent(, float(ActorsRepaired) / float(ActivationsRequired));
if (GetTotalProgress() >= 1.f)
{
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
if (KFGRI != none)
{
KFGRI.DeactivateObjective();
}
}
else
{
if (TimeUntilNextActivation > 0.f)
{
SetTimer(TimeUntilNextActivation, false, nameof(ActivateNextRepairableActor));
CurrentActorToRepair = none;
UpdateTrailActor();
}
else
{
ActivateNextRepairableActor();
}
}
}
simulated function bool IsActive()
{
return bIsActive;
}
simulated function bool IsBonus()
{
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 bool ShouldShowObjectiveHUD()
{
return false;
}
simulated function float GetProgress()
{
if (!HasFailedObjective())
{
return float(ActorsRepaired) / float(ActivationsRequired);
}
return 0.f;
}
simulated function bool IsComplete()
{
return GetProgress() >= 1.f;
}
simulated function float GetTotalProgress()
{
if (ActivationsRequired == 0)
{
return 0.f;
}
return float(ActorsRepaired) / float(ActivationsRequired);
}
simulated function float GetActivationPctChance()
{
return 1.f;
}
simulated function string GetLocalizedRequirements()
{
return Localize("Objectives", default.RequirementsLocKey, "KFGame") @ ActivationsRequired;
}
simulated function bool ShouldDrawIcon()
{
return CurrentActorToRepair != none;
}
simulated function Vector GetIconLocation()
{
if (CurrentActorToRepair != none)
{
return CurrentActorToRepair.Location + CurrentActorToRepair.IconLocationOffset;
}
return Location;
}
simulated function int GetVoshReward()
{
local int MaxDosh;
MaxDosh = GetMaxVoshReward();
if (MaxDosh == 0)
{
return MaxDosh;
}
return int(MaxDosh * GetTotalProgress());
}
simulated function int GetXPReward()
{
local int MaxXP;
MaxXP = GetMaxXPReward();
if (MaxXP == 0)
{
return MaxXP;
}
return int(MaxXP * GetTotalProgress());
}
simulated function string GetProgressText()
{
if (!bIsActive)
{
return "";
}
return ActorsRepaired $ "/" $ ActivationsRequired;
}
simulated function bool GetIsMissionCritical()
{
return bIsMissionCriticalObjective;
}
// this is currently a copy of DrawObjectiveHUD,
// except it uses the individual repairable weld completion instead of the overall objective completion
simulated function DrawHUD(KFHUDBase hud, Canvas drawCanvas)
{
local float Percentage;
local float BarHeight, BarLength;
local vector ScreenPos, TargetLocation;
local float ResModifier;
local float ThisDot;
local KFGameReplicationInfo KFGRI;
local vector ViewLocation, ViewVector;
local rotator ViewRotation;
local KFPlayerController KFPC;
ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * hud.FriendlyHudScale;
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
KFPC = KFPlayerController(GetALocalPlayerController());
if (!ShouldDrawIcon() || KFGRI.bHidePawnIcons)
{
return;
}
if (KFPC != none)
{
KFPC.GetPlayerViewPoint(ViewLocation, ViewRotation);
}
ViewVector = vector(ViewRotation);
ThisDot = Normal(GetIconLocation() - ViewLocation) dot ViewVector;
if (ThisDot <= 0)
{
return;
}
BarLength = FMin(hud.PlayerStatusBarLengthMax * (drawCanvas.ClipX / 1024.f), hud.PlayerStatusBarLengthMax) * ResModifier;
BarHeight = FMin(8.f * (drawCanvas.ClipX / 1024.f), 8.f) * ResModifier;
TargetLocation = GetIconLocation();
ScreenPos = drawCanvas.Project(TargetLocation);
// Make sure that the entire health bar is on screen
ScreenPos.X = FClamp(ScreenPos.X, BarLength * 0.5f + hud.PlayerStatusIconSize, drawCanvas.ClipX - BarLength * 0.5f);
ScreenPos.Y = FClamp(ScreenPos.Y, hud.PlayerStatusIconSize * 0.5f, drawCanvas.ClipY - hud.PlayerStatusIconSize * 0.5f);
//Draw progress bar
Percentage = FMin(FClamp(float(CurrentActorToRepair.WeldIntegrity) / float(CurrentActorToRepair.MaxWeldIntegrity), 0.f, 1.f), 1);
hud.DrawKFBar(Percentage, BarLength, BarHeight, ScreenPos.X - (BarLength * 0.5f), ScreenPos.Y, hud.NonPlayerHealth);
//draw objective icon
if (GetIcon() != none)
{
drawCanvas.SetDrawColorStruct(hud.PlayerBarShadowColor);
drawCanvas.SetPos((ScreenPos.X - (BarLength * 0.75)) + 1, (ScreenPos.Y - BarHeight * 2.0) + 1);
drawCanvas.DrawTile(GetIcon(), hud.PlayerStatusIconSize * ResModifier, hud.PlayerStatusIconSize * ResModifier, 0, 0, 256, 256);
drawCanvas.SetDrawColorStruct(GetIconColor());
drawCanvas.SetPos(ScreenPos.X - (BarLength * 0.75), ScreenPos.Y - BarHeight * 2.0);
drawCanvas.DrawTile(GetIcon(), hud.PlayerStatusIconSize * ResModifier, hud.PlayerStatusIconSize * ResModifier, 0, 0, 256, 256);
}
}
defaultproperties
{
LocalizationKey="RepairObjective"
DescriptionLocKey="UseWelderToRepair"
NameShortLocKey="RepairObjective"
DescriptionShortLocKey="UseWelderToRepairShort"
RequirementsLocKey="RepairObjectiveRequired"
bAlwaysRelevant=true
RemoteRole=ROLE_SimulatedProxy
TimeUntilNextActivation=5.f
SupportedEvents.Add(class'KFSeqEvent_ObjectiveProgress')
GameModeBlacklist.Add(class'KFGameInfo_Endless')
GameModeBlacklist.Add(class'KFGameInfo_WeeklySurvival')
Begin Object Class=SpriteComponent Name=Sprite
Sprite=Texture2D'EditorResources.S_Actor'
HiddenGame=True
AlwaysLoadOnClient=False
AlwaysLoadOnServer=False
End Object
Components.Add(Sprite)
ActivationsRequired=6
bUseTrailToObjective=true
PerPlayerSpawnRateMod=(1.f, 1.f, 1.f, 1.f, 1.f, 1.f)
ObjectiveIcon=Texture2D'Objectives_UI.UI_Objectives_ObjectiveMode'
//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"
bRandomSequence=true
}