diff --git a/CVC/Classes/BaseVote.uc b/CVC/Classes/BaseVote.uc index 07a02be..df6d1e7 100644 --- a/CVC/Classes/BaseVote.uc +++ b/CVC/Classes/BaseVote.uc @@ -1,114 +1,114 @@ -class BaseVote extends Object - config(CVC) - abstract; - -var public config String PositiveColorHex; -var public config String NegativeColorHex; -var public config bool bChatNotifications; -var public config bool bHudNotifications; -var public config float DefferedClearHUD; -var public config int VoteTime; - -public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - switch (Version) - { - case `NO_CONFIG: - ApplyDefault(LogLevel); - - case 1: - default.VoteTime = class'KFVoteCollector'.default.VoteTime; - - default: break; - } - - if (LatestVersion != Version) - { - StaticSaveConfig(); - } -} - -public static function Load(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - if (!IsValidHexColor(default.PositiveColorHex, LogLevel)) - { - `Log_Error("PositiveColorHex" @ "(" $ default.PositiveColorHex $ ")" @ "is not valid hex color"); - default.PositiveColorHex = class'KFLocalMessage'.default.EventColor; - } - - if (!IsValidHexColor(default.NegativeColorHex, LogLevel)) - { - `Log_Error("NegativeColorHex" @ "(" $ default.NegativeColorHex $ ")" @ "is not valid hex color"); - default.NegativeColorHex = class'KFLocalMessage'.default.InteractionColor; - } - - if (default.DefferedClearHUD < 0) - { - `Log_Error("DefferedClearHUD" @ "(" $ default.DefferedClearHUD $ ")" @ "must be greater than 0"); - default.DefferedClearHUD = 0.0f; - } - - if (default.VoteTime <= 0 || default.VoteTime > 255) - { - `Log_Error("VoteTime" @ "(" $ default.VoteTime $ ")" @ "must be in range 1-255"); - default.VoteTime = class'KFVoteCollector'.default.VoteTime; - } -} - -protected static function ApplyDefault(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - default.bChatNotifications = true; - default.bHudNotifications = true; - default.PositiveColorHex = class'KFLocalMessage'.default.EventColor; - default.NegativeColorHex = class'KFLocalMessage'.default.InteractionColor; - default.DefferedClearHUD = 1.0f; - default.VoteTime = class'KFVoteCollector'.default.VoteTime; -} - -protected static function bool IsValidHexColor(String HexColor, E_LogLevel LogLevel) -{ - local byte Index; - - `Log_TraceStatic(); - - if (len(HexColor) != 6) return false; - - HexColor = Locs(HexColor); - - for (Index = 0; Index < 6; ++Index) - { - switch (Mid(HexColor, Index, 1)) - { - case "0": break; - case "1": break; - case "2": break; - case "3": break; - case "4": break; - case "5": break; - case "6": break; - case "7": break; - case "8": break; - case "9": break; - case "a": break; - case "b": break; - case "c": break; - case "d": break; - case "e": break; - case "f": break; - default: return false; - } - } - - return true; -} - -defaultproperties -{ - -} +class BaseVote extends Object + config(CVC) + abstract; + +var public config String PositiveColorHex; +var public config String NegativeColorHex; +var public config bool bChatNotifications; +var public config bool bHudNotifications; +var public config float DefferedClearHUD; +var public config int VoteTime; + +public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + switch (Version) + { + case `NO_CONFIG: + ApplyDefault(LogLevel); + + case 1: + default.VoteTime = class'KFVoteCollector'.default.VoteTime; + + default: break; + } + + if (LatestVersion != Version) + { + StaticSaveConfig(); + } +} + +public static function Load(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + if (!IsValidHexColor(default.PositiveColorHex, LogLevel)) + { + `Log_Error("PositiveColorHex" @ "(" $ default.PositiveColorHex $ ")" @ "is not valid hex color"); + default.PositiveColorHex = class'KFLocalMessage'.default.EventColor; + } + + if (!IsValidHexColor(default.NegativeColorHex, LogLevel)) + { + `Log_Error("NegativeColorHex" @ "(" $ default.NegativeColorHex $ ")" @ "is not valid hex color"); + default.NegativeColorHex = class'KFLocalMessage'.default.InteractionColor; + } + + if (default.DefferedClearHUD < 0) + { + `Log_Error("DefferedClearHUD" @ "(" $ default.DefferedClearHUD $ ")" @ "must be greater than 0"); + default.DefferedClearHUD = 0.0f; + } + + if (default.VoteTime <= 0 || default.VoteTime > 255) + { + `Log_Error("VoteTime" @ "(" $ default.VoteTime $ ")" @ "must be in range 1-255"); + default.VoteTime = class'KFVoteCollector'.default.VoteTime; + } +} + +protected static function ApplyDefault(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + default.bChatNotifications = true; + default.bHudNotifications = true; + default.PositiveColorHex = class'KFLocalMessage'.default.EventColor; + default.NegativeColorHex = class'KFLocalMessage'.default.InteractionColor; + default.DefferedClearHUD = 1.0f; + default.VoteTime = class'KFVoteCollector'.default.VoteTime; +} + +protected static function bool IsValidHexColor(String HexColor, E_LogLevel LogLevel) +{ + local byte Index; + + `Log_TraceStatic(); + + if (len(HexColor) != 6) return false; + + HexColor = Locs(HexColor); + + for (Index = 0; Index < 6; ++Index) + { + switch (Mid(HexColor, Index, 1)) + { + case "0": break; + case "1": break; + case "2": break; + case "3": break; + case "4": break; + case "5": break; + case "6": break; + case "7": break; + case "8": break; + case "9": break; + case "a": break; + case "b": break; + case "c": break; + case "d": break; + case "e": break; + case "f": break; + default: return false; + } + } + + return true; +} + +defaultproperties +{ + +} diff --git a/CVC/Classes/CVC.uc b/CVC/Classes/CVC.uc index 808a5e9..9037289 100644 --- a/CVC/Classes/CVC.uc +++ b/CVC/Classes/CVC.uc @@ -1,390 +1,390 @@ -class CVC extends Info - dependson(CVC_LocalMessage) - config(CVC); - -const LatestVersion = 2; - -const CfgKickProtected = class'KickProtected'; -const CfgKickVote = class'KickVote'; -const CfgStartWaveKickProtection = class'StartWaveKickProtection'; -const CfgSkipTraderVote = class'SkipTraderVote'; -const CfgPauseVote = class'PauseVote'; -const CfgMapStat = class'MapStat'; -const CfgMapVote = class'MapVote'; - -var private config int Version; -var private config E_LogLevel LogLevel; - -var private KFGameInfo KFGI; -var private KFGameInfo_Survival KFGIS; -var private KFGameReplicationInfo KFGRI; - -var private Array KickProtectedPlayers; -var private Array RepInfos; - -public simulated function bool SafeDestroy() -{ - `Log_Trace(); - - return (bPendingDelete || bDeleteMe || Destroy()); -} - -public event PreBeginPlay() -{ - `Log_Trace(); - - if (WorldInfo.NetMode == NM_Client) - { - `Log_Fatal("NetMode == NM_Client, Destroy..."); - SafeDestroy(); - return; - } - - Super.PreBeginPlay(); - - PreInit(); -} - -public event PostBeginPlay() -{ - `Log_Trace(); - - if (bPendingDelete || bDeleteMe) return; - - Super.PostBeginPlay(); - - PostInit(); -} - -private function PreInit() -{ - `Log_Trace(); - - if (Version == `NO_CONFIG) - { - LogLevel = LL_Info; - SaveConfig(); - } - - CfgMapStat.static.InitConfig(Version, LatestVersion, LogLevel); - CfgMapVote.static.InitConfig(Version, LatestVersion, LogLevel); - CfgSkipTraderVote.static.InitConfig(Version, LatestVersion, LogLevel); - CfgPauseVote.static.InitConfig(Version, LatestVersion, LogLevel); - CfgKickVote.static.InitConfig(Version, LatestVersion, LogLevel); - CfgKickProtected.static.InitConfig(Version, LatestVersion, LogLevel); - CfgStartWaveKickProtection.static.InitConfig(Version, LatestVersion, LogLevel); - - switch (Version) - { - case `NO_CONFIG: - `Log_Info("Config created"); - - case 1: - - case MaxInt: - `Log_Info("Config updated to version"@LatestVersion); - break; - - case LatestVersion: - `Log_Info("Config is up-to-date"); - break; - - default: - `Log_Warn("The config version is higher than the current version (are you using an old mutator?)"); - `Log_Warn("Config version is" @ Version @ "but current version is" @ LatestVersion); - `Log_Warn("The config version will be changed to" @ LatestVersion); - break; - } - - if (LatestVersion != Version) - { - Version = LatestVersion; - SaveConfig(); - } - - if (LogLevel == LL_WrongLevel) - { - LogLevel = LL_Info; - `Log_Warn("Wrong 'LogLevel', return to default value"); - SaveConfig(); - } - `Log_Base("LogLevel:" @ LogLevel); - - CfgKickVote.static.Load(LogLevel); - CfgSkipTraderVote.static.Load(LogLevel); - CfgPauseVote.static.Load(LogLevel); - CfgMapStat.static.Load(LogLevel); - CfgMapVote.static.Load(LogLevel); - CfgStartWaveKickProtection.static.Load(LogLevel); - - KickProtectedPlayers = CfgKickProtected.static.Load(LogLevel); -} - -private function PostInit() -{ - `Log_Trace(); - - if (WorldInfo == None || WorldInfo.Game == None) - { - SetTimer(1.0f, false, nameof(PostInit)); - return; - } - - KFGI = KFGameInfo(WorldInfo.Game); - if (KFGI == None) - { - `Log_Fatal("Incompatible gamemode:" @ WorldInfo.Game); - SafeDestroy(); - return; - } - - KFGIS = KFGameInfo_Survival(KFGI); - if (KFGIS == None) - { - `Log_Warn("Unknown gamemode (" $ KFGI $ "), KickProtectionStartWaves disabled"); - CfgStartWaveKickProtection.default.Waves = 0; - } - - if (KFGI.GameReplicationInfo == None) - { - SetTimer(1.0f, false, nameof(PostInit)); - return; - } - - KFGRI = KFGameReplicationInfo(KFGI.GameReplicationInfo); - if (KFGRI == None) - { - `Log_Fatal("Incompatible Replication info:" @ KFGI.GameReplicationInfo); - SafeDestroy(); - return; - } - - KFGRI.VoteCollectorClass = class'CVC_VoteCollector'; - KFGRI.VoteCollector = new(KFGRI) KFGRI.VoteCollectorClass; - - if (KFGRI.VoteCollector == None) - { - `Log_Fatal("Can't replace VoteCollector!"); - SafeDestroy(); - return; - } - else - { - CVC_VoteCollector(KFGRI.VoteCollector).CVC = Self; - CVC_VoteCollector(KFGRI.VoteCollector).LogLevel = LogLevel; - `Log_Info("VoteCollector replaced"); - } -} - -public function bool PlayerIsKickProtected(PlayerReplicationInfo PRI) -{ - `Log_Trace(); - - return (KickProtectedPlayers.Find('Uid', PRI.UniqueId.Uid) != INDEX_NONE); -} - -public function bool PlayerIsStartWaveKickProtected(KFPlayerController KFPC) -{ - `Log_Trace(); - - return (PlayerOnStartWave(KFPC) && PlayerHasRequiredLevel(KFPC)); -} - -private function bool PlayerOnStartWave(KFPlayerController KFPC) -{ - local CVC_RepInfo RepInfo; - - `Log_Trace(); - - if (KFGIS != None && CfgStartWaveKickProtection.default.Waves != 0) - { - foreach RepInfos(RepInfo) - { - if (RepInfo.GetKFPC() == KFPC) - { - return (RepInfo.StartWave + CfgStartWaveKickProtection.default.Waves >= KFGIS.WaveNum); - } - } - } - - return false; -} - -private function bool PlayerHasRequiredLevel(KFPlayerController KFPC) -{ - local KFPlayerReplicationInfo KFPRI; - - `Log_Trace(); - - KFPRI = KFPlayerReplicationInfo(KFPC.PlayerReplicationInfo); - - if (KFPRI == None) - { - return true; - } - - return (KFPRI.GetActivePerkLevel() >= CfgStartWaveKickProtection.default.MinLevel); -} - -public function bool PlayerCanStartKickVote(KFPlayerController KFPC, KFPlayerController KFPC_Kickee) -{ - `Log_Trace(); - - if (KFPC_Kickee != None) - { - if (KFPC == KFPC_Kickee) - { - return false; // kickee cant vote - } - if (!PlayerHasRequiredLevel(KFPC_Kickee)) - { - return true; // always can vote for players without req level - } - } - - return !PlayerOnStartWave(KFPC); -} - -public function BroadcastChatLocalized(E_CVC_LocalMessageType LMT, optional String HexColor, optional KFPlayerController ExceptKFPC = None, optional String String1, optional String String2) -{ - local CVC_RepInfo RepInfo; - - `Log_Trace(); - - foreach RepInfos(RepInfo) - { - if (RepInfo.GetKFPC() != ExceptKFPC) - { - RepInfo.WriteToChatLocalized(LMT, HexColor, String1, String2); - } - } -} - -public function BroadcastHUDLocalized(E_CVC_LocalMessageType LMT, optional float DisplayTime = 0.0f, optional String String1, optional String String2, optional String String3) -{ - local CVC_RepInfo RepInfo; - - `Log_Trace(); - - foreach RepInfos(RepInfo) - { - if (RepInfo.GetKFPC() != None) - { - RepInfo.WriteToHUDLocalized(LMT, String1, String2, String3, DisplayTime); - } - } -} - -public function BroadcastClearMessageHUD(optional float DefferedTime = 0.0f) -{ - local CVC_RepInfo RepInfo; - - `Log_Trace(); - - foreach RepInfos(RepInfo) - { - if (RepInfo.GetKFPC() != None) - { - RepInfo.DefferedClearMessageHUD(DefferedTime); - } - } -} - -public function WriteToChatLocalized(KFPlayerController KFPC, E_CVC_LocalMessageType LMT, optional String HexColor, optional String String1, optional String String2) -{ - local CVC_RepInfo RepInfo; - - `Log_Trace(); - - foreach RepInfos(RepInfo) - { - if (RepInfo.GetKFPC() == KFPC) - { - RepInfo.WriteToChatLocalized(LMT, HexColor, String1, String2); - return; - } - } -} - -public function WriteToHUDLocalized(KFPlayerController KFPC, E_CVC_LocalMessageType LMT, optional float DisplayTime = 0.0f, optional String String1, optional String String2, optional String String3) -{ - local CVC_RepInfo RepInfo; - - `Log_Trace(); - - foreach RepInfos(RepInfo) - { - if (RepInfo.GetKFPC() == KFPC) - { - RepInfo.WriteToHUDLocalized(LMT, String1, String2, String3, DisplayTime); - return; - } - } -} - -public function NotifyLogin(Controller C) -{ - `Log_Trace(); - - if (!CreateRepInfo(C)) - { - `Log_Error("Can't create RepInfo for:" @ C); - } -} - -public function NotifyLogout(Controller C) -{ - `Log_Trace(); - - if (!DestroyRepInfo(C)) - { - `Log_Error("Can't destroy RepInfo of:" @ C); - } -} - -public function bool CreateRepInfo(Controller C) -{ - local CVC_RepInfo RepInfo; - - `Log_Trace(); - - if (C == None) return false; - - RepInfo = Spawn(class'CVC_RepInfo', C); - - if (RepInfo == None) return false; - - RepInfo.CVC = Self; - RepInfo.LogLevel = LogLevel; - RepInfo.StartWave = ((KFGIS != None) ? KFGIS.WaveNum : 0); - - RepInfos.AddItem(RepInfo); - - return true; -} - -public function bool DestroyRepInfo(Controller C) -{ - local CVC_RepInfo RepInfo; - - `Log_Trace(); - - if (C == None) return false; - - foreach RepInfos(RepInfo) - { - if (RepInfo.Owner == C) - { - RepInfos.RemoveItem(RepInfo); - RepInfo.SafeDestroy(); - return true; - } - } - - return false; -} - -defaultproperties -{ - +class CVC extends Info + dependson(CVC_LocalMessage) + config(CVC); + +const LatestVersion = 2; + +const CfgKickProtected = class'KickProtected'; +const CfgKickVote = class'KickVote'; +const CfgStartWaveKickProtection = class'StartWaveKickProtection'; +const CfgSkipTraderVote = class'SkipTraderVote'; +const CfgPauseVote = class'PauseVote'; +const CfgMapStat = class'MapStat'; +const CfgMapVote = class'MapVote'; + +var private config int Version; +var private config E_LogLevel LogLevel; + +var private KFGameInfo KFGI; +var private KFGameInfo_Survival KFGIS; +var private KFGameReplicationInfo KFGRI; + +var private Array KickProtectedPlayers; +var private Array RepInfos; + +public simulated function bool SafeDestroy() +{ + `Log_Trace(); + + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public event PreBeginPlay() +{ + `Log_Trace(); + + if (WorldInfo.NetMode == NM_Client) + { + `Log_Fatal("NetMode == NM_Client, Destroy..."); + SafeDestroy(); + return; + } + + Super.PreBeginPlay(); + + PreInit(); +} + +public event PostBeginPlay() +{ + `Log_Trace(); + + if (bPendingDelete || bDeleteMe) return; + + Super.PostBeginPlay(); + + PostInit(); +} + +private function PreInit() +{ + `Log_Trace(); + + if (Version == `NO_CONFIG) + { + LogLevel = LL_Info; + SaveConfig(); + } + + CfgMapStat.static.InitConfig(Version, LatestVersion, LogLevel); + CfgMapVote.static.InitConfig(Version, LatestVersion, LogLevel); + CfgSkipTraderVote.static.InitConfig(Version, LatestVersion, LogLevel); + CfgPauseVote.static.InitConfig(Version, LatestVersion, LogLevel); + CfgKickVote.static.InitConfig(Version, LatestVersion, LogLevel); + CfgKickProtected.static.InitConfig(Version, LatestVersion, LogLevel); + CfgStartWaveKickProtection.static.InitConfig(Version, LatestVersion, LogLevel); + + switch (Version) + { + case `NO_CONFIG: + `Log_Info("Config created"); + + case 1: + + case MaxInt: + `Log_Info("Config updated to version"@LatestVersion); + break; + + case LatestVersion: + `Log_Info("Config is up-to-date"); + break; + + default: + `Log_Warn("The config version is higher than the current version (are you using an old mutator?)"); + `Log_Warn("Config version is" @ Version @ "but current version is" @ LatestVersion); + `Log_Warn("The config version will be changed to" @ LatestVersion); + break; + } + + if (LatestVersion != Version) + { + Version = LatestVersion; + SaveConfig(); + } + + if (LogLevel == LL_WrongLevel) + { + LogLevel = LL_Info; + `Log_Warn("Wrong 'LogLevel', return to default value"); + SaveConfig(); + } + `Log_Base("LogLevel:" @ LogLevel); + + CfgKickVote.static.Load(LogLevel); + CfgSkipTraderVote.static.Load(LogLevel); + CfgPauseVote.static.Load(LogLevel); + CfgMapStat.static.Load(LogLevel); + CfgMapVote.static.Load(LogLevel); + CfgStartWaveKickProtection.static.Load(LogLevel); + + KickProtectedPlayers = CfgKickProtected.static.Load(LogLevel); +} + +private function PostInit() +{ + `Log_Trace(); + + if (WorldInfo == None || WorldInfo.Game == None) + { + SetTimer(1.0f, false, nameof(PostInit)); + return; + } + + KFGI = KFGameInfo(WorldInfo.Game); + if (KFGI == None) + { + `Log_Fatal("Incompatible gamemode:" @ WorldInfo.Game); + SafeDestroy(); + return; + } + + KFGIS = KFGameInfo_Survival(KFGI); + if (KFGIS == None) + { + `Log_Warn("Unknown gamemode (" $ KFGI $ "), KickProtectionStartWaves disabled"); + CfgStartWaveKickProtection.default.Waves = 0; + } + + if (KFGI.GameReplicationInfo == None) + { + SetTimer(1.0f, false, nameof(PostInit)); + return; + } + + KFGRI = KFGameReplicationInfo(KFGI.GameReplicationInfo); + if (KFGRI == None) + { + `Log_Fatal("Incompatible Replication info:" @ KFGI.GameReplicationInfo); + SafeDestroy(); + return; + } + + KFGRI.VoteCollectorClass = class'CVC_VoteCollector'; + KFGRI.VoteCollector = new(KFGRI) KFGRI.VoteCollectorClass; + + if (KFGRI.VoteCollector == None) + { + `Log_Fatal("Can't replace VoteCollector!"); + SafeDestroy(); + return; + } + else + { + CVC_VoteCollector(KFGRI.VoteCollector).CVC = Self; + CVC_VoteCollector(KFGRI.VoteCollector).LogLevel = LogLevel; + `Log_Info("VoteCollector replaced"); + } +} + +public function bool PlayerIsKickProtected(PlayerReplicationInfo PRI) +{ + `Log_Trace(); + + return (KickProtectedPlayers.Find('Uid', PRI.UniqueId.Uid) != INDEX_NONE); +} + +public function bool PlayerIsStartWaveKickProtected(KFPlayerController KFPC) +{ + `Log_Trace(); + + return (PlayerOnStartWave(KFPC) && PlayerHasRequiredLevel(KFPC)); +} + +private function bool PlayerOnStartWave(KFPlayerController KFPC) +{ + local CVC_RepInfo RepInfo; + + `Log_Trace(); + + if (KFGIS != None && CfgStartWaveKickProtection.default.Waves != 0) + { + foreach RepInfos(RepInfo) + { + if (RepInfo.GetKFPC() == KFPC) + { + return (RepInfo.StartWave + CfgStartWaveKickProtection.default.Waves >= KFGIS.WaveNum); + } + } + } + + return false; +} + +private function bool PlayerHasRequiredLevel(KFPlayerController KFPC) +{ + local KFPlayerReplicationInfo KFPRI; + + `Log_Trace(); + + KFPRI = KFPlayerReplicationInfo(KFPC.PlayerReplicationInfo); + + if (KFPRI == None) + { + return true; + } + + return (KFPRI.GetActivePerkLevel() >= CfgStartWaveKickProtection.default.MinLevel); +} + +public function bool PlayerCanStartKickVote(KFPlayerController KFPC, KFPlayerController KFPC_Kickee) +{ + `Log_Trace(); + + if (KFPC_Kickee != None) + { + if (KFPC == KFPC_Kickee) + { + return false; // kickee cant vote + } + if (!PlayerHasRequiredLevel(KFPC_Kickee)) + { + return true; // always can vote for players without req level + } + } + + return !PlayerOnStartWave(KFPC); +} + +public function BroadcastChatLocalized(E_CVC_LocalMessageType LMT, optional String HexColor, optional KFPlayerController ExceptKFPC = None, optional String String1, optional String String2) +{ + local CVC_RepInfo RepInfo; + + `Log_Trace(); + + foreach RepInfos(RepInfo) + { + if (RepInfo.GetKFPC() != ExceptKFPC) + { + RepInfo.WriteToChatLocalized(LMT, HexColor, String1, String2); + } + } +} + +public function BroadcastHUDLocalized(E_CVC_LocalMessageType LMT, optional float DisplayTime = 0.0f, optional String String1, optional String String2, optional String String3) +{ + local CVC_RepInfo RepInfo; + + `Log_Trace(); + + foreach RepInfos(RepInfo) + { + if (RepInfo.GetKFPC() != None) + { + RepInfo.WriteToHUDLocalized(LMT, String1, String2, String3, DisplayTime); + } + } +} + +public function BroadcastClearMessageHUD(optional float DefferedTime = 0.0f) +{ + local CVC_RepInfo RepInfo; + + `Log_Trace(); + + foreach RepInfos(RepInfo) + { + if (RepInfo.GetKFPC() != None) + { + RepInfo.DefferedClearMessageHUD(DefferedTime); + } + } +} + +public function WriteToChatLocalized(KFPlayerController KFPC, E_CVC_LocalMessageType LMT, optional String HexColor, optional String String1, optional String String2) +{ + local CVC_RepInfo RepInfo; + + `Log_Trace(); + + foreach RepInfos(RepInfo) + { + if (RepInfo.GetKFPC() == KFPC) + { + RepInfo.WriteToChatLocalized(LMT, HexColor, String1, String2); + return; + } + } +} + +public function WriteToHUDLocalized(KFPlayerController KFPC, E_CVC_LocalMessageType LMT, optional float DisplayTime = 0.0f, optional String String1, optional String String2, optional String String3) +{ + local CVC_RepInfo RepInfo; + + `Log_Trace(); + + foreach RepInfos(RepInfo) + { + if (RepInfo.GetKFPC() == KFPC) + { + RepInfo.WriteToHUDLocalized(LMT, String1, String2, String3, DisplayTime); + return; + } + } +} + +public function NotifyLogin(Controller C) +{ + `Log_Trace(); + + if (!CreateRepInfo(C)) + { + `Log_Error("Can't create RepInfo for:" @ C); + } +} + +public function NotifyLogout(Controller C) +{ + `Log_Trace(); + + if (!DestroyRepInfo(C)) + { + `Log_Error("Can't destroy RepInfo of:" @ C); + } +} + +public function bool CreateRepInfo(Controller C) +{ + local CVC_RepInfo RepInfo; + + `Log_Trace(); + + if (C == None) return false; + + RepInfo = Spawn(class'CVC_RepInfo', C); + + if (RepInfo == None) return false; + + RepInfo.CVC = Self; + RepInfo.LogLevel = LogLevel; + RepInfo.StartWave = ((KFGIS != None) ? KFGIS.WaveNum : 0); + + RepInfos.AddItem(RepInfo); + + return true; +} + +public function bool DestroyRepInfo(Controller C) +{ + local CVC_RepInfo RepInfo; + + `Log_Trace(); + + if (C == None) return false; + + foreach RepInfos(RepInfo) + { + if (RepInfo.Owner == C) + { + RepInfos.RemoveItem(RepInfo); + RepInfo.SafeDestroy(); + return true; + } + } + + return false; +} + +defaultproperties +{ + } \ No newline at end of file diff --git a/CVC/Classes/CVC.upkg b/CVC/Classes/CVC.upkg index 29cb156..09febdf 100644 --- a/CVC/Classes/CVC.upkg +++ b/CVC/Classes/CVC.upkg @@ -1,4 +1,4 @@ -[Flags] -AllowDownload=True -ClientOptional=False -ServerSideOnly=False +[Flags] +AllowDownload=True +ClientOptional=False +ServerSideOnly=False diff --git a/CVC/Classes/CVCMut.uc b/CVC/Classes/CVCMut.uc index bcda41d..b007ac3 100644 --- a/CVC/Classes/CVCMut.uc +++ b/CVC/Classes/CVCMut.uc @@ -1,60 +1,60 @@ -class CVCMut extends KFMutator; - -var private CVC CVC; - -public simulated function bool SafeDestroy() -{ - return (bPendingDelete || bDeleteMe || Destroy()); -} - -public event PreBeginPlay() -{ - Super.PreBeginPlay(); - - if (WorldInfo.NetMode == NM_Client) return; - - foreach WorldInfo.DynamicActors(class'CVC', CVC) - { - break; - } - - if (CVC == None) - { - CVC = WorldInfo.Spawn(class'CVC'); - } - - if (CVC == None) - { - `Log_Base("FATAL: Can't Spawn 'CVC'"); - SafeDestroy(); - } -} - -public function AddMutator(Mutator Mut) -{ - if (Mut == Self) return; - - if (Mut.Class == Class) - Mut.Destroy(); - else - Super.AddMutator(Mut); -} - -public function NotifyLogin(Controller C) -{ - Super.NotifyLogin(C); - - CVC.NotifyLogin(C); -} - -public function NotifyLogout(Controller C) -{ - Super.NotifyLogout(C); - - CVC.NotifyLogout(C); -} - -defaultproperties -{ - +class CVCMut extends KFMutator; + +var private CVC CVC; + +public simulated function bool SafeDestroy() +{ + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public event PreBeginPlay() +{ + Super.PreBeginPlay(); + + if (WorldInfo.NetMode == NM_Client) return; + + foreach WorldInfo.DynamicActors(class'CVC', CVC) + { + break; + } + + if (CVC == None) + { + CVC = WorldInfo.Spawn(class'CVC'); + } + + if (CVC == None) + { + `Log_Base("FATAL: Can't Spawn 'CVC'"); + SafeDestroy(); + } +} + +public function AddMutator(Mutator Mut) +{ + if (Mut == Self) return; + + if (Mut.Class == Class) + Mut.Destroy(); + else + Super.AddMutator(Mut); +} + +public function NotifyLogin(Controller C) +{ + Super.NotifyLogin(C); + + CVC.NotifyLogin(C); +} + +public function NotifyLogout(Controller C) +{ + Super.NotifyLogout(C); + + CVC.NotifyLogout(C); +} + +defaultproperties +{ + } \ No newline at end of file diff --git a/CVC/Classes/CVC_LocalMessage.uc b/CVC/Classes/CVC_LocalMessage.uc index a48d638..22207ca 100644 --- a/CVC/Classes/CVC_LocalMessage.uc +++ b/CVC/Classes/CVC_LocalMessage.uc @@ -1,145 +1,145 @@ -class CVC_LocalMessage extends Object - abstract; - -var const String PlayerIsKickProtectedDefault; -var private localized String PlayerIsKickProtected; - -var const String PlayerIsStartWaveKickProtectedDefault; -var private localized String PlayerIsStartWaveKickProtected; - -var const String PlayerCantStartKickVoteDefault; -var private localized String PlayerCantStartKickVote; - -var const String KickVoteNotEnoughPlayersDefault; -var private localized String KickVoteNotEnoughPlayers; - -var const String KickVoteStartedDefault; -var private localized String KickVoteStarted; - -var const String KickVoteStartedForPlayerDefault; -var private localized String KickVoteStartedForPlayer; - -var const String KickVoteNotStartedForPlayerDefault; -var private localized String KickVoteNotStartedForPlayer; - -var const String VotedPlayersDefault; -var private localized String VotedPlayers; - -var const String DidntVotePlayersDefault; -var private localized String DidntVotePlayers; - -enum E_CVC_LocalMessageType -{ - CVC_PlayerIsKickProtected, - CVC_PlayerIsStartWaveKickProtected, - CVC_PlayerCantStartKickVote, - - CVC_KickVoteNotEnoughPlayers, - CVC_KickVoteStarted, - CVC_KickVoteStartedForPlayer, - CVC_KickVoteNotStartedForPlayer, - - CVC_KickVoteYesReceived, - CVC_KickVoteNoReceived, - CVC_KickVoteStartedHUD, - CVC_KickVoteReceivedHUD, - - CVC_SkipVoteYesReceived, - CVC_SkipVoteNoReceived, - - CVC_PauseVoteYesReceived, - CVC_PauseVoteNoReceived, - - CVC_VoteProgressHUD, -}; - -private static function String ReplKicker(String Str, String Kicker) -{ - return Repl(Str, "", Kicker, false); -} - -private static function String ReplKickee(String Str, String Kickee) -{ - return Repl(Str, "", Kickee, false); -} - -private static function String ReplWaves(String Str, String Waves) -{ - return Repl(Str, "", Waves, false); -} - -public static function String GetLocalizedString( - E_LogLevel LogLevel, - E_CVC_LocalMessageType LMT, - optional String String1, - optional String String2, - optional String String3) -{ - `Log_TraceStatic(); - - switch (LMT) - { - case CVC_PlayerIsKickProtected: - return ReplKickee(default.PlayerIsKickProtected != "" ? default.PlayerIsKickProtected : default.PlayerIsKickProtectedDefault, String1); - - case CVC_PlayerIsStartWaveKickProtected: - return ReplWaves(ReplKickee(default.PlayerIsStartWaveKickProtected != "" ? default.PlayerIsStartWaveKickProtected : default.PlayerIsStartWaveKickProtectedDefault, String1), String2); - - case CVC_PlayerCantStartKickVote: - return ReplWaves(default.PlayerCantStartKickVote != "" ? default.PlayerCantStartKickVote : default.PlayerCantStartKickVoteDefault, String1); - - case CVC_KickVoteNotEnoughPlayers: - return ReplWaves(default.KickVoteNotEnoughPlayers != "" ? default.KickVoteNotEnoughPlayers : default.KickVoteNotEnoughPlayersDefault, String1); - - case CVC_KickVoteYesReceived: - return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.YesString); - - case CVC_KickVoteNoReceived: - return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.NoString); - - case CVC_KickVoteStartedHUD: - return ReplKickee(ReplKicker((default.KickVoteStarted != "" ? default.KickVoteStarted : default.KickVoteStartedDefault), String1), String2) $ "\n" $ class'KFCommon_LocalizedStrings'.default.YesString $ ":" @ String3; - - case CVC_KickVoteReceivedHUD: - return class'KFCommon_LocalizedStrings'.default.YesString $ ":" @ String1 $ "\n" $ class'KFCommon_LocalizedStrings'.default.NoString $ ":" @ String2; - - case CVC_KickVoteStarted: - return ReplKickee(ReplKicker((default.KickVoteStarted != "" ? default.KickVoteStarted : default.KickVoteStartedDefault), String1), String2); - - case CVC_KickVoteStartedForPlayer: - return ReplKicker((default.KickVoteStartedForPlayer != "" ? default.KickVoteStartedForPlayer : default.KickVoteStartedForPlayerDefault), String1); - - case CVC_KickVoteNotStartedForPlayer: - return ReplKicker((default.KickVoteNotStartedForPlayer != "" ? default.KickVoteNotStartedForPlayer : default.KickVoteNotStartedForPlayerDefault), String1); - - case CVC_SkipVoteYesReceived: - return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.YesString); - - case CVC_SkipVoteNoReceived: - return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.NoString); - - case CVC_PauseVoteYesReceived: - return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.YesString); - - case CVC_PauseVoteNoReceived: - return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.NoString); - - case CVC_VoteProgressHUD: - return (default.DidntVotePlayers != "" ? default.DidntVotePlayers : default.DidntVotePlayersDefault) @ String2 $ (String1 != "" ? ("\n" $ (default.VotedPlayers != "" ? default.VotedPlayers : default.VotedPlayersDefault) @ String1) : ""); - } - - return ""; -} - -defaultproperties -{ - PlayerIsKickProtectedDefault = " is protected from kick" - PlayerIsStartWaveKickProtectedDefault = "You can't kick right now. He can be kicked when he plays at least wave(s)" - PlayerCantStartKickVoteDefault = "You can't start kick vote now. You can start kick vote when you play at least wave(s)" - KickVoteNotEnoughPlayersDefault = "Not enough players to start vote (only players who have played at least wave(s) can vote)" - KickVoteStartedDefault = " has started a vote to kick " - KickVoteStartedForPlayerDefault = " started voting to kick you" - KickVoteNotStartedForPlayerDefault = " tried to kick you" - VotedPlayersDefault = "Voted:" - DidntVotePlayersDefault = "Didn't vote:" +class CVC_LocalMessage extends Object + abstract; + +var const String PlayerIsKickProtectedDefault; +var private localized String PlayerIsKickProtected; + +var const String PlayerIsStartWaveKickProtectedDefault; +var private localized String PlayerIsStartWaveKickProtected; + +var const String PlayerCantStartKickVoteDefault; +var private localized String PlayerCantStartKickVote; + +var const String KickVoteNotEnoughPlayersDefault; +var private localized String KickVoteNotEnoughPlayers; + +var const String KickVoteStartedDefault; +var private localized String KickVoteStarted; + +var const String KickVoteStartedForPlayerDefault; +var private localized String KickVoteStartedForPlayer; + +var const String KickVoteNotStartedForPlayerDefault; +var private localized String KickVoteNotStartedForPlayer; + +var const String VotedPlayersDefault; +var private localized String VotedPlayers; + +var const String DidntVotePlayersDefault; +var private localized String DidntVotePlayers; + +enum E_CVC_LocalMessageType +{ + CVC_PlayerIsKickProtected, + CVC_PlayerIsStartWaveKickProtected, + CVC_PlayerCantStartKickVote, + + CVC_KickVoteNotEnoughPlayers, + CVC_KickVoteStarted, + CVC_KickVoteStartedForPlayer, + CVC_KickVoteNotStartedForPlayer, + + CVC_KickVoteYesReceived, + CVC_KickVoteNoReceived, + CVC_KickVoteStartedHUD, + CVC_KickVoteReceivedHUD, + + CVC_SkipVoteYesReceived, + CVC_SkipVoteNoReceived, + + CVC_PauseVoteYesReceived, + CVC_PauseVoteNoReceived, + + CVC_VoteProgressHUD, +}; + +private static function String ReplKicker(String Str, String Kicker) +{ + return Repl(Str, "", Kicker, false); +} + +private static function String ReplKickee(String Str, String Kickee) +{ + return Repl(Str, "", Kickee, false); +} + +private static function String ReplWaves(String Str, String Waves) +{ + return Repl(Str, "", Waves, false); +} + +public static function String GetLocalizedString( + E_LogLevel LogLevel, + E_CVC_LocalMessageType LMT, + optional String String1, + optional String String2, + optional String String3) +{ + `Log_TraceStatic(); + + switch (LMT) + { + case CVC_PlayerIsKickProtected: + return ReplKickee(default.PlayerIsKickProtected != "" ? default.PlayerIsKickProtected : default.PlayerIsKickProtectedDefault, String1); + + case CVC_PlayerIsStartWaveKickProtected: + return ReplWaves(ReplKickee(default.PlayerIsStartWaveKickProtected != "" ? default.PlayerIsStartWaveKickProtected : default.PlayerIsStartWaveKickProtectedDefault, String1), String2); + + case CVC_PlayerCantStartKickVote: + return ReplWaves(default.PlayerCantStartKickVote != "" ? default.PlayerCantStartKickVote : default.PlayerCantStartKickVoteDefault, String1); + + case CVC_KickVoteNotEnoughPlayers: + return ReplWaves(default.KickVoteNotEnoughPlayers != "" ? default.KickVoteNotEnoughPlayers : default.KickVoteNotEnoughPlayersDefault, String1); + + case CVC_KickVoteYesReceived: + return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.YesString); + + case CVC_KickVoteNoReceived: + return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.NoString); + + case CVC_KickVoteStartedHUD: + return ReplKickee(ReplKicker((default.KickVoteStarted != "" ? default.KickVoteStarted : default.KickVoteStartedDefault), String1), String2) $ "\n" $ class'KFCommon_LocalizedStrings'.default.YesString $ ":" @ String3; + + case CVC_KickVoteReceivedHUD: + return class'KFCommon_LocalizedStrings'.default.YesString $ ":" @ String1 $ "\n" $ class'KFCommon_LocalizedStrings'.default.NoString $ ":" @ String2; + + case CVC_KickVoteStarted: + return ReplKickee(ReplKicker((default.KickVoteStarted != "" ? default.KickVoteStarted : default.KickVoteStartedDefault), String1), String2); + + case CVC_KickVoteStartedForPlayer: + return ReplKicker((default.KickVoteStartedForPlayer != "" ? default.KickVoteStartedForPlayer : default.KickVoteStartedForPlayerDefault), String1); + + case CVC_KickVoteNotStartedForPlayer: + return ReplKicker((default.KickVoteNotStartedForPlayer != "" ? default.KickVoteNotStartedForPlayer : default.KickVoteNotStartedForPlayerDefault), String1); + + case CVC_SkipVoteYesReceived: + return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.YesString); + + case CVC_SkipVoteNoReceived: + return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.NoString); + + case CVC_PauseVoteYesReceived: + return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.YesString); + + case CVC_PauseVoteNoReceived: + return (String1 $ ":" @ class'KFCommon_LocalizedStrings'.default.NoString); + + case CVC_VoteProgressHUD: + return (default.DidntVotePlayers != "" ? default.DidntVotePlayers : default.DidntVotePlayersDefault) @ String2 $ (String1 != "" ? ("\n" $ (default.VotedPlayers != "" ? default.VotedPlayers : default.VotedPlayersDefault) @ String1) : ""); + } + + return ""; +} + +defaultproperties +{ + PlayerIsKickProtectedDefault = " is protected from kick" + PlayerIsStartWaveKickProtectedDefault = "You can't kick right now. He can be kicked when he plays at least wave(s)" + PlayerCantStartKickVoteDefault = "You can't start kick vote now. You can start kick vote when you play at least wave(s)" + KickVoteNotEnoughPlayersDefault = "Not enough players to start vote (only players who have played at least wave(s) can vote)" + KickVoteStartedDefault = " has started a vote to kick " + KickVoteStartedForPlayerDefault = " started voting to kick you" + KickVoteNotStartedForPlayerDefault = " tried to kick you" + VotedPlayersDefault = "Voted:" + DidntVotePlayersDefault = "Didn't vote:" } \ No newline at end of file diff --git a/CVC/Classes/CVC_RepInfo.uc b/CVC/Classes/CVC_RepInfo.uc index 6c8f63e..d69436d 100644 --- a/CVC/Classes/CVC_RepInfo.uc +++ b/CVC/Classes/CVC_RepInfo.uc @@ -1,123 +1,123 @@ -class CVC_RepInfo extends ReplicationInfo; - -const CVCLMT = class'CVC_LocalMessage'; - -var public E_LogLevel LogLevel; -var public CVC CVC; -var public int StartWave; - -var private KFPlayerController KFPC; - -replication -{ - if (bNetInitial && Role == ROLE_Authority) - LogLevel; -} - -public simulated function bool SafeDestroy() -{ - `Log_Trace(); - - return (bPendingDelete || bDeleteMe || Destroy()); -} - -public reliable client function WriteToChatLocalized(E_CVC_LocalMessageType LMT, optional String HexColor, optional String String1, optional String String2, optional String String3) -{ - `Log_Trace(); - - WriteToChat(CVCLMT.static.GetLocalizedString(LogLevel, LMT, String1, String2, String3), HexColor); -} - -public reliable client function WriteToChat(String Message, optional String HexColor) -{ - local KFGFxHudWrapper HUD; - - `Log_Trace(); - - if (GetKFPC() == None) return; - - if (KFPC.MyGFxManager.PartyWidget != None && KFPC.MyGFxManager.PartyWidget.PartyChatWidget != None) - { - KFPC.MyGFxManager.PartyWidget.PartyChatWidget.AddChatMessage(Message, HexColor); - } - - HUD = KFGFxHudWrapper(KFPC.myHUD); - if (HUD != None && HUD.HUDMovie != None && HUD.HUDMovie.HudChatBox != None) - { - HUD.HUDMovie.HudChatBox.AddChatMessage(Message, HexColor); - } -} - -public reliable client function WriteToHUDLocalized(E_CVC_LocalMessageType LMT, optional String String1, optional String String2, optional String String3, optional float DisplayTime = 0.0f) -{ - `Log_Trace(); - - WriteToHUD(CVCLMT.static.GetLocalizedString(LogLevel, LMT, String1, String2, String3), DisplayTime); -} - -public reliable client function WriteToHUD(String Message, optional float DisplayTime = 0.0f) -{ - `Log_Trace(); - - if (GetKFPC() == None) return; - - if (DisplayTime == 0.0f) - { - DisplayTime = CalcDisplayTime(Message); - } - - if (KFPC.MyGFxHUD != None) - { - KFPC.MyGFxHUD.DisplayMapText(Message, DisplayTime, false); - } -} - -public reliable client function DefferedClearMessageHUD(optional float Time = 0.0f) -{ - `Log_Trace(); - - SetTimer(Time, false, nameof(ClearMessageHUD)); -} - -public reliable client function ClearMessageHUD() -{ - `Log_Trace(); - - if (GetKFPC() == None) return; - - if (KFPC.MyGFxHUD != None && KFPC.MyGFxHUD.MapTextWidget != None) - { - KFPC.MyGFxHUD.MapTextWidget.StoredMessageList.Length = 0; - KFPC.MyGFxHUD.MapTextWidget.HideMessage(); - } -} - -private function float CalcDisplayTime(String Message) -{ - `Log_Trace(); - - return FClamp(Len(Message) / 20.0f, 3, 30); -} - -public simulated function KFPlayerController GetKFPC() -{ - `Log_Trace(); - - if (KFPC != None) return KFPC; - - KFPC = KFPlayerController(Owner); - - if (KFPC == None && ROLE < ROLE_Authority) - { - KFPC = KFPlayerController(GetALocalPlayerController()); - } - - return KFPC; -} - -defaultproperties -{ - bAlwaysRelevant = false - bOnlyRelevantToOwner = true - bSkipActorPropertyReplication = false -} +class CVC_RepInfo extends ReplicationInfo; + +const CVCLMT = class'CVC_LocalMessage'; + +var public E_LogLevel LogLevel; +var public CVC CVC; +var public int StartWave; + +var private KFPlayerController KFPC; + +replication +{ + if (bNetInitial && Role == ROLE_Authority) + LogLevel; +} + +public simulated function bool SafeDestroy() +{ + `Log_Trace(); + + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public reliable client function WriteToChatLocalized(E_CVC_LocalMessageType LMT, optional String HexColor, optional String String1, optional String String2, optional String String3) +{ + `Log_Trace(); + + WriteToChat(CVCLMT.static.GetLocalizedString(LogLevel, LMT, String1, String2, String3), HexColor); +} + +public reliable client function WriteToChat(String Message, optional String HexColor) +{ + local KFGFxHudWrapper HUD; + + `Log_Trace(); + + if (GetKFPC() == None) return; + + if (KFPC.MyGFxManager.PartyWidget != None && KFPC.MyGFxManager.PartyWidget.PartyChatWidget != None) + { + KFPC.MyGFxManager.PartyWidget.PartyChatWidget.AddChatMessage(Message, HexColor); + } + + HUD = KFGFxHudWrapper(KFPC.myHUD); + if (HUD != None && HUD.HUDMovie != None && HUD.HUDMovie.HudChatBox != None) + { + HUD.HUDMovie.HudChatBox.AddChatMessage(Message, HexColor); + } +} + +public reliable client function WriteToHUDLocalized(E_CVC_LocalMessageType LMT, optional String String1, optional String String2, optional String String3, optional float DisplayTime = 0.0f) +{ + `Log_Trace(); + + WriteToHUD(CVCLMT.static.GetLocalizedString(LogLevel, LMT, String1, String2, String3), DisplayTime); +} + +public reliable client function WriteToHUD(String Message, optional float DisplayTime = 0.0f) +{ + `Log_Trace(); + + if (GetKFPC() == None) return; + + if (DisplayTime == 0.0f) + { + DisplayTime = CalcDisplayTime(Message); + } + + if (KFPC.MyGFxHUD != None) + { + KFPC.MyGFxHUD.DisplayMapText(Message, DisplayTime, false); + } +} + +public reliable client function DefferedClearMessageHUD(optional float Time = 0.0f) +{ + `Log_Trace(); + + SetTimer(Time, false, nameof(ClearMessageHUD)); +} + +public reliable client function ClearMessageHUD() +{ + `Log_Trace(); + + if (GetKFPC() == None) return; + + if (KFPC.MyGFxHUD != None && KFPC.MyGFxHUD.MapTextWidget != None) + { + KFPC.MyGFxHUD.MapTextWidget.StoredMessageList.Length = 0; + KFPC.MyGFxHUD.MapTextWidget.HideMessage(); + } +} + +private function float CalcDisplayTime(String Message) +{ + `Log_Trace(); + + return FClamp(Len(Message) / 20.0f, 3, 30); +} + +public simulated function KFPlayerController GetKFPC() +{ + `Log_Trace(); + + if (KFPC != None) return KFPC; + + KFPC = KFPlayerController(Owner); + + if (KFPC == None && ROLE < ROLE_Authority) + { + KFPC = KFPlayerController(GetALocalPlayerController()); + } + + return KFPC; +} + +defaultproperties +{ + bAlwaysRelevant = false + bOnlyRelevantToOwner = true + bSkipActorPropertyReplication = false +} diff --git a/CVC/Classes/CVC_VoteCollector.uc b/CVC/Classes/CVC_VoteCollector.uc index 8a9d332..2e7f53d 100644 --- a/CVC/Classes/CVC_VoteCollector.uc +++ b/CVC/Classes/CVC_VoteCollector.uc @@ -1,1111 +1,1111 @@ -class CVC_VoteCollector extends KFVoteCollector; - -const CfgKickProtected = class'KickProtected'; -const CfgKickVote = class'KickVote'; -const CfgStartWaveKickProtection = class'StartWaveKickProtection'; -const CfgSkipTraderVote = class'SkipTraderVote'; -const CfgPauseVote = class'PauseVote'; -const CfgMapStat = class'MapStat'; -const CfgMapStats = class'MapStats'; -const CfgMapVote = class'MapVote'; - -struct S_KickVote -{ - var String Name; - var String SteamID; - var String UniqueID; - var bool VoteYes; - var class Perk; - var byte Level; -}; -// KickVotes[0]: Kickee -// KickVotes[1]: Kicker -// KickVotes[2...]: Voters -var private Array KickVotes; - -var public CVC CVC; -var public E_LogLevel LogLevel; - -var private KFGameInfo KFGI; - -var private KFPlayerController KFPC_Kicker; -var private KFPlayerController KFPC_Kickee; - -var private String KickerName; -var private String KickeeName; - -var private String YesVotesPlayers, NoVotesPlayers; - -var private bool AllowHudNotification; - -replication -{ - if (bNetInitial && Role == ROLE_Authority) - LogLevel; -} - -private function KFGameInfo GetKFGI() -{ - `Log_Trace(); - - if (KFGI != None) return KFGI; - - KFGI = KFGameInfo(WorldInfo.Game); - - return KFGI; -} - -public function ServerStartVoteKick(PlayerReplicationInfo PRI_Kickee, PlayerReplicationInfo PRI_Kicker) -{ - local Array KFPRIs; - local KFPlayerReplicationInfo KFPRI; - - `Log_Trace(); - - if (GetKFGI() == None) return; - - KFPC_Kicker = KFPlayerController(PRI_Kicker.Owner); - KFPC_Kickee = KFPlayerController(PRI_Kickee.Owner); - - KickerName = PRI_Kicker.PlayerName; - KickeeName = PRI_Kickee.PlayerName; - - if (KFGI.bDisableKickVote) - { - KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteDisabled); - return; - } - - if (PRI_Kicker.bOnlySpectator) - { - KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteNoSpectators); - return; - } - - if (!CVC.PlayerCanStartKickVote(KFPC_Kicker, KFPC_Kickee)) - { - CVC.WriteToChatLocalized( - KFPC_Kicker, - CVC_PlayerCantStartKickVote, - CfgKickVote.default.WarningColorHex, - String(CfgStartWaveKickProtection.default.Waves)); - return; - } - - if (CVC.PlayerIsStartWaveKickProtected(KFPC_Kickee)) - { - CVC.WriteToChatLocalized( - KFPC_Kicker, - CVC_PlayerIsStartWaveKickProtected, - CfgKickVote.default.WarningColorHex, - KickeeName, - String(CfgStartWaveKickProtection.default.Waves)); - return; - } - - if (VotingPlayers(PRI_Kickee) < CfgKickVote.default.MinVotingPlayersToStartKickVote) - { - if (CfgStartWaveKickProtection.default.Waves == 0) - { - KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteNotEnoughPlayers); - } - else - { - CVC.WriteToChatLocalized( - KFPC_Kicker, - CVC_KickVoteNotEnoughPlayers, - CfgKickVote.default.WarningColorHex, - String(CfgStartWaveKickProtection.default.Waves)); - } - return; - } - - if (KickedPlayers >= CfgKickVote.default.MaxKicks) - { - KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteMaxKicksReached); - return; - } - - if (CVC.PlayerIsKickProtected(PRI_Kickee)) - { - CVC.WriteToChatLocalized( - KFPC_Kicker, - CVC_PlayerIsKickProtected, - CfgKickVote.default.WarningColorHex, - KickeeName); - - if (CfgKickProtected.default.NotifyPlayerAboutKickAttempt) - { - CVC.WriteToChatLocalized( - KFPC_Kickee, - CVC_KickVoteNotStartedForPlayer, - CfgKickVote.default.WarningColorHex, - KickerName); - } - return; - } - - if (KFGI.AccessControl != None && KFGI.AccessControl.IsAdmin(KFPC_Kickee)) - { - KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteAdmin); - return; - } - - if (bIsFailedVoteTimerActive) - { - KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteRejected); - return; - } - - if (bIsSkipTraderVoteInProgress || bIsPauseGameVoteInProgress) - { - KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_OtherVoteInProgress); - return; - } - - if (!bIsKickVoteInProgress) - { - PlayersThatHaveVoted.Length = 0; - - CurrentKickVote.PlayerID = PRI_Kickee.UniqueId; - CurrentKickVote.PlayerPRI = PRI_Kickee; - CurrentKickVote.PlayerIPAddress = KFPC_Kickee.GetPlayerNetworkAddress(); - - bIsKickVoteInProgress = true; - - GetKFPRIArray(KFPRIs); - foreach KFPRIs(KFPRI) - { - KFPRI.ShowKickVote(PRI_Kickee, CfgKickVote.default.VoteTime, !(KFPRI == PRI_Kicker || KFPRI == PRI_Kickee)); - } - - if (CfgKickVote.default.bChatNotifications) - { - CVC.BroadcastChatLocalized( - CVC_KickVoteStarted, - CfgKickVote.default.PositiveColorHex, - KFPC_Kickee, - KickerName, - KickeeName); - - CVC.WriteToChatLocalized( - KFPC_Kickee, - CVC_KickVoteStartedForPlayer, - CfgKickVote.default.NegativeColorHex, - KickerName); - } - else - { - KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', LMT_KickVoteStarted, CurrentKickVote.PlayerPRI); - } - - if (CfgKickVote.default.bLogKickVote) - { - KickVotes.Length = 0; - KickVotes.AddItem(PlayerKickVote(PRI_Kickee, false)); - } - - if (CfgKickVote.default.bHudNotificationsOnlyOnTraderTime) - { - AllowHudNotification = bTraderIsOpen; - } - - SetTimer(CfgKickVote.default.VoteTime, false, nameof(ConcludeVoteKick), Self); - - RecieveVoteKick(PRI_Kicker, true); - } - else if (PRI_Kickee == CurrentKickVote.PlayerPRI) - { - RecieveVoteKick(PRI_Kicker, false); // WTF is that?! - `Log_Debug("WTF happens:" @ KickeeName); - } - else - { - KFPlayerController(PRI_Kicker.Owner).ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteInProgress); - } -} - -private function int VotingPlayers(optional PlayerReplicationInfo KickeePRI, optional Array KFPRIs) -{ - local KFPlayerReplicationInfo KFPRI; - local KFPlayerController KFPC; - local int VotingPlayersNum; - - `Log_Trace(); - - if (KFPRIs.Length == 0) - { - GetKFPRIArray(KFPRIs); - } - - if (KFPC_Kickee == None) - { - if (KickeePRI == None) - { - KickeePRI = CurrentKickVote.PlayerPRI; - } - if (KickeePRI != None) - { - KFPC_Kickee = KFPlayerController(KickeePRI.Owner); - } - } - - VotingPlayersNum = 0; - foreach KFPRIs(KFPRI) - { - KFPC = KFPlayerController(KFPRI.Owner); - if (KFPC != None && KFPC != KFPC_Kickee) - { - VotingPlayersNum++; - } - } - - return VotingPlayersNum; -} - -private function String DidntVotedPlayers() -{ - local Array KFPRIs; - local KFPlayerReplicationInfo KFPRI; - local String DidntVoted; - - `Log_Trace(); - - GetKFPRIArray(KFPRIs); - - foreach KFPRIs(KFPRI) - { - if (PlayersThatHaveVoted.Find(KFPRI) == INDEX_None) - { - DidntVoted $= (DidntVoted == "" ? KFPRI.PlayerName : ("," @ KFPRI.PlayerName)); - } - } - - return DidntVoted; -} - -private function String VotedPlayers() -{ - local PlayerReplicationInfo PRI; - local String Voted; - - `Log_Trace(); - - foreach PlayersThatHaveVoted(PRI) - { - Voted $= (Voted == "" ? PRI.PlayerName : ("," @ PRI.PlayerName)); - } - - return Voted; -} - -private function S_KickVote PlayerKickVote(PlayerReplicationInfo PRI, bool bKick) -{ - local KFPlayerReplicationInfo KFPRI; - local PlayerController PC; - local OnlineSubsystem OS; - local S_KickVote KV; - - `Log_Trace(); - - KV.Name = PRI.PlayerName; - KV.UniqueID = class'OnlineSubsystem'.static.UniqueNetIdToString(PRI.UniqueId); - - PC = PlayerController(PRI.Owner); - if (PC != None && !PC.bIsEosPlayer) - { - OS = class'GameEngine'.static.GetOnlineSubsystem(); - if (OS != None) - { - KV.SteamID = OS.UniqueNetIdToInt64(PRI.UniqueId); - } - } - - KV.VoteYes = bKick; - - KFPRI = KFPlayerReplicationInfo(PRI); - if (KFPRI != None) - { - KV.Perk = KFPRI.CurrentPerkClass; - KV.Level = KFPRI.GetActivePerkLevel(); - } - - return KV; -} - -public reliable server function RecieveVoteKick(PlayerReplicationInfo PRI, bool bKick) -{ - `Log_Trace(); - - // there is a bug somewhere in the TWI code: - // sometimes votes for skipping a trader or pausing come to this function - // this is an attempt to fix it without affecting other parts of the game - // probably this part can be changed when I understand when this bug occurs - if (bIsSkipTraderVoteInProgress) - { - `Log_Debug("Receive kick vote while skip trader vote is active"); - RecieveVoteSkipTrader(PRI, bKick); - return; - } - if (bIsPauseGameVoteInProgress) - { - `Log_Debug("Receive kick vote while skip pause vote is active"); - ReceiveVotePauseGame(PRI, bKick); - return; - } - if (!bIsKickVoteInProgress) - { - `Log_Debug("Receive kick vote while kick vote is not active"); - return; - } - - if (PlayersThatHaveVoted.Find(PRI) == INDEX_NONE) - { - if (bKick) - { - YesVotesPlayers = (YesVotesPlayers == "") ? PRI.PlayerName : YesVotesPlayers $ "," @ PRI.PlayerName; - } - else - { - NoVotesPlayers = (NoVotesPlayers == "") ? PRI.PlayerName : NoVotesPlayers $ "," @ PRI.PlayerName; - } - - if (CfgKickVote.default.bLogKickVote) - { - KickVotes.AddItem(PlayerKickVote(PRI, bKick)); - } - - if (CfgKickVote.default.bChatNotifications) - { - CVC.BroadcastChatLocalized( - bKick ? CVC_KickVoteYesReceived : CVC_KickVoteNoReceived, - bKick ? CfgKickVote.default.PositiveColorHex : CfgKickVote.default.NegativeColorHex, - KFPC_Kickee, - PRI.PlayerName); - - CVC.WriteToChatLocalized( - KFPC_Kickee, - bKick ? CVC_KickVoteYesReceived : CVC_KickVoteNoReceived, - bKick ? CfgKickVote.default.NegativeColorHex : CfgKickVote.default.PositiveColorHex, - PRI.PlayerName); - } - if (CfgKickVote.default.bHUDNotifications && AllowHudNotification) - { - if (NoVotesPlayers == "") - { - CVC.BroadcastHUDLocalized( - CVC_KickVoteStartedHUD, - float(CfgKickVote.default.VoteTime), - KickerName, - KickeeName, - YesVotesPlayers); - } - else - { - CVC.BroadcastHUDLocalized( - CVC_KickVoteReceivedHUD, - float(CfgKickVote.default.VoteTime), - YesVotesPlayers, - NoVotesPlayers); - } - } - } - - Super.RecieveVoteKick(PRI, bKick); -} - -public function bool ShouldConcludeKickVote() -{ - local int NumPRIs; - local int KickVotesNeeded; - - `Log_Trace(); - - if (CfgStartWaveKickProtection.default.Waves == 0) - { - return Super.ShouldConcludeKickVote(); - } - - NumPRIs = VotingPlayers(); - - if (YesVotes + NoVotes >= NumPRIs) - { - return true; - } - else if (GetKFGI() != None) - { - KickVotesNeeded = FCeil(float(NumPRIs) * KFGI.KickVotePercentage); - KickVotesNeeded = Clamp(KickVotesNeeded, 1, NumPRIs); - - if (YesVotes >= KickVotesNeeded) - { - return true; - } - else if (NoVotes > (NumPRIs - KickVotesNeeded)) - { - return true; - } - } - - return false; -} - -public reliable server function ConcludeVoteKick() -{ - local Array KFPRIs; - local KFPlayerReplicationInfo KFPRI; - local PlayerReplicationInfo PRI; - local int NumPRIs; - local KFPlayerController KickedPC; - local int KickVotesNeeded; - local int PrevKickedPlayers; - - `Log_Trace(); - - `Log_Debug("ConcludeVoteKick()" @ bIsKickVoteInProgress); - - if (bIsKickVoteInProgress) - { - YesVotesPlayers = ""; - NoVotesPlayers = ""; - - if (CfgKickVote.default.bHUDNotifications) - { - CVC.BroadcastClearMessageHUD(CfgKickVote.default.DefferedClearHUD); - } - } - - PrevKickedPlayers = KickedPlayers; - - if (CfgStartWaveKickProtection.default.Waves == 0) - { - Super.ConcludeVoteKick(); - } - else if (bIsKickVoteInProgress && GetKFGI() != None) - { - GetKFPRIArray(KFPRIs); - - foreach KFPRIs(KFPRI) KFPRI.HideKickVote(); - - NumPRIs = VotingPlayers(CurrentKickVote.PlayerPRI, KFPRIs); - - KickVotesNeeded = FCeil(float(NumPRIs) * KFGI.KickVotePercentage); - KickVotesNeeded = Clamp(KickVotesNeeded, 1, NumPRIs); - - if (YesVotes >= KickVotesNeeded) - { - if (CurrentKickVote.PlayerPRI == None || CurrentKickVote.PlayerPRI.bPendingDelete) - { - foreach WorldInfo.Game.InactivePRIArray(PRI) - { - if (PRI.UniqueId == CurrentKickVote.PlayerID) - { - CurrentKickVote.PlayerPRI = PRI; - break; - } - } - } - - if (KFGI.AccessControl != None) - { - KickedPC = ((CurrentKickVote.PlayerPRI != None) && (CurrentKickVote.PlayerPRI.Owner != None)) ? KFPlayerController(CurrentKickVote.PlayerPRI.Owner) : None; - KFAccessControl(KFGI.AccessControl).KickSessionBanPlayer(KickedPC, CurrentKickVote.PlayerID, KFGI.AccessControl.KickedMsg); - } - - KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', LMT_KickVoteSucceeded, CurrentKickVote.PlayerPRI); - KickedPlayers++; - } - else - { - bIsFailedVoteTimerActive = true; - SetTimer(KFGI.TimeBetweenFailedVotes, false, nameof(ClearFailedVoteFlag), Self); - KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', LMT_KickVoteFailed, CurrentKickVote.PlayerPRI); - } - - bIsKickVoteInProgress = false; - CurrentKickVote.PlayerPRI = None; - CurrentKickVote.PlayerID = class'PlayerReplicationInfo'.default.UniqueId; - YesVotes = 0; - NoVotes = 0; - } - - if (CfgKickVote.default.bLogKickVote && KickedPlayers > PrevKickedPlayers) - { - LogKickVotes(); - } -} - -private function LogKickVotes() -{ - local S_KickVote KV; - local S_KickVote Kicker; - local S_KickVote Kickee; - local Array Yes; - local Array No; - local int Index; - - `Log_Trace(); - - foreach KickVotes(KV, Index) - { - switch (Index) - { - case 0: Kickee = KV; break; - case 1: Kicker = KV; break; - default: if (KV.VoteYes) Yes.AddItem(KV); else No.AddItem(KV); break; - } - } - - `Log_Kick("Kicker:" @ LogVotePlayer(Kicker)); - `Log_Kick("Kicked:" @ LogVotePlayer(Kickee)); - - `Log_Kick("Yes voters:"); - foreach Yes(KV) `Log_Kick(LogVotePlayer(KV)); - - if (No.Length == 0) return; - - `Log_Kick("No voters:"); - foreach No(KV) `Log_Kick(LogVotePlayer(KV)); -} - -private function String LogVotePlayer(S_KickVote KV) -{ - `Log_Trace(); - - return KV.Name @ "(UniqueID:" @ KV.UniqueID $ (KV.SteamID == "" ? "" : (", SteamID:" @ KV.SteamID $ ", Profile:" @ "https://steamcommunity.com/profiles/" $ KV.SteamID)) $ ")" @ "Perk:" @ Repl(String(KV.Perk), "KFPerk_", "", false) @ "Level:" @ String(KV.Level); -} - -public function ServerStartVoteSkipTrader(PlayerReplicationInfo PRI) -{ - local Array KFPRIs; - local KFPlayerReplicationInfo KFPRI; - local KFPlayerController KFPC; - local byte TraderTimeRemaining; - - KFPC = KFPlayerController(PRI.Owner); - - if (GetKFGI() == None) return; - - if (PRI.bOnlySpectator) - { - KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_SkipTraderVoteNoSpectators); - return; - } - - if (!bTraderIsOpen && !bForceShowSkipTrader) - { - KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_SkipTraderIsNotOpen); - return; - } - - if (bIsKickVoteInProgress || bIsPauseGameVoteInProgress) - { - KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_OtherVoteInProgress); - return; - } - - TraderTimeRemaining = GetTraderTimeRemaining(); - if(TraderTimeRemaining <= SkipTraderVoteLimit) - { - KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_SkipTraderNoEnoughTime); - return; - } - - if (!bIsSkipTraderVoteInProgress) - { - PlayersThatHaveVoted.Length = 0; - - CurrentSkipTraderVote.PlayerID = PRI.UniqueId; - CurrentSkipTraderVote.PlayerPRI = PRI; - CurrentSkipTraderVote.PlayerIPAddress = KFPC.GetPlayerNetworkAddress(); - - bIsSkipTraderVoteInProgress = true; - - if (bStopCountDown) - { - CurrentVoteTime = CfgSkipTraderVote.default.VoteTime; - } - else - { - CurrentVoteTime = Min(CfgSkipTraderVote.default.VoteTime, TraderTimeRemaining - SkipTraderVoteLimit); - } - - GetKFPRIArray(KFPRIs, , false); - foreach KFPRIs(KFPRI) - { - KFPRI.ShowSkipTraderVote(PRI, CurrentVoteTime, !(KFPRI == PRI) && PRI.GetTeamNum() != 255); - } - - KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', LMT_SkipTraderVoteStarted, CurrentSkipTraderVote.PlayerPRI); - SetTimer(CurrentVoteTime, false, nameof(ConcludeVoteSkipTrader), Self); - SetTimer(1, true, nameof(UpdateTimer), Self); - - RecieveVoteSkipTrader(PRI, true); - - KFPlayerReplicationInfo(PRI).bAlreadyStartedASkipTraderVote = true; - } - else - { - KFPlayerController(PRI.Owner).ReceiveLocalizedMessage(class'KFLocalMessage', LMT_SkipTraderVoteInProgress); - } -} - -public reliable server function UpdateTimer() -{ - local Array KFPRIs; - local KFPlayerReplicationInfo KFPRI; - local int VoteTimeLimit; - - CurrentVoteTime--; - - VoteTimeLimit = GetTraderTimeRemaining() - SkipTraderVoteLimit; - if (!bStopCountDown && CurrentVoteTime > VoteTimeLimit) - { - CurrentVoteTime = VoteTimeLimit; - } - - GetKFPRIArray(KFPRIs, , false); - foreach KFPRIs(KFPRI) - { - KFPRI.UpdateSkipTraderTime(CurrentVoteTime); - } - - if (CurrentVoteTime <= 0) - { - ConcludeVoteSkipTrader(); - } -} - -public reliable server function RecieveVoteSkipTrader(PlayerReplicationInfo PRI, bool bSkip) -{ - local bool MustNotify; - - `Log_Trace(); - - MustNotify = (PlayersThatHaveVoted.Find(PRI) == INDEX_NONE); - - Super.RecieveVoteSkipTrader(PRI, bSkip); - - if (MustNotify) - { - if (CfgSkipTraderVote.default.bChatNotifications) - { - CVC.BroadcastChatLocalized( - bSkip ? CVC_SkipVoteYesReceived : CVC_SkipVoteNoReceived, - bSkip ? CfgSkipTraderVote.default.PositiveColorHex : CfgSkipTraderVote.default.NegativeColorHex, - None, - PRI.PlayerName); - } - if (CfgSkipTraderVote.default.bHUDNotifications) - { - CVC.BroadcastHUDLocalized( - CVC_VoteProgressHUD, - float(CfgSkipTraderVote.default.VoteTime), - VotedPlayers(), - DidntVotedPlayers()); - } - } -} - -public reliable server function ConcludeVoteSkipTrader() -{ - `Log_Trace(); - - `Log_Debug("ConcludeVoteSkipTrader()" @ bIsSkipTraderVoteInProgress); - - if (bIsSkipTraderVoteInProgress) - { - YesVotesPlayers = ""; - NoVotesPlayers = ""; - - if (CfgSkipTraderVote.default.bHUDNotifications) - { - CVC.BroadcastClearMessageHUD(CfgSkipTraderVote.default.DefferedClearHUD); - } - - ClearTimer(nameof(ConcludeVoteSkipTrader), Self); - ClearTimer(nameof(UpdateTimer), Self); - } - - Super.ConcludeVoteSkipTrader(); -} - -public function ServerStartVotePauseGame(PlayerReplicationInfo PRI) -{ - local Array KFPRIs; - local KFPlayerReplicationInfo KFPRI; - local KFPlayerController KFPC; - local byte WaveTimeRemaining; - - if (GetKFGI() == None) return; - - KFPC = KFPlayerController(PRI.Owner); - - if (PRI.bOnlySpectator) - { - KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteNoSpectators : LMT_PauseVoteNoSpectators); - return; - } - - if (bWaveIsActive) - { - KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteWaveActive : LMT_PauseVoteWaveActive); - return; - } - - if (!bEndlessMode) - { - KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_PauseVoteWrongMode); - return; - } - - if (bIsKickVoteInProgress || bIsSkipTraderVoteInProgress) - { - KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_OtherVoteInProgress); - return; - } - - WaveTimeRemaining = GetTraderTimeRemaining(); - if (WaveTimeRemaining <= PauseGameVoteLimit) - { - KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteNoEnoughTime : LMT_PauseVoteNoEnoughTime); - return; - } - - if (!bIsPauseGameVoteInProgress) - { - PlayersThatHaveVoted.Length = 0; - - CurrentPauseGameVote.PlayerID = PRI.UniqueId; - CurrentPauseGameVote.PlayerPRI = PRI; - CurrentPauseGameVote.PlayerIPAddress = KFPC.GetPlayerNetworkAddress(); - - bIsPauseGameVoteInProgress = true; - - if (bStopCountDown) - { - CurrentVoteTime = CfgPauseVote.default.VoteTime; - } - else - { - CurrentVoteTime = Min(CfgPauseVote.default.VoteTime, WaveTimeRemaining - PauseGameVoteLimit); - } - - GetKFPRIArray(KFPRIs); - foreach KFPRIs(KFPRI) - { - KFPRI.ShowPauseGameVote(PRI, CurrentVoteTime, !(KFPRI == PRI)); - } - - KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteStarted : LMT_PauseVoteStarted, CurrentPauseGameVote.PlayerPRI); - SetTimer(CurrentVoteTime, false, nameof(ConcludeVotePauseGame), Self); - SetTimer(1, true, nameof(UpdatePauseGameTimer), Self); - - ReceiveVotePauseGame(PRI, true); - - KFPlayerReplicationInfo(PRI).bAlreadyStartedAPauseGameVote = true; - } - else - { - KFPlayerController(PRI.Owner).ReceiveLocalizedMessage(class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteInProgress : LMT_PauseVoteInProgress); - } -} - -public reliable server function UpdatePauseGameTimer() // TODO: -{ - local Array KFPRIs; - local KFPlayerReplicationInfo KFPRI; - local int VoteTimeLimit; - - CurrentVoteTime--; - - VoteTimeLimit = GetTraderTimeRemaining() - PauseGameVoteLimit; - if (!bStopCountDown && CurrentVoteTime > VoteTimeLimit) - { - CurrentVoteTime = VoteTimeLimit; - } - - GetKFPRIArray(KFPRIs); - foreach KFPRIs(KFPRI) - { - KFPRI.UpdatePauseGameTime(CurrentVoteTime); - } - - if (CurrentVoteTime <= 0) - { - ConcludeVotePauseGame(); - } -} - -public reliable server function ReceiveVotePauseGame(PlayerReplicationInfo PRI, bool bSkip) -{ - local bool MustNotify; - - `Log_Trace(); - - MustNotify = (PlayersThatHaveVoted.Find(PRI) == INDEX_NONE); - - Super.ReceiveVotePauseGame(PRI, bSkip); - - if (MustNotify) - { - if (CfgPauseVote.default.bChatNotifications) - { - CVC.BroadcastChatLocalized( - bSkip ? CVC_PauseVoteYesReceived : CVC_PauseVoteNoReceived, - bSkip ? CfgPauseVote.default.PositiveColorHex : CfgPauseVote.default.NegativeColorHex, - None, - PRI.PlayerName); - } - if (CfgPauseVote.default.bHUDNotifications) - { - CVC.BroadcastHUDLocalized( - CVC_VoteProgressHUD, - float(CfgPauseVote.default.VoteTime), - VotedPlayers(), - DidntVotedPlayers()); - } - } -} - -public reliable server function ConcludeVotePauseGame() -{ - `Log_Trace(); - - `Log_Debug("ConcludeVotePauseGame()" @ bIsPauseGameVoteInProgress); - - if (bIsPauseGameVoteInProgress) - { - YesVotesPlayers = ""; - NoVotesPlayers = ""; - - if (CfgPauseVote.default.bHUDNotifications) - { - CVC.BroadcastClearMessageHUD(CfgPauseVote.default.DefferedClearHUD); - } - - ClearTimer(nameof(ConcludeVotePauseGame), Self); - ClearTimer(nameof(UpdatePauseGameTimer), Self); - } - - Super.ConcludeVotePauseGame(); -} - -private function Array ActiveMapCycle() -{ - `Log_Trace(); - - if (WorldInfo.NetMode == NM_Standalone) - { - return Maplist; - } - - if (GetKFGI() != None) - { - return KFGI.GameMapCycles[KFGI.ActiveMapCycle].Maps; - } -} - -private function Array GetAviableMaps() -{ - local String LowerDefaultNextMap; - local Array MapCycle; - local Array Maps; - local String Map; - local int Index; - - `Log_Trace(); - - if (GetKFGI() == None) return Maps; - - MapCycle = ActiveMapCycle(); - - LowerDefaultNextMap = Locs(CfgMapVote.default.DefaultNextMap); - `Log_Debug("LowerDefaultNextMap:" @ LowerDefaultNextMap); - switch (LowerDefaultNextMap) - { - case "any": - `Log_Debug("any"); - foreach MapCycle(Map) - { - if (KFGI.IsMapAllowedInCycle(Map)) - { - Maps.AddItem(Map); - } - } - break; - - case "official": - `Log_Debug("official"); - foreach MapCycle(Map) - { - if (KFGI.IsMapAllowedInCycle(Map) && !IsCustomMap(Map)) - { - Maps.AddItem(Map); - } - } - break; - - case "custom": - `Log_Debug("custom"); - foreach MapCycle(Map) - { - if (KFGI.IsMapAllowedInCycle(Map) && IsCustomMap(Map)) - { - Maps.AddItem(Map); - } - } - break; - - default: - `Log_Debug("kf-"); - if (Left(LowerDefaultNextMap, 3) == "kf-") - { - Index = MapCycle.Find(LowerDefaultNextMap); - if (Index != INDEX_NONE) - { - Maps.AddItem(MapCycle[Index]); - } - } - break; - } - - `Log_Debug("AviableMaps:"); foreach Maps(Map) `Log_Debug(Map); - - return Maps; -} - -private function bool IsCustomMap(String MapName) -{ - local KFMapSummary MapData; - - `Log_Trace(); - - MapData = class'KFUIDataStore_GameResource'.static.GetMapSummaryFromMapName(MapName); - if (MapData == None) - { - return true; - } - else - { - return (MapData.MapAssociation == EAI_Custom); - } -} - -private function int DefaultNextMapIndex() -{ - local Array AviableMaps; - local Array MapCycle; - local int CurrentMapIndex; - - `Log_Trace(); - - MapCycle = ActiveMapCycle(); - AviableMaps = GetAviableMaps(); - - if (MapCycle.Length > 0 && AviableMaps.Length > 0) - { - if (CfgMapVote.default.bRandomizeNextMap) - { - return MapCycle.Find(AviableMaps[Rand(AviableMaps.Length)]); - } - else - { - // I don't use KFGameInfo.GetNextMap() because - // it uses and changes global KFGameInfo.MapCycleIndex variable - CurrentMapIndex = MapCycle.Find(WorldInfo.GetMapName(true)); - if (CurrentMapIndex != INDEX_NONE) - { - for (++CurrentMapIndex; CurrentMapIndex < MapCycle.Length; ++CurrentMapIndex) - { - if (AviableMaps.Find(MapCycle[CurrentMapIndex]) != INDEX_NONE) - { - return CurrentMapIndex; - } - } - } - for (CurrentMapIndex = 0; CurrentMapIndex < MapCycle.Length; ++CurrentMapIndex) - { - if (AviableMaps.Find(MapCycle[CurrentMapIndex]) != INDEX_NONE) - { - return CurrentMapIndex; - } - } - } - } - - return INDEX_NONE; -} - -private function String MapNameByIndex(int MapIndex) -{ - local Array MapCycle; - - `Log_Trace(); - - if (MapIndex == INDEX_NONE) return ""; - - MapCycle = ActiveMapCycle(); - - if (MapIndex >= MapCycle.Length) return ""; - - return MapCycle[MapIndex]; -} - -public function int GetNextMap() -{ - local int MapIndex; - local String MapName; - - `Log_Trace(); - - if (CfgMapStat.default.bEnable) - { - if (WorldInfo.GRI != None) - { - CfgMapStats.static.IncMapStat( - WorldInfo.GetMapName(true), - WorldInfo.GRI.ElapsedTime / 60, - CfgMapStat.default.SortPolicy, - LogLevel); - } - else - { - `Log_Warn("WorldInfo.GRI is None, can't write map stats"); - } - } - - if (MapVoteList.Length > 0) - { - MapIndex = MapVoteList[0].MapIndex; - MapName = MapNameByIndex(MapIndex); - if (MapName != "") - { - `Log_Info("Next map (vote):" @ MapName); - } - else - { - `Log_Warn("Can't find next map (vote)"); - } - } - else - { - MapIndex = DefaultNextMapIndex(); - MapName = MapNameByIndex(MapIndex); - if (MapName != "") - { - `Log_Info("Next map (default):" @ MapName); - } - else - { - `Log_Warn("Can't find next map (default)"); - } - } - - return MapIndex; -} - -defaultproperties -{ - AllowHudNotification = true; -} +class CVC_VoteCollector extends KFVoteCollector; + +const CfgKickProtected = class'KickProtected'; +const CfgKickVote = class'KickVote'; +const CfgStartWaveKickProtection = class'StartWaveKickProtection'; +const CfgSkipTraderVote = class'SkipTraderVote'; +const CfgPauseVote = class'PauseVote'; +const CfgMapStat = class'MapStat'; +const CfgMapStats = class'MapStats'; +const CfgMapVote = class'MapVote'; + +struct S_KickVote +{ + var String Name; + var String SteamID; + var String UniqueID; + var bool VoteYes; + var class Perk; + var byte Level; +}; +// KickVotes[0]: Kickee +// KickVotes[1]: Kicker +// KickVotes[2...]: Voters +var private Array KickVotes; + +var public CVC CVC; +var public E_LogLevel LogLevel; + +var private KFGameInfo KFGI; + +var private KFPlayerController KFPC_Kicker; +var private KFPlayerController KFPC_Kickee; + +var private String KickerName; +var private String KickeeName; + +var private String YesVotesPlayers, NoVotesPlayers; + +var private bool AllowHudNotification; + +replication +{ + if (bNetInitial && Role == ROLE_Authority) + LogLevel; +} + +private function KFGameInfo GetKFGI() +{ + `Log_Trace(); + + if (KFGI != None) return KFGI; + + KFGI = KFGameInfo(WorldInfo.Game); + + return KFGI; +} + +public function ServerStartVoteKick(PlayerReplicationInfo PRI_Kickee, PlayerReplicationInfo PRI_Kicker) +{ + local Array KFPRIs; + local KFPlayerReplicationInfo KFPRI; + + `Log_Trace(); + + if (GetKFGI() == None) return; + + KFPC_Kicker = KFPlayerController(PRI_Kicker.Owner); + KFPC_Kickee = KFPlayerController(PRI_Kickee.Owner); + + KickerName = PRI_Kicker.PlayerName; + KickeeName = PRI_Kickee.PlayerName; + + if (KFGI.bDisableKickVote) + { + KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteDisabled); + return; + } + + if (PRI_Kicker.bOnlySpectator) + { + KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteNoSpectators); + return; + } + + if (!CVC.PlayerCanStartKickVote(KFPC_Kicker, KFPC_Kickee)) + { + CVC.WriteToChatLocalized( + KFPC_Kicker, + CVC_PlayerCantStartKickVote, + CfgKickVote.default.WarningColorHex, + String(CfgStartWaveKickProtection.default.Waves)); + return; + } + + if (CVC.PlayerIsStartWaveKickProtected(KFPC_Kickee)) + { + CVC.WriteToChatLocalized( + KFPC_Kicker, + CVC_PlayerIsStartWaveKickProtected, + CfgKickVote.default.WarningColorHex, + KickeeName, + String(CfgStartWaveKickProtection.default.Waves)); + return; + } + + if (VotingPlayers(PRI_Kickee) < CfgKickVote.default.MinVotingPlayersToStartKickVote) + { + if (CfgStartWaveKickProtection.default.Waves == 0) + { + KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteNotEnoughPlayers); + } + else + { + CVC.WriteToChatLocalized( + KFPC_Kicker, + CVC_KickVoteNotEnoughPlayers, + CfgKickVote.default.WarningColorHex, + String(CfgStartWaveKickProtection.default.Waves)); + } + return; + } + + if (KickedPlayers >= CfgKickVote.default.MaxKicks) + { + KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteMaxKicksReached); + return; + } + + if (CVC.PlayerIsKickProtected(PRI_Kickee)) + { + CVC.WriteToChatLocalized( + KFPC_Kicker, + CVC_PlayerIsKickProtected, + CfgKickVote.default.WarningColorHex, + KickeeName); + + if (CfgKickProtected.default.NotifyPlayerAboutKickAttempt) + { + CVC.WriteToChatLocalized( + KFPC_Kickee, + CVC_KickVoteNotStartedForPlayer, + CfgKickVote.default.WarningColorHex, + KickerName); + } + return; + } + + if (KFGI.AccessControl != None && KFGI.AccessControl.IsAdmin(KFPC_Kickee)) + { + KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteAdmin); + return; + } + + if (bIsFailedVoteTimerActive) + { + KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteRejected); + return; + } + + if (bIsSkipTraderVoteInProgress || bIsPauseGameVoteInProgress) + { + KFPC_Kicker.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_OtherVoteInProgress); + return; + } + + if (!bIsKickVoteInProgress) + { + PlayersThatHaveVoted.Length = 0; + + CurrentKickVote.PlayerID = PRI_Kickee.UniqueId; + CurrentKickVote.PlayerPRI = PRI_Kickee; + CurrentKickVote.PlayerIPAddress = KFPC_Kickee.GetPlayerNetworkAddress(); + + bIsKickVoteInProgress = true; + + GetKFPRIArray(KFPRIs); + foreach KFPRIs(KFPRI) + { + KFPRI.ShowKickVote(PRI_Kickee, CfgKickVote.default.VoteTime, !(KFPRI == PRI_Kicker || KFPRI == PRI_Kickee)); + } + + if (CfgKickVote.default.bChatNotifications) + { + CVC.BroadcastChatLocalized( + CVC_KickVoteStarted, + CfgKickVote.default.PositiveColorHex, + KFPC_Kickee, + KickerName, + KickeeName); + + CVC.WriteToChatLocalized( + KFPC_Kickee, + CVC_KickVoteStartedForPlayer, + CfgKickVote.default.NegativeColorHex, + KickerName); + } + else + { + KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', LMT_KickVoteStarted, CurrentKickVote.PlayerPRI); + } + + if (CfgKickVote.default.bLogKickVote) + { + KickVotes.Length = 0; + KickVotes.AddItem(PlayerKickVote(PRI_Kickee, false)); + } + + if (CfgKickVote.default.bHudNotificationsOnlyOnTraderTime) + { + AllowHudNotification = bTraderIsOpen; + } + + SetTimer(CfgKickVote.default.VoteTime, false, nameof(ConcludeVoteKick), Self); + + RecieveVoteKick(PRI_Kicker, true); + } + else if (PRI_Kickee == CurrentKickVote.PlayerPRI) + { + RecieveVoteKick(PRI_Kicker, false); // WTF is that?! + `Log_Debug("WTF happens:" @ KickeeName); + } + else + { + KFPlayerController(PRI_Kicker.Owner).ReceiveLocalizedMessage(class'KFLocalMessage', LMT_KickVoteInProgress); + } +} + +private function int VotingPlayers(optional PlayerReplicationInfo KickeePRI, optional Array KFPRIs) +{ + local KFPlayerReplicationInfo KFPRI; + local KFPlayerController KFPC; + local int VotingPlayersNum; + + `Log_Trace(); + + if (KFPRIs.Length == 0) + { + GetKFPRIArray(KFPRIs); + } + + if (KFPC_Kickee == None) + { + if (KickeePRI == None) + { + KickeePRI = CurrentKickVote.PlayerPRI; + } + if (KickeePRI != None) + { + KFPC_Kickee = KFPlayerController(KickeePRI.Owner); + } + } + + VotingPlayersNum = 0; + foreach KFPRIs(KFPRI) + { + KFPC = KFPlayerController(KFPRI.Owner); + if (KFPC != None && KFPC != KFPC_Kickee) + { + VotingPlayersNum++; + } + } + + return VotingPlayersNum; +} + +private function String DidntVotedPlayers() +{ + local Array KFPRIs; + local KFPlayerReplicationInfo KFPRI; + local String DidntVoted; + + `Log_Trace(); + + GetKFPRIArray(KFPRIs); + + foreach KFPRIs(KFPRI) + { + if (PlayersThatHaveVoted.Find(KFPRI) == INDEX_None) + { + DidntVoted $= (DidntVoted == "" ? KFPRI.PlayerName : ("," @ KFPRI.PlayerName)); + } + } + + return DidntVoted; +} + +private function String VotedPlayers() +{ + local PlayerReplicationInfo PRI; + local String Voted; + + `Log_Trace(); + + foreach PlayersThatHaveVoted(PRI) + { + Voted $= (Voted == "" ? PRI.PlayerName : ("," @ PRI.PlayerName)); + } + + return Voted; +} + +private function S_KickVote PlayerKickVote(PlayerReplicationInfo PRI, bool bKick) +{ + local KFPlayerReplicationInfo KFPRI; + local PlayerController PC; + local OnlineSubsystem OS; + local S_KickVote KV; + + `Log_Trace(); + + KV.Name = PRI.PlayerName; + KV.UniqueID = class'OnlineSubsystem'.static.UniqueNetIdToString(PRI.UniqueId); + + PC = PlayerController(PRI.Owner); + if (PC != None && !PC.bIsEosPlayer) + { + OS = class'GameEngine'.static.GetOnlineSubsystem(); + if (OS != None) + { + KV.SteamID = OS.UniqueNetIdToInt64(PRI.UniqueId); + } + } + + KV.VoteYes = bKick; + + KFPRI = KFPlayerReplicationInfo(PRI); + if (KFPRI != None) + { + KV.Perk = KFPRI.CurrentPerkClass; + KV.Level = KFPRI.GetActivePerkLevel(); + } + + return KV; +} + +public reliable server function RecieveVoteKick(PlayerReplicationInfo PRI, bool bKick) +{ + `Log_Trace(); + + // there is a bug somewhere in the TWI code: + // sometimes votes for skipping a trader or pausing come to this function + // this is an attempt to fix it without affecting other parts of the game + // probably this part can be changed when I understand when this bug occurs + if (bIsSkipTraderVoteInProgress) + { + `Log_Debug("Receive kick vote while skip trader vote is active"); + RecieveVoteSkipTrader(PRI, bKick); + return; + } + if (bIsPauseGameVoteInProgress) + { + `Log_Debug("Receive kick vote while skip pause vote is active"); + ReceiveVotePauseGame(PRI, bKick); + return; + } + if (!bIsKickVoteInProgress) + { + `Log_Debug("Receive kick vote while kick vote is not active"); + return; + } + + if (PlayersThatHaveVoted.Find(PRI) == INDEX_NONE) + { + if (bKick) + { + YesVotesPlayers = (YesVotesPlayers == "") ? PRI.PlayerName : YesVotesPlayers $ "," @ PRI.PlayerName; + } + else + { + NoVotesPlayers = (NoVotesPlayers == "") ? PRI.PlayerName : NoVotesPlayers $ "," @ PRI.PlayerName; + } + + if (CfgKickVote.default.bLogKickVote) + { + KickVotes.AddItem(PlayerKickVote(PRI, bKick)); + } + + if (CfgKickVote.default.bChatNotifications) + { + CVC.BroadcastChatLocalized( + bKick ? CVC_KickVoteYesReceived : CVC_KickVoteNoReceived, + bKick ? CfgKickVote.default.PositiveColorHex : CfgKickVote.default.NegativeColorHex, + KFPC_Kickee, + PRI.PlayerName); + + CVC.WriteToChatLocalized( + KFPC_Kickee, + bKick ? CVC_KickVoteYesReceived : CVC_KickVoteNoReceived, + bKick ? CfgKickVote.default.NegativeColorHex : CfgKickVote.default.PositiveColorHex, + PRI.PlayerName); + } + if (CfgKickVote.default.bHUDNotifications && AllowHudNotification) + { + if (NoVotesPlayers == "") + { + CVC.BroadcastHUDLocalized( + CVC_KickVoteStartedHUD, + float(CfgKickVote.default.VoteTime), + KickerName, + KickeeName, + YesVotesPlayers); + } + else + { + CVC.BroadcastHUDLocalized( + CVC_KickVoteReceivedHUD, + float(CfgKickVote.default.VoteTime), + YesVotesPlayers, + NoVotesPlayers); + } + } + } + + Super.RecieveVoteKick(PRI, bKick); +} + +public function bool ShouldConcludeKickVote() +{ + local int NumPRIs; + local int KickVotesNeeded; + + `Log_Trace(); + + if (CfgStartWaveKickProtection.default.Waves == 0) + { + return Super.ShouldConcludeKickVote(); + } + + NumPRIs = VotingPlayers(); + + if (YesVotes + NoVotes >= NumPRIs) + { + return true; + } + else if (GetKFGI() != None) + { + KickVotesNeeded = FCeil(float(NumPRIs) * KFGI.KickVotePercentage); + KickVotesNeeded = Clamp(KickVotesNeeded, 1, NumPRIs); + + if (YesVotes >= KickVotesNeeded) + { + return true; + } + else if (NoVotes > (NumPRIs - KickVotesNeeded)) + { + return true; + } + } + + return false; +} + +public reliable server function ConcludeVoteKick() +{ + local Array KFPRIs; + local KFPlayerReplicationInfo KFPRI; + local PlayerReplicationInfo PRI; + local int NumPRIs; + local KFPlayerController KickedPC; + local int KickVotesNeeded; + local int PrevKickedPlayers; + + `Log_Trace(); + + `Log_Debug("ConcludeVoteKick()" @ bIsKickVoteInProgress); + + if (bIsKickVoteInProgress) + { + YesVotesPlayers = ""; + NoVotesPlayers = ""; + + if (CfgKickVote.default.bHUDNotifications) + { + CVC.BroadcastClearMessageHUD(CfgKickVote.default.DefferedClearHUD); + } + } + + PrevKickedPlayers = KickedPlayers; + + if (CfgStartWaveKickProtection.default.Waves == 0) + { + Super.ConcludeVoteKick(); + } + else if (bIsKickVoteInProgress && GetKFGI() != None) + { + GetKFPRIArray(KFPRIs); + + foreach KFPRIs(KFPRI) KFPRI.HideKickVote(); + + NumPRIs = VotingPlayers(CurrentKickVote.PlayerPRI, KFPRIs); + + KickVotesNeeded = FCeil(float(NumPRIs) * KFGI.KickVotePercentage); + KickVotesNeeded = Clamp(KickVotesNeeded, 1, NumPRIs); + + if (YesVotes >= KickVotesNeeded) + { + if (CurrentKickVote.PlayerPRI == None || CurrentKickVote.PlayerPRI.bPendingDelete) + { + foreach WorldInfo.Game.InactivePRIArray(PRI) + { + if (PRI.UniqueId == CurrentKickVote.PlayerID) + { + CurrentKickVote.PlayerPRI = PRI; + break; + } + } + } + + if (KFGI.AccessControl != None) + { + KickedPC = ((CurrentKickVote.PlayerPRI != None) && (CurrentKickVote.PlayerPRI.Owner != None)) ? KFPlayerController(CurrentKickVote.PlayerPRI.Owner) : None; + KFAccessControl(KFGI.AccessControl).KickSessionBanPlayer(KickedPC, CurrentKickVote.PlayerID, KFGI.AccessControl.KickedMsg); + } + + KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', LMT_KickVoteSucceeded, CurrentKickVote.PlayerPRI); + KickedPlayers++; + } + else + { + bIsFailedVoteTimerActive = true; + SetTimer(KFGI.TimeBetweenFailedVotes, false, nameof(ClearFailedVoteFlag), Self); + KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', LMT_KickVoteFailed, CurrentKickVote.PlayerPRI); + } + + bIsKickVoteInProgress = false; + CurrentKickVote.PlayerPRI = None; + CurrentKickVote.PlayerID = class'PlayerReplicationInfo'.default.UniqueId; + YesVotes = 0; + NoVotes = 0; + } + + if (CfgKickVote.default.bLogKickVote && KickedPlayers > PrevKickedPlayers) + { + LogKickVotes(); + } +} + +private function LogKickVotes() +{ + local S_KickVote KV; + local S_KickVote Kicker; + local S_KickVote Kickee; + local Array Yes; + local Array No; + local int Index; + + `Log_Trace(); + + foreach KickVotes(KV, Index) + { + switch (Index) + { + case 0: Kickee = KV; break; + case 1: Kicker = KV; break; + default: if (KV.VoteYes) Yes.AddItem(KV); else No.AddItem(KV); break; + } + } + + `Log_Kick("Kicker:" @ LogVotePlayer(Kicker)); + `Log_Kick("Kicked:" @ LogVotePlayer(Kickee)); + + `Log_Kick("Yes voters:"); + foreach Yes(KV) `Log_Kick(LogVotePlayer(KV)); + + if (No.Length == 0) return; + + `Log_Kick("No voters:"); + foreach No(KV) `Log_Kick(LogVotePlayer(KV)); +} + +private function String LogVotePlayer(S_KickVote KV) +{ + `Log_Trace(); + + return KV.Name @ "(UniqueID:" @ KV.UniqueID $ (KV.SteamID == "" ? "" : (", SteamID:" @ KV.SteamID $ ", Profile:" @ "https://steamcommunity.com/profiles/" $ KV.SteamID)) $ ")" @ "Perk:" @ Repl(String(KV.Perk), "KFPerk_", "", false) @ "Level:" @ String(KV.Level); +} + +public function ServerStartVoteSkipTrader(PlayerReplicationInfo PRI) +{ + local Array KFPRIs; + local KFPlayerReplicationInfo KFPRI; + local KFPlayerController KFPC; + local byte TraderTimeRemaining; + + KFPC = KFPlayerController(PRI.Owner); + + if (GetKFGI() == None) return; + + if (PRI.bOnlySpectator) + { + KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_SkipTraderVoteNoSpectators); + return; + } + + if (!bTraderIsOpen && !bForceShowSkipTrader) + { + KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_SkipTraderIsNotOpen); + return; + } + + if (bIsKickVoteInProgress || bIsPauseGameVoteInProgress) + { + KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_OtherVoteInProgress); + return; + } + + TraderTimeRemaining = GetTraderTimeRemaining(); + if(TraderTimeRemaining <= SkipTraderVoteLimit) + { + KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_SkipTraderNoEnoughTime); + return; + } + + if (!bIsSkipTraderVoteInProgress) + { + PlayersThatHaveVoted.Length = 0; + + CurrentSkipTraderVote.PlayerID = PRI.UniqueId; + CurrentSkipTraderVote.PlayerPRI = PRI; + CurrentSkipTraderVote.PlayerIPAddress = KFPC.GetPlayerNetworkAddress(); + + bIsSkipTraderVoteInProgress = true; + + if (bStopCountDown) + { + CurrentVoteTime = CfgSkipTraderVote.default.VoteTime; + } + else + { + CurrentVoteTime = Min(CfgSkipTraderVote.default.VoteTime, TraderTimeRemaining - SkipTraderVoteLimit); + } + + GetKFPRIArray(KFPRIs, , false); + foreach KFPRIs(KFPRI) + { + KFPRI.ShowSkipTraderVote(PRI, CurrentVoteTime, !(KFPRI == PRI) && PRI.GetTeamNum() != 255); + } + + KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', LMT_SkipTraderVoteStarted, CurrentSkipTraderVote.PlayerPRI); + SetTimer(CurrentVoteTime, false, nameof(ConcludeVoteSkipTrader), Self); + SetTimer(1, true, nameof(UpdateTimer), Self); + + RecieveVoteSkipTrader(PRI, true); + + KFPlayerReplicationInfo(PRI).bAlreadyStartedASkipTraderVote = true; + } + else + { + KFPlayerController(PRI.Owner).ReceiveLocalizedMessage(class'KFLocalMessage', LMT_SkipTraderVoteInProgress); + } +} + +public reliable server function UpdateTimer() +{ + local Array KFPRIs; + local KFPlayerReplicationInfo KFPRI; + local int VoteTimeLimit; + + CurrentVoteTime--; + + VoteTimeLimit = GetTraderTimeRemaining() - SkipTraderVoteLimit; + if (!bStopCountDown && CurrentVoteTime > VoteTimeLimit) + { + CurrentVoteTime = VoteTimeLimit; + } + + GetKFPRIArray(KFPRIs, , false); + foreach KFPRIs(KFPRI) + { + KFPRI.UpdateSkipTraderTime(CurrentVoteTime); + } + + if (CurrentVoteTime <= 0) + { + ConcludeVoteSkipTrader(); + } +} + +public reliable server function RecieveVoteSkipTrader(PlayerReplicationInfo PRI, bool bSkip) +{ + local bool MustNotify; + + `Log_Trace(); + + MustNotify = (PlayersThatHaveVoted.Find(PRI) == INDEX_NONE); + + Super.RecieveVoteSkipTrader(PRI, bSkip); + + if (MustNotify) + { + if (CfgSkipTraderVote.default.bChatNotifications) + { + CVC.BroadcastChatLocalized( + bSkip ? CVC_SkipVoteYesReceived : CVC_SkipVoteNoReceived, + bSkip ? CfgSkipTraderVote.default.PositiveColorHex : CfgSkipTraderVote.default.NegativeColorHex, + None, + PRI.PlayerName); + } + if (CfgSkipTraderVote.default.bHUDNotifications) + { + CVC.BroadcastHUDLocalized( + CVC_VoteProgressHUD, + float(CfgSkipTraderVote.default.VoteTime), + VotedPlayers(), + DidntVotedPlayers()); + } + } +} + +public reliable server function ConcludeVoteSkipTrader() +{ + `Log_Trace(); + + `Log_Debug("ConcludeVoteSkipTrader()" @ bIsSkipTraderVoteInProgress); + + if (bIsSkipTraderVoteInProgress) + { + YesVotesPlayers = ""; + NoVotesPlayers = ""; + + if (CfgSkipTraderVote.default.bHUDNotifications) + { + CVC.BroadcastClearMessageHUD(CfgSkipTraderVote.default.DefferedClearHUD); + } + + ClearTimer(nameof(ConcludeVoteSkipTrader), Self); + ClearTimer(nameof(UpdateTimer), Self); + } + + Super.ConcludeVoteSkipTrader(); +} + +public function ServerStartVotePauseGame(PlayerReplicationInfo PRI) +{ + local Array KFPRIs; + local KFPlayerReplicationInfo KFPRI; + local KFPlayerController KFPC; + local byte WaveTimeRemaining; + + if (GetKFGI() == None) return; + + KFPC = KFPlayerController(PRI.Owner); + + if (PRI.bOnlySpectator) + { + KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteNoSpectators : LMT_PauseVoteNoSpectators); + return; + } + + if (bWaveIsActive) + { + KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteWaveActive : LMT_PauseVoteWaveActive); + return; + } + + if (!bEndlessMode) + { + KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_PauseVoteWrongMode); + return; + } + + if (bIsKickVoteInProgress || bIsSkipTraderVoteInProgress) + { + KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', LMT_OtherVoteInProgress); + return; + } + + WaveTimeRemaining = GetTraderTimeRemaining(); + if (WaveTimeRemaining <= PauseGameVoteLimit) + { + KFPC.ReceiveLocalizedMessage(class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteNoEnoughTime : LMT_PauseVoteNoEnoughTime); + return; + } + + if (!bIsPauseGameVoteInProgress) + { + PlayersThatHaveVoted.Length = 0; + + CurrentPauseGameVote.PlayerID = PRI.UniqueId; + CurrentPauseGameVote.PlayerPRI = PRI; + CurrentPauseGameVote.PlayerIPAddress = KFPC.GetPlayerNetworkAddress(); + + bIsPauseGameVoteInProgress = true; + + if (bStopCountDown) + { + CurrentVoteTime = CfgPauseVote.default.VoteTime; + } + else + { + CurrentVoteTime = Min(CfgPauseVote.default.VoteTime, WaveTimeRemaining - PauseGameVoteLimit); + } + + GetKFPRIArray(KFPRIs); + foreach KFPRIs(KFPRI) + { + KFPRI.ShowPauseGameVote(PRI, CurrentVoteTime, !(KFPRI == PRI)); + } + + KFGI.BroadcastLocalized(KFGI, class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteStarted : LMT_PauseVoteStarted, CurrentPauseGameVote.PlayerPRI); + SetTimer(CurrentVoteTime, false, nameof(ConcludeVotePauseGame), Self); + SetTimer(1, true, nameof(UpdatePauseGameTimer), Self); + + ReceiveVotePauseGame(PRI, true); + + KFPlayerReplicationInfo(PRI).bAlreadyStartedAPauseGameVote = true; + } + else + { + KFPlayerController(PRI.Owner).ReceiveLocalizedMessage(class'KFLocalMessage', bIsEndlessPaused ? LMT_ResumeVoteInProgress : LMT_PauseVoteInProgress); + } +} + +public reliable server function UpdatePauseGameTimer() // TODO: +{ + local Array KFPRIs; + local KFPlayerReplicationInfo KFPRI; + local int VoteTimeLimit; + + CurrentVoteTime--; + + VoteTimeLimit = GetTraderTimeRemaining() - PauseGameVoteLimit; + if (!bStopCountDown && CurrentVoteTime > VoteTimeLimit) + { + CurrentVoteTime = VoteTimeLimit; + } + + GetKFPRIArray(KFPRIs); + foreach KFPRIs(KFPRI) + { + KFPRI.UpdatePauseGameTime(CurrentVoteTime); + } + + if (CurrentVoteTime <= 0) + { + ConcludeVotePauseGame(); + } +} + +public reliable server function ReceiveVotePauseGame(PlayerReplicationInfo PRI, bool bSkip) +{ + local bool MustNotify; + + `Log_Trace(); + + MustNotify = (PlayersThatHaveVoted.Find(PRI) == INDEX_NONE); + + Super.ReceiveVotePauseGame(PRI, bSkip); + + if (MustNotify) + { + if (CfgPauseVote.default.bChatNotifications) + { + CVC.BroadcastChatLocalized( + bSkip ? CVC_PauseVoteYesReceived : CVC_PauseVoteNoReceived, + bSkip ? CfgPauseVote.default.PositiveColorHex : CfgPauseVote.default.NegativeColorHex, + None, + PRI.PlayerName); + } + if (CfgPauseVote.default.bHUDNotifications) + { + CVC.BroadcastHUDLocalized( + CVC_VoteProgressHUD, + float(CfgPauseVote.default.VoteTime), + VotedPlayers(), + DidntVotedPlayers()); + } + } +} + +public reliable server function ConcludeVotePauseGame() +{ + `Log_Trace(); + + `Log_Debug("ConcludeVotePauseGame()" @ bIsPauseGameVoteInProgress); + + if (bIsPauseGameVoteInProgress) + { + YesVotesPlayers = ""; + NoVotesPlayers = ""; + + if (CfgPauseVote.default.bHUDNotifications) + { + CVC.BroadcastClearMessageHUD(CfgPauseVote.default.DefferedClearHUD); + } + + ClearTimer(nameof(ConcludeVotePauseGame), Self); + ClearTimer(nameof(UpdatePauseGameTimer), Self); + } + + Super.ConcludeVotePauseGame(); +} + +private function Array ActiveMapCycle() +{ + `Log_Trace(); + + if (WorldInfo.NetMode == NM_Standalone) + { + return Maplist; + } + + if (GetKFGI() != None) + { + return KFGI.GameMapCycles[KFGI.ActiveMapCycle].Maps; + } +} + +private function Array GetAviableMaps() +{ + local String LowerDefaultNextMap; + local Array MapCycle; + local Array Maps; + local String Map; + local int Index; + + `Log_Trace(); + + if (GetKFGI() == None) return Maps; + + MapCycle = ActiveMapCycle(); + + LowerDefaultNextMap = Locs(CfgMapVote.default.DefaultNextMap); + `Log_Debug("LowerDefaultNextMap:" @ LowerDefaultNextMap); + switch (LowerDefaultNextMap) + { + case "any": + `Log_Debug("any"); + foreach MapCycle(Map) + { + if (KFGI.IsMapAllowedInCycle(Map)) + { + Maps.AddItem(Map); + } + } + break; + + case "official": + `Log_Debug("official"); + foreach MapCycle(Map) + { + if (KFGI.IsMapAllowedInCycle(Map) && !IsCustomMap(Map)) + { + Maps.AddItem(Map); + } + } + break; + + case "custom": + `Log_Debug("custom"); + foreach MapCycle(Map) + { + if (KFGI.IsMapAllowedInCycle(Map) && IsCustomMap(Map)) + { + Maps.AddItem(Map); + } + } + break; + + default: + `Log_Debug("kf-"); + if (Left(LowerDefaultNextMap, 3) == "kf-") + { + Index = MapCycle.Find(LowerDefaultNextMap); + if (Index != INDEX_NONE) + { + Maps.AddItem(MapCycle[Index]); + } + } + break; + } + + `Log_Debug("AviableMaps:"); foreach Maps(Map) `Log_Debug(Map); + + return Maps; +} + +private function bool IsCustomMap(String MapName) +{ + local KFMapSummary MapData; + + `Log_Trace(); + + MapData = class'KFUIDataStore_GameResource'.static.GetMapSummaryFromMapName(MapName); + if (MapData == None) + { + return true; + } + else + { + return (MapData.MapAssociation == EAI_Custom); + } +} + +private function int DefaultNextMapIndex() +{ + local Array AviableMaps; + local Array MapCycle; + local int CurrentMapIndex; + + `Log_Trace(); + + MapCycle = ActiveMapCycle(); + AviableMaps = GetAviableMaps(); + + if (MapCycle.Length > 0 && AviableMaps.Length > 0) + { + if (CfgMapVote.default.bRandomizeNextMap) + { + return MapCycle.Find(AviableMaps[Rand(AviableMaps.Length)]); + } + else + { + // I don't use KFGameInfo.GetNextMap() because + // it uses and changes global KFGameInfo.MapCycleIndex variable + CurrentMapIndex = MapCycle.Find(WorldInfo.GetMapName(true)); + if (CurrentMapIndex != INDEX_NONE) + { + for (++CurrentMapIndex; CurrentMapIndex < MapCycle.Length; ++CurrentMapIndex) + { + if (AviableMaps.Find(MapCycle[CurrentMapIndex]) != INDEX_NONE) + { + return CurrentMapIndex; + } + } + } + for (CurrentMapIndex = 0; CurrentMapIndex < MapCycle.Length; ++CurrentMapIndex) + { + if (AviableMaps.Find(MapCycle[CurrentMapIndex]) != INDEX_NONE) + { + return CurrentMapIndex; + } + } + } + } + + return INDEX_NONE; +} + +private function String MapNameByIndex(int MapIndex) +{ + local Array MapCycle; + + `Log_Trace(); + + if (MapIndex == INDEX_NONE) return ""; + + MapCycle = ActiveMapCycle(); + + if (MapIndex >= MapCycle.Length) return ""; + + return MapCycle[MapIndex]; +} + +public function int GetNextMap() +{ + local int MapIndex; + local String MapName; + + `Log_Trace(); + + if (CfgMapStat.default.bEnable) + { + if (WorldInfo.GRI != None) + { + CfgMapStats.static.IncMapStat( + WorldInfo.GetMapName(true), + WorldInfo.GRI.ElapsedTime / 60, + CfgMapStat.default.SortPolicy, + LogLevel); + } + else + { + `Log_Warn("WorldInfo.GRI is None, can't write map stats"); + } + } + + if (MapVoteList.Length > 0) + { + MapIndex = MapVoteList[0].MapIndex; + MapName = MapNameByIndex(MapIndex); + if (MapName != "") + { + `Log_Info("Next map (vote):" @ MapName); + } + else + { + `Log_Warn("Can't find next map (vote)"); + } + } + else + { + MapIndex = DefaultNextMapIndex(); + MapName = MapNameByIndex(MapIndex); + if (MapName != "") + { + `Log_Info("Next map (default):" @ MapName); + } + else + { + `Log_Warn("Can't find next map (default)"); + } + } + + return MapIndex; +} + +defaultproperties +{ + AllowHudNotification = true; +} diff --git a/CVC/Classes/KickProtected.uc b/CVC/Classes/KickProtected.uc index 36f5b94..abf1476 100644 --- a/CVC/Classes/KickProtected.uc +++ b/CVC/Classes/KickProtected.uc @@ -1,82 +1,82 @@ -class KickProtected extends Object - config(CVC) - abstract; - -var public config bool NotifyPlayerAboutKickAttempt; -var private config Array PlayerID; - -public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - switch (Version) - { - case `NO_CONFIG: - ApplyDefault(LogLevel); - - default: break; - } - - if (LatestVersion != Version) - { - StaticSaveConfig(); - } -} - -public static function Array Load(E_LogLevel LogLevel) -{ - local Array UIDs; - local UniqueNetId UID; - local String ID; - - `Log_TraceStatic(); - - foreach default.PlayerID(ID) - { - if (AnyToUID(ID, UID, LogLevel)) - { - UIDs.AddItem(UID); - } - else - { - `Log_Warn("Can't load PlayerID:" @ ID); - } - } - - return UIDs; -} - -private static function ApplyDefault(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - default.NotifyPlayerAboutKickAttempt = true; - default.PlayerID.Length = 0; - default.PlayerID.AddItem("76561190000000000"); - default.PlayerID.AddItem("0x0000000000000000"); -} - -private static function bool IsUID(String ID, E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - return (Left(ID, 2) ~= "0x"); -} - -private static function bool AnyToUID(String ID, out UniqueNetId UID, E_LogLevel LogLevel) -{ - local OnlineSubsystem OS; - - `Log_TraceStatic(); - - OS = class'GameEngine'.static.GetOnlineSubsystem(); - - if (OS == None) return false; - - return IsUID(ID, LogLevel) ? OS.StringToUniqueNetId(ID, UID) : OS.Int64ToUniqueNetId(ID, UID); -} - -defaultproperties -{ - -} +class KickProtected extends Object + config(CVC) + abstract; + +var public config bool NotifyPlayerAboutKickAttempt; +var private config Array PlayerID; + +public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + switch (Version) + { + case `NO_CONFIG: + ApplyDefault(LogLevel); + + default: break; + } + + if (LatestVersion != Version) + { + StaticSaveConfig(); + } +} + +public static function Array Load(E_LogLevel LogLevel) +{ + local Array UIDs; + local UniqueNetId UID; + local String ID; + + `Log_TraceStatic(); + + foreach default.PlayerID(ID) + { + if (AnyToUID(ID, UID, LogLevel)) + { + UIDs.AddItem(UID); + } + else + { + `Log_Warn("Can't load PlayerID:" @ ID); + } + } + + return UIDs; +} + +private static function ApplyDefault(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + default.NotifyPlayerAboutKickAttempt = true; + default.PlayerID.Length = 0; + default.PlayerID.AddItem("76561190000000000"); + default.PlayerID.AddItem("0x0000000000000000"); +} + +private static function bool IsUID(String ID, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + return (Left(ID, 2) ~= "0x"); +} + +private static function bool AnyToUID(String ID, out UniqueNetId UID, E_LogLevel LogLevel) +{ + local OnlineSubsystem OS; + + `Log_TraceStatic(); + + OS = class'GameEngine'.static.GetOnlineSubsystem(); + + if (OS == None) return false; + + return IsUID(ID, LogLevel) ? OS.StringToUniqueNetId(ID, UID) : OS.Int64ToUniqueNetId(ID, UID); +} + +defaultproperties +{ + +} diff --git a/CVC/Classes/KickVote.uc b/CVC/Classes/KickVote.uc index 6598a18..64a308f 100644 --- a/CVC/Classes/KickVote.uc +++ b/CVC/Classes/KickVote.uc @@ -1,52 +1,52 @@ -class KickVote extends BaseVote - config(CVC) - abstract; - -var public config bool bHudNotificationsOnlyOnTraderTime; -var public config int MinVotingPlayersToStartKickVote; -var public config int MaxKicks; -var public config bool bLogKickVote; -var public config String WarningColorHex; - -public static function Load(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - if (default.MinVotingPlayersToStartKickVote < 2) - { - `Log_Error("MinVotingPlayersToStartKickVote" @ "(" $ default.MinVotingPlayersToStartKickVote $ ")" @ "must be greater than 1"); - default.MinVotingPlayersToStartKickVote = 2; - } - - if (default.MaxKicks < 1) - { - `Log_Error("MaxKicks" @ "(" $ default.MaxKicks $ ")" @ "must be greater than 0"); - default.MaxKicks = 2; - } - - if (!IsValidHexColor(default.WarningColorHex, LogLevel)) - { - `Log_Error("WarningColorHex" @ "(" $ default.WarningColorHex $ ")" @ "is not valid hex color"); - default.WarningColorHex = class'KFLocalMessage'.default.PriorityColor; - } - - Super.Load(LogLevel); -} - -protected static function ApplyDefault(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - Super.ApplyDefault(LogLevel); - - default.bHudNotificationsOnlyOnTraderTime = true; - default.MinVotingPlayersToStartKickVote = 2; - default.MaxKicks = 2; - default.DefferedClearHUD = 2.0f; - default.WarningColorHex = class'KFLocalMessage'.default.PriorityColor; -} - -defaultproperties -{ - -} +class KickVote extends BaseVote + config(CVC) + abstract; + +var public config bool bHudNotificationsOnlyOnTraderTime; +var public config int MinVotingPlayersToStartKickVote; +var public config int MaxKicks; +var public config bool bLogKickVote; +var public config String WarningColorHex; + +public static function Load(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + if (default.MinVotingPlayersToStartKickVote < 2) + { + `Log_Error("MinVotingPlayersToStartKickVote" @ "(" $ default.MinVotingPlayersToStartKickVote $ ")" @ "must be greater than 1"); + default.MinVotingPlayersToStartKickVote = 2; + } + + if (default.MaxKicks < 1) + { + `Log_Error("MaxKicks" @ "(" $ default.MaxKicks $ ")" @ "must be greater than 0"); + default.MaxKicks = 2; + } + + if (!IsValidHexColor(default.WarningColorHex, LogLevel)) + { + `Log_Error("WarningColorHex" @ "(" $ default.WarningColorHex $ ")" @ "is not valid hex color"); + default.WarningColorHex = class'KFLocalMessage'.default.PriorityColor; + } + + Super.Load(LogLevel); +} + +protected static function ApplyDefault(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + Super.ApplyDefault(LogLevel); + + default.bHudNotificationsOnlyOnTraderTime = true; + default.MinVotingPlayersToStartKickVote = 2; + default.MaxKicks = 2; + default.DefferedClearHUD = 2.0f; + default.WarningColorHex = class'KFLocalMessage'.default.PriorityColor; +} + +defaultproperties +{ + +} diff --git a/CVC/Classes/MapStat.uc b/CVC/Classes/MapStat.uc index 0a0755e..ef6e67f 100644 --- a/CVC/Classes/MapStat.uc +++ b/CVC/Classes/MapStat.uc @@ -1,57 +1,57 @@ -class MapStat extends Object - config(CVC) - abstract; - -var public config bool bEnable; -var public config String SortPolicy; - -public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - switch (Version) - { - case `NO_CONFIG: - ApplyDefault(LogLevel); - - default: break; - } - - if (LatestVersion != Version) - { - StaticSaveConfig(); - } -} - -public static function Load(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - switch (Locs(default.SortPolicy)) - { - case "counterasc": return; - case "counterdesc": return; - case "nameasc": return; - case "namedesc": return; - case "playtimetotalasc": return; - case "playtimetotaldesc": return; - case "playtimeavgasc": return; - case "playtimeavgdesc": return; - } - - `Log_Error("Can't load SortPolicy (" $ default.SortPolicy $ "), must be one of: CounterAsc CounterDesc NameAsc NameDesc PlaytimeTotalAsc PlaytimeTotalDesc PlaytimeAvgAsc PlaytimeAvgDesc"); - default.SortPolicy = "CounterDesc"; -} - -protected static function ApplyDefault(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - default.bEnable = false; - default.SortPolicy = "CounterDesc"; -} - -defaultproperties -{ - -} +class MapStat extends Object + config(CVC) + abstract; + +var public config bool bEnable; +var public config String SortPolicy; + +public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + switch (Version) + { + case `NO_CONFIG: + ApplyDefault(LogLevel); + + default: break; + } + + if (LatestVersion != Version) + { + StaticSaveConfig(); + } +} + +public static function Load(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + switch (Locs(default.SortPolicy)) + { + case "counterasc": return; + case "counterdesc": return; + case "nameasc": return; + case "namedesc": return; + case "playtimetotalasc": return; + case "playtimetotaldesc": return; + case "playtimeavgasc": return; + case "playtimeavgdesc": return; + } + + `Log_Error("Can't load SortPolicy (" $ default.SortPolicy $ "), must be one of: CounterAsc CounterDesc NameAsc NameDesc PlaytimeTotalAsc PlaytimeTotalDesc PlaytimeAvgAsc PlaytimeAvgDesc"); + default.SortPolicy = "CounterDesc"; +} + +protected static function ApplyDefault(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + default.bEnable = false; + default.SortPolicy = "CounterDesc"; +} + +defaultproperties +{ + +} diff --git a/CVC/Classes/MapStats.uc b/CVC/Classes/MapStats.uc index 9b3854c..4ff33e6 100644 --- a/CVC/Classes/MapStats.uc +++ b/CVC/Classes/MapStats.uc @@ -1,70 +1,70 @@ -class MapStats extends Object - config(MapStats); - -struct MapStatEntry -{ - var String Name; // map - var int Counter; // play count - var int PlayTimeTotal; // minutes total - var int PlayTimeAvg; // minutes per map -}; -var config array MapStat; - -static delegate int CounterAsc (MapStatEntry A, MapStatEntry B) { return B.Counter < A.Counter ? -1 : 0; } -static delegate int CounterDesc (MapStatEntry A, MapStatEntry B) { return A.Counter < B.Counter ? -1 : 0; } -static delegate int NameAsc (MapStatEntry A, MapStatEntry B) { return B.Name < A.Name ? -1 : 0; } -static delegate int NameDesc (MapStatEntry A, MapStatEntry B) { return A.Name < B.Name ? -1 : 0; } -static delegate int PlayTimeTotalAsc (MapStatEntry A, MapStatEntry B) { return B.PlayTimeTotal < A.PlayTimeTotal ? -1 : 0; } -static delegate int PlayTimeTotalDesc (MapStatEntry A, MapStatEntry B) { return A.PlayTimeTotal < B.PlayTimeTotal ? -1 : 0; } -static delegate int PlayTimeAvgAsc (MapStatEntry A, MapStatEntry B) { return B.PlayTimeAvg < A.PlayTimeAvg ? -1 : 0; } -static delegate int PlayTimeAvgDesc (MapStatEntry A, MapStatEntry B) { return A.PlayTimeAvg < B.PlayTimeAvg ? -1 : 0; } - -static function SortMapStat(String SortPolicy, E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - switch (Locs(SortPolicy)) - { - case "counterasc": default.MapStat.Sort(CounterAsc); break; - case "counterdesc": default.MapStat.Sort(CounterDesc); break; - case "nameasc": default.MapStat.Sort(NameAsc); break; - case "namedesc": default.MapStat.Sort(NameDesc); break; - case "playtimetotalasc": default.MapStat.Sort(PlayTimeTotalAsc); break; - case "playtimetotaldesc": default.MapStat.Sort(PlayTimeTotalDesc); break; - case "playtimeavgasc": default.MapStat.Sort(PlayTimeAvgAsc); break; - case "playtimeavgdesc": default.MapStat.Sort(PlayTimeAvgDesc); break; - } -} - -static function IncMapStat(String Map, int PlayTime, String SortPolicy, E_LogLevel LogLevel) -{ - local int MapStatEntryIndex; - local MapStatEntry NewEntry; - - `Log_TraceStatic(); - - MapStatEntryIndex = default.MapStat.Find('Name', Map); - if (MapStatEntryIndex == INDEX_NONE) - { - NewEntry.Name = Map; - NewEntry.Counter = 1; - NewEntry.PlayTimeTotal = PlayTime; - NewEntry.PlayTimeAvg = PlayTime; - default.MapStat.AddItem(NewEntry); - } - else - { - default.MapStat[MapStatEntryIndex].Counter++; - default.MapStat[MapStatEntryIndex].PlayTimeTotal += PlayTime; - default.MapStat[MapStatEntryIndex].PlayTimeAvg = default.MapStat[MapStatEntryIndex].PlayTimeTotal / default.MapStat[MapStatEntryIndex].Counter; - } - - SortMapStat(SortPolicy, LogLevel); - - StaticSaveConfig(); -} - -defaultproperties -{ - -} +class MapStats extends Object + config(MapStats); + +struct MapStatEntry +{ + var String Name; // map + var int Counter; // play count + var int PlayTimeTotal; // minutes total + var int PlayTimeAvg; // minutes per map +}; +var config array MapStat; + +static delegate int CounterAsc (MapStatEntry A, MapStatEntry B) { return B.Counter < A.Counter ? -1 : 0; } +static delegate int CounterDesc (MapStatEntry A, MapStatEntry B) { return A.Counter < B.Counter ? -1 : 0; } +static delegate int NameAsc (MapStatEntry A, MapStatEntry B) { return B.Name < A.Name ? -1 : 0; } +static delegate int NameDesc (MapStatEntry A, MapStatEntry B) { return A.Name < B.Name ? -1 : 0; } +static delegate int PlayTimeTotalAsc (MapStatEntry A, MapStatEntry B) { return B.PlayTimeTotal < A.PlayTimeTotal ? -1 : 0; } +static delegate int PlayTimeTotalDesc (MapStatEntry A, MapStatEntry B) { return A.PlayTimeTotal < B.PlayTimeTotal ? -1 : 0; } +static delegate int PlayTimeAvgAsc (MapStatEntry A, MapStatEntry B) { return B.PlayTimeAvg < A.PlayTimeAvg ? -1 : 0; } +static delegate int PlayTimeAvgDesc (MapStatEntry A, MapStatEntry B) { return A.PlayTimeAvg < B.PlayTimeAvg ? -1 : 0; } + +static function SortMapStat(String SortPolicy, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + switch (Locs(SortPolicy)) + { + case "counterasc": default.MapStat.Sort(CounterAsc); break; + case "counterdesc": default.MapStat.Sort(CounterDesc); break; + case "nameasc": default.MapStat.Sort(NameAsc); break; + case "namedesc": default.MapStat.Sort(NameDesc); break; + case "playtimetotalasc": default.MapStat.Sort(PlayTimeTotalAsc); break; + case "playtimetotaldesc": default.MapStat.Sort(PlayTimeTotalDesc); break; + case "playtimeavgasc": default.MapStat.Sort(PlayTimeAvgAsc); break; + case "playtimeavgdesc": default.MapStat.Sort(PlayTimeAvgDesc); break; + } +} + +static function IncMapStat(String Map, int PlayTime, String SortPolicy, E_LogLevel LogLevel) +{ + local int MapStatEntryIndex; + local MapStatEntry NewEntry; + + `Log_TraceStatic(); + + MapStatEntryIndex = default.MapStat.Find('Name', Map); + if (MapStatEntryIndex == INDEX_NONE) + { + NewEntry.Name = Map; + NewEntry.Counter = 1; + NewEntry.PlayTimeTotal = PlayTime; + NewEntry.PlayTimeAvg = PlayTime; + default.MapStat.AddItem(NewEntry); + } + else + { + default.MapStat[MapStatEntryIndex].Counter++; + default.MapStat[MapStatEntryIndex].PlayTimeTotal += PlayTime; + default.MapStat[MapStatEntryIndex].PlayTimeAvg = default.MapStat[MapStatEntryIndex].PlayTimeTotal / default.MapStat[MapStatEntryIndex].Counter; + } + + SortMapStat(SortPolicy, LogLevel); + + StaticSaveConfig(); +} + +defaultproperties +{ + +} diff --git a/CVC/Classes/MapVote.uc b/CVC/Classes/MapVote.uc index 2e9b2bb..2e30ee8 100644 --- a/CVC/Classes/MapVote.uc +++ b/CVC/Classes/MapVote.uc @@ -1,57 +1,57 @@ -class MapVote extends Object - config(CVC) - abstract; - -var public config String DefaultNextMap; // Any, Official, Custom, KF- -var public config bool bRandomizeNextMap; - -public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - switch (Version) - { - case `NO_CONFIG: - ApplyDefault(LogLevel); - - default: break; - } - - if (LatestVersion != Version) - { - StaticSaveConfig(); - } -} - -public static function Load(E_LogLevel LogLevel) -{ - local String LowerDefaultNextMap; - - `Log_TraceStatic(); - - LowerDefaultNextMap = Locs(default.DefaultNextMap); - - switch (LowerDefaultNextMap) - { - case "any": return; - case "official": return; - case "custom": return; - default: if (Left(LowerDefaultNextMap, 3) == "kf-") return; - } - - `Log_Error("Can't load DefaultNextMap (" $ default.DefaultNextMap $ "), must be one of: Any Official Custom KF-"); - default.DefaultNextMap = "Any"; -} - -protected static function ApplyDefault(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - default.bRandomizeNextMap = true; - default.DefaultNextMap = "Any"; -} - -defaultproperties -{ - -} +class MapVote extends Object + config(CVC) + abstract; + +var public config String DefaultNextMap; // Any, Official, Custom, KF- +var public config bool bRandomizeNextMap; + +public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + switch (Version) + { + case `NO_CONFIG: + ApplyDefault(LogLevel); + + default: break; + } + + if (LatestVersion != Version) + { + StaticSaveConfig(); + } +} + +public static function Load(E_LogLevel LogLevel) +{ + local String LowerDefaultNextMap; + + `Log_TraceStatic(); + + LowerDefaultNextMap = Locs(default.DefaultNextMap); + + switch (LowerDefaultNextMap) + { + case "any": return; + case "official": return; + case "custom": return; + default: if (Left(LowerDefaultNextMap, 3) == "kf-") return; + } + + `Log_Error("Can't load DefaultNextMap (" $ default.DefaultNextMap $ "), must be one of: Any Official Custom KF-"); + default.DefaultNextMap = "Any"; +} + +protected static function ApplyDefault(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + default.bRandomizeNextMap = true; + default.DefaultNextMap = "Any"; +} + +defaultproperties +{ + +} diff --git a/CVC/Classes/PauseVote.uc b/CVC/Classes/PauseVote.uc index c685449..f490513 100644 --- a/CVC/Classes/PauseVote.uc +++ b/CVC/Classes/PauseVote.uc @@ -1,19 +1,19 @@ -class PauseVote extends BaseVote - config(CVC) - abstract; - -protected static function ApplyDefault(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - Super.ApplyDefault(LogLevel); - - default.PositiveColorHex = class'KFLocalMessage'.default.GameColor; - default.bChatNotifications = false; - default.bHudNotifications = false; -} - -defaultproperties -{ - -} +class PauseVote extends BaseVote + config(CVC) + abstract; + +protected static function ApplyDefault(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + Super.ApplyDefault(LogLevel); + + default.PositiveColorHex = class'KFLocalMessage'.default.GameColor; + default.bChatNotifications = false; + default.bHudNotifications = false; +} + +defaultproperties +{ + +} diff --git a/CVC/Classes/SkipTraderVote.uc b/CVC/Classes/SkipTraderVote.uc index a0c3c20..47a4ea0 100644 --- a/CVC/Classes/SkipTraderVote.uc +++ b/CVC/Classes/SkipTraderVote.uc @@ -1,19 +1,19 @@ -class SkipTraderVote extends BaseVote - config(CVC) - abstract; - -protected static function ApplyDefault(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - Super.ApplyDefault(LogLevel); - - default.PositiveColorHex = class'KFLocalMessage'.default.GameColor; - default.bChatNotifications = false; - default.bHudNotifications = false; -} - -defaultproperties -{ - -} +class SkipTraderVote extends BaseVote + config(CVC) + abstract; + +protected static function ApplyDefault(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + Super.ApplyDefault(LogLevel); + + default.PositiveColorHex = class'KFLocalMessage'.default.GameColor; + default.bChatNotifications = false; + default.bHudNotifications = false; +} + +defaultproperties +{ + +} diff --git a/CVC/Classes/StartWaveKickProtection.uc b/CVC/Classes/StartWaveKickProtection.uc index 2dcacbc..0ecdb8f 100644 --- a/CVC/Classes/StartWaveKickProtection.uc +++ b/CVC/Classes/StartWaveKickProtection.uc @@ -1,54 +1,54 @@ -class StartWaveKickProtection extends Object - config(CVC) - abstract; - -var public config int Waves; -var public config int MinLevel; - -public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - switch (Version) - { - case `NO_CONFIG: - ApplyDefault(LogLevel); - - default: break; - } - - if (LatestVersion != Version) - { - StaticSaveConfig(); - } -} - -public static function Load(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - if (default.Waves < 0) - { - `Log_Error("Waves" @ "(" $ default.Waves $ ")" @ "must be greater than or equal 0"); - default.Waves = 0; - } - - if (default.MinLevel < 0 || default.MinLevel > 25) - { - `Log_Error("MinLevel" @ "(" $ default.MinLevel $ ")" @ "must be in range 0-25"); - default.MinLevel = 0; - } -} - -protected static function ApplyDefault(E_LogLevel LogLevel) -{ - `Log_TraceStatic(); - - default.Waves = 0; - default.MinLevel = 0; -} - -defaultproperties -{ - -} +class StartWaveKickProtection extends Object + config(CVC) + abstract; + +var public config int Waves; +var public config int MinLevel; + +public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + switch (Version) + { + case `NO_CONFIG: + ApplyDefault(LogLevel); + + default: break; + } + + if (LatestVersion != Version) + { + StaticSaveConfig(); + } +} + +public static function Load(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + if (default.Waves < 0) + { + `Log_Error("Waves" @ "(" $ default.Waves $ ")" @ "must be greater than or equal 0"); + default.Waves = 0; + } + + if (default.MinLevel < 0 || default.MinLevel > 25) + { + `Log_Error("MinLevel" @ "(" $ default.MinLevel $ ")" @ "must be in range 0-25"); + default.MinLevel = 0; + } +} + +protected static function ApplyDefault(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + default.Waves = 0; + default.MinLevel = 0; +} + +defaultproperties +{ + +} diff --git a/CVC/Classes/_Logger.uc b/CVC/Classes/_Logger.uc index 837a570..6186eb3 100644 --- a/CVC/Classes/_Logger.uc +++ b/CVC/Classes/_Logger.uc @@ -1,21 +1,21 @@ -class _Logger extends Object - abstract; - -enum E_LogLevel -{ - LL_WrongLevel, - LL_None, - LL_Fatal, - LL_Error, - LL_Warning, - LL_Kick, - LL_Info, - LL_Debug, - LL_Trace, - LL_All -}; - -defaultproperties -{ - -} +class _Logger extends Object + abstract; + +enum E_LogLevel +{ + LL_WrongLevel, + LL_None, + LL_Fatal, + LL_Error, + LL_Warning, + LL_Kick, + LL_Info, + LL_Debug, + LL_Trace, + LL_All +}; + +defaultproperties +{ + +} diff --git a/CVC/Constants.uci b/CVC/Constants.uci index 1003f19..432fa68 100644 --- a/CVC/Constants.uci +++ b/CVC/Constants.uci @@ -1,2 +1,2 @@ -// Constants -`define NO_CONFIG 0 +// Constants +`define NO_CONFIG 0 diff --git a/CVC/Globals.uci b/CVC/Globals.uci index a48ac52..4dcd4fb 100644 --- a/CVC/Globals.uci +++ b/CVC/Globals.uci @@ -1,3 +1,3 @@ -// Imports -`include(Logger.uci) -`include(Constants.uci) +// Imports +`include(Logger.uci) +`include(Constants.uci) diff --git a/CVC/Logger.uci b/CVC/Logger.uci index 208c3d4..bd2a100 100644 --- a/CVC/Logger.uci +++ b/CVC/Logger.uci @@ -1,16 +1,16 @@ -// Logger -`define Log_Tag 'CVC' - -`define LocationStatic "`{ClassName}::" $ GetFuncName() - -`define Log_Base(msg, cond) `log(`msg `if(`cond), `cond`{endif}, `Log_Tag) - -`define Log_Fatal(msg) `log("FATAL:" @ `msg, (LogLevel >= LL_Fatal), `Log_Tag) -`define Log_Error(msg) `log("ERROR:" @ `msg, (LogLevel >= LL_Error), `Log_Tag) -`define Log_Warn(msg) `log("WARN:" @ `msg, (LogLevel >= LL_Warning), `Log_Tag) -`define Log_Kick(msg) `log("KICK:" @ `msg, (LogLevel >= LL_Kick), `Log_Tag) -`define Log_Info(msg) `log("INFO:" @ `msg, (LogLevel >= LL_Info), `Log_Tag) -`define Log_Debug(msg) `log("DEBUG:" @ `msg, (LogLevel >= LL_Debug), `Log_Tag) - -`define Log_Trace(msg) `log("TRACE:" @ `Location `if(`msg) @ `msg`{endif}, (LogLevel >= LL_Trace), `Log_Tag) -`define Log_TraceStatic(msg) `log("TRACE:" @ `LocationStatic `if(`msg) @ `msg`{endif}, (LogLevel >= LL_Trace), `Log_Tag) +// Logger +`define Log_Tag 'CVC' + +`define LocationStatic "`{ClassName}::" $ GetFuncName() + +`define Log_Base(msg, cond) `log(`msg `if(`cond), `cond`{endif}, `Log_Tag) + +`define Log_Fatal(msg) `log("FATAL:" @ `msg, (LogLevel >= LL_Fatal), `Log_Tag) +`define Log_Error(msg) `log("ERROR:" @ `msg, (LogLevel >= LL_Error), `Log_Tag) +`define Log_Warn(msg) `log("WARN:" @ `msg, (LogLevel >= LL_Warning), `Log_Tag) +`define Log_Kick(msg) `log("KICK:" @ `msg, (LogLevel >= LL_Kick), `Log_Tag) +`define Log_Info(msg) `log("INFO:" @ `msg, (LogLevel >= LL_Info), `Log_Tag) +`define Log_Debug(msg) `log("DEBUG:" @ `msg, (LogLevel >= LL_Debug), `Log_Tag) + +`define Log_Trace(msg) `log("TRACE:" @ `Location `if(`msg) @ `msg`{endif}, (LogLevel >= LL_Trace), `Log_Tag) +`define Log_TraceStatic(msg) `log("TRACE:" @ `LocationStatic `if(`msg) @ `msg`{endif}, (LogLevel >= LL_Trace), `Log_Tag) diff --git a/Localization/INT/CVC.int b/Localization/INT/CVC.int index 3368cd2..118aaf2 100644 Binary files a/Localization/INT/CVC.int and b/Localization/INT/CVC.int differ diff --git a/Localization/RUS/CVC.rus b/Localization/RUS/CVC.rus index 457fcf4..706ecf1 100644 Binary files a/Localization/RUS/CVC.rus and b/Localization/RUS/CVC.rus differ diff --git a/README.md b/README.md index e68f162..c6253f9 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ [![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/GenZmeY/KF2-ControlledVoteCollector)](https://github.com/GenZmeY/KF2-ControlledVoteCollector/tags) [![GitHub](https://img.shields.io/github/license/GenZmeY/KF2-ControlledVoteCollector)](LICENSE) -# Description +## Description New vote collector with improvements and features. -# Features +## Features - map statistics; - default/next map setting; - anonymous or public voting; @@ -17,10 +17,10 @@ New vote collector with improvements and features. - kick voting setup; - early kick protection. -# Usage & Setup +## Usage & Setup [See steam workshop page](https://steamcommunity.com/sharedfiles/filedetails/?id=2847465899) -# Build +## Build **Note:** If you want to build/test/brew/publish a mutator without git-bash and/or scripts, follow [these instructions](https://tripwireinteractive.atlassian.net/wiki/spaces/KF2SW/pages/26247172/KF2+Code+Modding+How-to) instead of what is described here. 1. Install [Killing Floor 2](https://store.steampowered.com/app/232090/Killing_Floor_2/), Killing Floor 2 - SDK and [git for windows](https://git-scm.com/download/win); 2. open git-bash and go to any folder where you want to store sources: @@ -34,9 +34,9 @@ New vote collector with improvements and features. 5. The compiled files will be here: `C:\Users\\Documents\My Games\KillingFloor2\KFGame\Unpublished\BrewedPC\Script\` -# Bug reports +## Bug reports If you find a bug, go to the [issue page](https://github.com/GenZmeY/KF2-ControlledVoteCollector/issues) and check if there is a description of your bug. If not, create a new issue. Describe what the bug looks like and how reproduce it. -# License +## License [GNU GPLv3](LICENSE) diff --git a/builder.cfg b/builder.cfg index 9a2944f..5953297 100644 --- a/builder.cfg +++ b/builder.cfg @@ -7,7 +7,7 @@ StripSource="True" # Mutators to be compiled # Specify them with a space as a separator, -# Mutators will be compiled in the specified order +# Mutators will be compiled in the specified order PackageBuildOrder="CVC" @@ -16,7 +16,7 @@ PackageBuildOrder="CVC" # Packages you want to brew using @peelz's patched KFEditor. # Useful for cases where regular brew doesn't put *.upk inside the package. # Specify them with a space as a separator, -# The order doesn't matter +# The order doesn't matter PackagePeelzBrew="" @@ -24,7 +24,7 @@ PackagePeelzBrew="" # Mutators that will be uploaded to the workshop # Specify them with a space as a separator, -# The order doesn't matter +# The order doesn't matter PackageUpload="CVC"