547 lines
15 KiB
Ucode
547 lines
15 KiB
Ucode
|
//=============================================================================
|
||
|
// 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<AkEvent> TriggerReadySoundEvents;
|
||
|
|
||
|
/** A sound to play when the trigger is pulled */
|
||
|
var() array<AkEvent> 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<AkEvent> 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);
|
||
|
}
|