From ea86df8d86772e617b57a1d71df0f3a6dec0d1f6 Mon Sep 17 00:00:00 2001 From: NockyCZ <63038995+NockyCZ@users.noreply.github.com> Date: Tue, 4 Jun 2024 20:35:34 +0200 Subject: [PATCH] Update v1.1.4 --- source/DeathmachAPI/DeathmatchAPI.cs | 24 ++++ source/DeathmachAPI/DeathmatchAPI.csproj | 9 ++ source/DeathmachAPI/Events.cs | 5 + source/DeathmachAPI/Helpers.cs | 16 +++ source/Deathmatch/API.cs | 87 ++++++++++++ source/{ => Deathmatch}/Common/Classes.cs | 15 -- source/{ => Deathmatch}/Common/Collections.cs | 21 +-- source/{ => Deathmatch}/Common/Enums.cs | 0 source/{ => Deathmatch}/Common/Globals.cs | 12 +- source/{ => Deathmatch}/Configs.cs | 4 +- source/{ => Deathmatch}/Deathmatch.cs | 101 ++++++++----- source/{ => Deathmatch}/Deathmatch.csproj | 1 + source/{ => Deathmatch}/Events.cs | 122 +++++++++++++++- source/{ => Deathmatch}/Functions/Commands.cs | 0 source/{ => Deathmatch}/Functions/Entities.cs | 0 source/{ => Deathmatch}/Functions/Menus.cs | 0 source/{ => Deathmatch}/Functions/Players.cs | 133 +++++------------- source/{ => Deathmatch}/Functions/Spawns.cs | 78 +++++----- source/{ => Deathmatch}/Functions/Weapons.cs | 108 +++++++------- 19 files changed, 485 insertions(+), 251 deletions(-) create mode 100644 source/DeathmachAPI/DeathmatchAPI.cs create mode 100644 source/DeathmachAPI/DeathmatchAPI.csproj create mode 100644 source/DeathmachAPI/Events.cs create mode 100644 source/DeathmachAPI/Helpers.cs create mode 100644 source/Deathmatch/API.cs rename source/{ => Deathmatch}/Common/Classes.cs (60%) rename source/{ => Deathmatch}/Common/Collections.cs (68%) rename source/{ => Deathmatch}/Common/Enums.cs (100%) rename source/{ => Deathmatch}/Common/Globals.cs (62%) rename source/{ => Deathmatch}/Configs.cs (98%) rename source/{ => Deathmatch}/Deathmatch.cs (77%) rename source/{ => Deathmatch}/Deathmatch.csproj (83%) rename source/{ => Deathmatch}/Events.cs (74%) rename source/{ => Deathmatch}/Functions/Commands.cs (100%) rename source/{ => Deathmatch}/Functions/Entities.cs (100%) rename source/{ => Deathmatch}/Functions/Menus.cs (100%) rename source/{ => Deathmatch}/Functions/Players.cs (79%) rename source/{ => Deathmatch}/Functions/Spawns.cs (88%) rename source/{ => Deathmatch}/Functions/Weapons.cs (62%) diff --git a/source/DeathmachAPI/DeathmatchAPI.cs b/source/DeathmachAPI/DeathmatchAPI.cs new file mode 100644 index 0000000..ce0d334 --- /dev/null +++ b/source/DeathmachAPI/DeathmatchAPI.cs @@ -0,0 +1,24 @@ +using DeathmatchAPI.Events; +using DeathmatchAPI.Helpers; + +namespace DeathmatchAPI; + +public interface IDeathmatchAPI +{ + public void StartCustomMode(int modeId); + public void ChangeNextMode(int modeId); + public void AddCustomMode(int modeId, ModeData mode); + public void ChangeCheckDistance(int distance); + + /* + Team String - Available values: ct | t + Spawns Dictionary - Vector & QAngle to string + */ + public void SetupCustomSpawns(string team, Dictionary spawns); + public void SwapHudMessageVisibility(bool visible); + public int GetActiveModeId(); + public int GetActiveModeRemainingTime(); + public Dictionary GetCustomModes(); + public event EventHandler DeathmatchEventHandlers; + public void TriggerEvent(IDeathmatchEventsAPI @event); +} \ No newline at end of file diff --git a/source/DeathmachAPI/DeathmatchAPI.csproj b/source/DeathmachAPI/DeathmatchAPI.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/source/DeathmachAPI/DeathmatchAPI.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/source/DeathmachAPI/Events.cs b/source/DeathmachAPI/Events.cs new file mode 100644 index 0000000..ebc74c2 --- /dev/null +++ b/source/DeathmachAPI/Events.cs @@ -0,0 +1,5 @@ +namespace DeathmatchAPI.Events; +public interface IDeathmatchEventsAPI +{ + public record OnCustomModeStarted(int modeId) : IDeathmatchEventsAPI; +} \ No newline at end of file diff --git a/source/DeathmachAPI/Helpers.cs b/source/DeathmachAPI/Helpers.cs new file mode 100644 index 0000000..7ceff6c --- /dev/null +++ b/source/DeathmachAPI/Helpers.cs @@ -0,0 +1,16 @@ +namespace DeathmatchAPI.Helpers; + +public class ModeData +{ + public required string Name { get; set; } + public required int Interval { get; set; } + public required int Armor { get; set; } + public required bool OnlyHS { get; set; } + public required bool KnifeDamage { get; set; } + public required bool RandomWeapons { get; set; } + public required string CenterMessageText { get; set; } + public List? PrimaryWeapons { get; set; } + public List? SecondaryWeapons { get; set; } + public List? Utilities { get; set; } + public List? ExecuteCommands { get; set; } +} \ No newline at end of file diff --git a/source/Deathmatch/API.cs b/source/Deathmatch/API.cs new file mode 100644 index 0000000..4a96319 --- /dev/null +++ b/source/Deathmatch/API.cs @@ -0,0 +1,87 @@ +using DeathmatchAPI; +using DeathmatchAPI.Events; +using DeathmatchAPI.Helpers; + +namespace Deathmatch; + +public partial class Deathmatch : IDeathmatchAPI +{ + public event EventHandler? DeathmatchEventHandlers; + public void TriggerEvent(IDeathmatchEventsAPI @event) + { + DeathmatchEventHandlers?.Invoke(this, @event); + } + + public void StartCustomMode(int modeId) + { + if (!CustomModes.ContainsKey(modeId.ToString())) + throw new Exception($"A Custom mode with ID '{modeId}' cannot be started, because this mode does not exist!"); + + SetupCustomMode(modeId.ToString()); + } + + public void ChangeNextMode(int modeId) + { + if (!CustomModes.ContainsKey(modeId.ToString())) + throw new Exception($"A Custom mode with ID '{modeId}' cannot be set as next mode, because this mode does not exist!"); + + NextMode = modeId; + } + + public void AddCustomMode(int modeId, ModeData mode) + { + if (CustomModes.ContainsKey(modeId.ToString())) + throw new Exception($"A Custom mode with ID '{modeId}' cannot be added, because this mode already exists!"); + + CustomModes.Add(modeId.ToString(), mode); + } + + public void ChangeCheckDistance(int distance) + { + CheckedEnemiesDistance = distance; + } + + public void SetupCustomSpawns(string team, Dictionary spawns) + { + if (team.Equals("ct")) + { + spawnPositionsCT.Clear(); + foreach (var spawn in spawns) + { + spawnPositionsCT.Add(ParseVector(spawn.Key), ParseQAngle(spawn.Value)); + } + } + else if (team.Equals("t")) + { + spawnPositionsT.Clear(); + foreach (var spawn in spawns) + { + spawnPositionsT.Add(ParseVector(spawn.Key), ParseQAngle(spawn.Value)); + } + } + else + { + throw new Exception($"Invalid team name '{team}'! Allowed options: ct , t"); + } + } + + public void SwapHudMessageVisibility(bool visible) + { + VisibleHud = visible; + } + + public int GetActiveModeId() + { + return ActiveCustomMode; + } + + public int GetActiveModeRemainingTime() + { + return RemainingTime; + } + + public Dictionary GetCustomModes() + { + return CustomModes; + } +} \ No newline at end of file diff --git a/source/Common/Classes.cs b/source/Deathmatch/Common/Classes.cs similarity index 60% rename from source/Common/Classes.cs rename to source/Deathmatch/Common/Classes.cs index 9d2808f..7554f31 100644 --- a/source/Common/Classes.cs +++ b/source/Deathmatch/Common/Classes.cs @@ -4,21 +4,6 @@ namespace Deathmatch { public partial class Deathmatch { - public class ModeData - { - public required string Name { get; set; } - public required int Interval { get; set; } - public required int Armor { get; set; } - public required bool OnlyHS { get; set; } - public required bool KnifeDamage { get; set; } - public required bool RandomWeapons { get; set; } - public required string CenterMessageText { get; set; } - public List? PrimaryWeapons { get; set; } - public List? SecondaryWeapons { get; set; } - public List? Utilities { get; set; } - public List? ExecuteCommands { get; set; } - } - public class DeathmatchPlayerData { public required string PrimaryWeapon { get; set; } diff --git a/source/Common/Collections.cs b/source/Deathmatch/Common/Collections.cs similarity index 68% rename from source/Common/Collections.cs rename to source/Deathmatch/Common/Collections.cs index c64195e..7ab1578 100644 --- a/source/Common/Collections.cs +++ b/source/Deathmatch/Common/Collections.cs @@ -1,21 +1,22 @@ using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; +using DeathmatchAPI.Helpers; using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; namespace Deathmatch { public partial class Deathmatch { - public Dictionary CustomModes = new(); - public Dictionary>> RestrictedWeapons = new(); + public static Dictionary CustomModes = new(); + public static Dictionary>> RestrictedWeapons = new(); public static Dictionary spawnPositionsCT = new(); public static Dictionary spawnPositionsT = new(); internal static PlayerCache playerData = new PlayerCache(); - public List<(string, bool, int)> PrefsMenuSounds = new(); - public List<(string, bool, int)> PrefsMenuFunctions = new(); - public List AllowedPrimaryWeaponsList = new List(); - public List AllowedSecondaryWeaponsList = new List(); - public List blockRandomWeaponsIntegeration = new List(); + public static List<(string, bool, int)> PrefsMenuSounds = new(); + public static List<(string, bool, int)> PrefsMenuFunctions = new(); + public static List AllowedPrimaryWeaponsList = new List(); + public static List AllowedSecondaryWeaponsList = new List(); + public static List blockRandomWeaponsIntegeration = new List(); readonly Dictionary weaponSelectMapping = new Dictionary { @@ -25,14 +26,14 @@ public partial class Deathmatch { "m4a1", "weapon_m4a1_silencer" } }; - readonly HashSet SecondaryWeaponsList = new HashSet + readonly HashSet SecondaryWeaponsList = new() { "weapon_hkp2000", "weapon_cz75a", "weapon_deagle", "weapon_elite", "weapon_fiveseven", "weapon_glock", "weapon_p250", "weapon_revolver", "weapon_tec9", "weapon_usp_silencer" }; - readonly HashSet PrimaryWeaponsList = new HashSet + readonly HashSet PrimaryWeaponsList = new() { "weapon_mag7", "weapon_nova", "weapon_sawedoff", "weapon_xm1014", "weapon_m249", "weapon_negev", "weapon_mac10", "weapon_mp5sd", @@ -42,7 +43,7 @@ public partial class Deathmatch "weapon_awp", "weapon_g3sg1", "weapon_scar20", "weapon_ssg08" }; - readonly HashSet RadioMessagesList = new HashSet + readonly HashSet RadioMessagesList = new() { "coverme", "takepoint", "holdpos", "followme", "regroup", "takingfire", "go", "fallback", diff --git a/source/Common/Enums.cs b/source/Deathmatch/Common/Enums.cs similarity index 100% rename from source/Common/Enums.cs rename to source/Deathmatch/Common/Enums.cs diff --git a/source/Common/Globals.cs b/source/Deathmatch/Common/Globals.cs similarity index 62% rename from source/Common/Globals.cs rename to source/Deathmatch/Common/Globals.cs index 8f114c9..23ae430 100644 --- a/source/Common/Globals.cs +++ b/source/Deathmatch/Common/Globals.cs @@ -1,21 +1,29 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Capabilities; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using DeathmatchAPI; +using DeathmatchAPI.Helpers; namespace Deathmatch { public partial class Deathmatch { - public DeathmatchConfig Config { get; set; } = null!; + private static readonly Random Random = new Random(); + public static PluginCapability DeathmatchAPI { get; } = new("deathmatch"); + public DeathmatchConfig Config { get; set; } = new(); public static int NextMode; public static string ModeCenterMessage = ""; public static int ActiveCustomMode = 0; public static int ModeTimer = 0; public static int RemainingTime = 500; public static bool IsActiveEditor = false; + public static bool VisibleHud = true; + public static int CheckedEnemiesDistance = 500; public static bool IsCasualGamemode; public static bool DefaultMapSpawnDisabled = false; - public ModeData? ActiveMode; + public static bool IsLinuxServer; + public static ModeData? ActiveMode; public MemoryFunctionWithReturn? CCSPlayer_CanAcquireFunc; public MemoryFunctionWithReturn? GetCSWeaponDataFromKeyFunc; } diff --git a/source/Configs.cs b/source/Deathmatch/Configs.cs similarity index 98% rename from source/Configs.cs rename to source/Deathmatch/Configs.cs index cbc989a..c298eae 100644 --- a/source/Configs.cs +++ b/source/Deathmatch/Configs.cs @@ -1,4 +1,5 @@ using CounterStrikeSharp.API.Core; +using DeathmatchAPI.Helpers; using System.Text.Json.Serialization; using static Deathmatch.Deathmatch; @@ -30,10 +31,11 @@ public class Gameplay [JsonPropertyName("Random Selection Of Modes")] public bool RandomSelectionOfModes { get; set; } = true; [JsonPropertyName("Map Start Custom Mode")] public int MapStartMode { get; set; } = 0; [JsonPropertyName("New Mode Countdown")] public int NewModeCountdown { get; set; } = 10; + [JsonPropertyName("Hud Type")] public int HudType { get; set; } = 1; [JsonPropertyName("Check Enemies Distance")] public bool CheckDistance { get; set; } = true; [JsonPropertyName("Distance From Enemies for Respawn")] public int DistanceRespawn { get; set; } = 500; [JsonPropertyName("Default Weapons")] public int DefaultModeWeapons { get; set; } = 2; - [JsonPropertyName("Contains Restricted Weapons As Default Weapons")] public bool RemoveRestrictedWeapons { get; set; } = true; + [JsonPropertyName("Include Restricted Weapons As Defaults")] public bool RemoveRestrictedWeapons { get; set; } = true; [JsonPropertyName("Switch Weapons")] public bool SwitchWeapons { get; set; } = true; [JsonPropertyName("Allow Buymenu")] public bool AllowBuyMenu { get; set; } = true; [JsonPropertyName("Use Default Spawns")] public bool DefaultSpawns { get; set; } = false; diff --git a/source/Deathmatch.cs b/source/Deathmatch/Deathmatch.cs similarity index 77% rename from source/Deathmatch.cs rename to source/Deathmatch/Deathmatch.cs index 48dee82..434baed 100644 --- a/source/Deathmatch.cs +++ b/source/Deathmatch/Deathmatch.cs @@ -8,6 +8,10 @@ using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Menu; using Newtonsoft.Json; +using CounterStrikeSharp.API.Core.Capabilities; +using DeathmatchAPI.Helpers; +using static DeathmatchAPI.Events.IDeathmatchEventsAPI; +using System.Runtime.InteropServices; namespace Deathmatch; @@ -16,19 +20,27 @@ public partial class Deathmatch : BasePlugin, IPluginConfig { public override string ModuleName => "Deathmatch Core"; public override string ModuleAuthor => "Nocky"; - public override string ModuleVersion => "1.1.3"; + public override string ModuleVersion => "1.1.4"; public void OnConfigParsed(DeathmatchConfig config) { Config = config; + CheckedEnemiesDistance = Config.Gameplay.DistanceRespawn; } public override void Load(bool hotReload) { - GetCSWeaponDataFromKeyFunc = new(GameData.GetSignature("GetCSWeaponDataFromKey")); - CCSPlayer_CanAcquireFunc = new(GameData.GetSignature("CCSPlayer_CanAcquire")); - CCSPlayer_CanAcquireFunc.Hook(OnWeaponCanAcquire, HookMode.Pre); - VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); + var API = new Deathmatch(); + Capabilities.RegisterPluginCapability(DeathmatchAPI, () => API); + + IsLinuxServer = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + if (IsLinuxServer) + { + GetCSWeaponDataFromKeyFunc = new(GameData.GetSignature("GetCSWeaponDataFromKey")); + CCSPlayer_CanAcquireFunc = new(GameData.GetSignature("CCSPlayer_CanAcquire")); + CCSPlayer_CanAcquireFunc.Hook(OnWeaponCanAcquire, HookMode.Pre); + } + VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); LoadCustomModes(); LoadWeaponsRestrict(); @@ -56,12 +68,15 @@ public override void Load(bool hotReload) DefaultMapSpawnDisabled = false; Server.NextFrame(() => { - SetupCustomMode(Config.Gameplay.MapStartMode.ToString()); - RemoveEntities(); - SetupDeathMatchConfigValues(); - SetupDeathmatchMenus(); - LoadMapSpawns(ModuleDirectory + $"/spawns/{mapName}.json", true); - LoadCustomConfigFile(); + AddTimer(2.0f, () => + { + LoadCustomConfigFile(); + SetupDeathMatchConfigValues(); + SetupDeathmatchMenus(); + SetupCustomMode(Config.Gameplay.MapStartMode.ToString()); + RemoveEntities(); + LoadMapSpawns(ModuleDirectory + $"/spawns/{mapName}.json", true); + }); if (Config.Gameplay.IsCustomModes) { @@ -109,32 +124,44 @@ public override void Load(bool hotReload) }); RegisterListener(() => { - if (IsActiveEditor) + if (VisibleHud) { - foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && !p.IsBot && !p.IsHLTV && AdminManager.PlayerHasPermissions(p, "@css/root"))) + if (IsActiveEditor) { - string CTSpawns = $"CT Spawns: {spawnPositionsCT.Count}"; - string TSpawns = $"T Spawns: {spawnPositionsT.Count}"; - p.PrintToCenterHtml($"Spawns Editor
{CTSpawns}
{TSpawns}
"); - } - } - else - { - foreach (var p in Utilities.GetPlayers().Where(p => playerData.ContainsPlayer(p) && playerData[p].HudMessages)) - { - if (ActiveMode != null && !string.IsNullOrEmpty(ModeCenterMessage) && MenuManager.GetActiveMenu(p) == null) + foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && !p.IsBot && !p.IsHLTV && AdminManager.PlayerHasPermissions(p, "@css/root"))) { - p.PrintToCenterHtml(ModeCenterMessage); + string CTSpawns = $"CT Spawns: {spawnPositionsCT.Count}"; + string TSpawns = $"T Spawns: {spawnPositionsT.Count}"; + p.PrintToCenterHtml($"Spawns Editor
{CTSpawns}
{TSpawns}
"); } - if (Config.General.HideModeRemainingTime && RemainingTime <= Config.Gameplay.NewModeCountdown && Config.Gameplay.NewModeCountdown > 0) + } + else + { + foreach (var p in Utilities.GetPlayers().Where(p => playerData.ContainsPlayer(p) && playerData[p].HudMessages)) { - if (RemainingTime == 0) + if (ActiveMode != null && !string.IsNullOrEmpty(ActiveMode.CenterMessageText) && MenuManager.GetActiveMenu(p) == null) { - p.PrintToCenter($"{Localizer["Hud.NewModeStarted"]}"); + if (Config.Gameplay.HudType == 1) + p.PrintToCenterHtml(ModeCenterMessage); + else + p.PrintToCenter(ModeCenterMessage); } - else + if (Config.General.HideModeRemainingTime && RemainingTime <= Config.Gameplay.NewModeCountdown && Config.Gameplay.NewModeCountdown > 0) { - p.PrintToCenter($"{Localizer["Hud.NewModeStarting", RemainingTime]}"); + if (RemainingTime == 0) + { + if (Config.Gameplay.HudType == 1) + p.PrintToCenter($"{Localizer["Hud.NewModeStarted"]}"); + else + p.PrintToCenterHtml($"{Localizer["Hud.NewModeStarted"]}"); + } + else + { + if (Config.Gameplay.HudType == 1) + p.PrintToCenter($"{Localizer["Hud.NewModeStarting", RemainingTime]}"); + else + p.PrintToCenterHtml($"{Localizer["Hud.NewModeStarted"]}"); + } } } } @@ -145,7 +172,11 @@ public override void Load(bool hotReload) public override void Unload(bool hotReload) { VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamage, HookMode.Pre); - CCSPlayer_CanAcquireFunc?.Unhook(OnWeaponCanAcquire, HookMode.Pre); + + if (IsLinuxServer) + CCSPlayer_CanAcquireFunc?.Unhook(OnWeaponCanAcquire, HookMode.Pre); + //else + // VirtualFunctions.CCSPlayer_WeaponServices_CanUseFunc.Unhook(OnWeaponCanUse, HookMode.Pre); } public void SetupCustomMode(string modeId) @@ -176,6 +207,11 @@ public void SetupCustomMode(string modeId) ModeCenterMessage = ModeCenterMessage.Replace("{REMAININGTIME}", RemainingTime.ToString()); } SetupDeathmatchConfiguration(ActiveMode, bNewmode); + + Server.NextFrame(() => + { + DeathmatchAPI.Get()?.TriggerEvent(new OnCustomModeStarted(ActiveCustomMode)); + }); } public void SetupDeathmatchConfiguration(ModeData mode, bool isNewMode) @@ -319,11 +355,9 @@ public void LoadWeaponsRestrict() } } } - public void SetupDeathMatchConfigValues() { var gameType = ConVar.Find("game_type")!.GetPrimitiveValue(); - IsCasualGamemode = gameType != 1; var iHideSecond = Config.General.HideRoundSeconds ? 1 : 0; @@ -348,11 +382,10 @@ public int GetModeType() { if (Config.Gameplay.RandomSelectionOfModes) { - Random random = new Random(); int iRandomMode; do { - iRandomMode = random.Next(0, CustomModes.Count); + iRandomMode = Random.Next(0, CustomModes.Count); } while (iRandomMode == ActiveCustomMode); return iRandomMode; } diff --git a/source/Deathmatch.csproj b/source/Deathmatch/Deathmatch.csproj similarity index 83% rename from source/Deathmatch.csproj rename to source/Deathmatch/Deathmatch.csproj index 31d3afc..933cc59 100644 --- a/source/Deathmatch.csproj +++ b/source/Deathmatch/Deathmatch.csproj @@ -9,6 +9,7 @@ + diff --git a/source/Events.cs b/source/Deathmatch/Events.cs similarity index 74% rename from source/Events.cs rename to source/Deathmatch/Events.cs index c472309..c375759 100644 --- a/source/Events.cs +++ b/source/Deathmatch/Events.cs @@ -5,6 +5,7 @@ using CounterStrikeSharp.API.Modules.Timers; using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Admin; +using System.Runtime.InteropServices; namespace Deathmatch { @@ -14,7 +15,7 @@ public partial class Deathmatch public HookResult OnPlayerConnectFull(EventPlayerConnectFull @event, GameEventInfo info) { var player = @event.Userid; - if (IsPlayerValid(player!) && !playerData.ContainsPlayer(player!)) + if (IsPlayerValid(player!) && !playerData.ContainsPlayer(player)) { bool IsVIP = AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag); DeathmatchPlayerData setupPlayerData = new DeathmatchPlayerData @@ -36,6 +37,15 @@ public HookResult OnPlayerConnectFull(EventPlayerConnectFull @event, GameEventIn } return HookResult.Continue; } + [GameEventHandler(HookMode.Pre)] + public HookResult OnPlayerConnectDisconnect(EventPlayerDisconnect @event, GameEventInfo info) + { + var player = @event.Userid; + if (playerData.ContainsPlayer(player)) + playerData.RemovePlayer(player); + + return HookResult.Continue; + } [GameEventHandler(HookMode.Post)] public HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) @@ -174,6 +184,97 @@ public HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) IsActiveEditor = false; return HookResult.Continue; } + + [GameEventHandler(HookMode.Post)] + public HookResult OnItemPurcharsed(EventItemPurchase @event, GameEventInfo info) + { + if (IsLinuxServer) + return HookResult.Continue; + + var player = @event.Userid; + if (player != null && player.IsValid && playerData.ContainsPlayer(player)) + { + var weaponName = @event.Weapon; + if (!IsCasualGamemode && blockRandomWeaponsIntegeration.Contains(player)) + { + player.RemoveItemByDesignerName(weaponName, true); + return HookResult.Continue; + } + + if (ActiveMode != null && ActiveMode.RandomWeapons) + { + if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) + player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); + + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsSelectIsDisabled"]}"); + player.RemoveItemByDesignerName(weaponName, true); + return HookResult.Continue; + } + if (!AllowedPrimaryWeaponsList.Contains(weaponName) && !AllowedSecondaryWeaponsList.Contains(weaponName)) + { + if (!player.IsBot) + { + if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) + player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); + + string replacedweaponName = Localizer[weaponName]; + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsDisabled", replacedweaponName]}"); + } + player.RemoveWeapons(); + GivePlayerWeapons(player, false, false); + return HookResult.Continue; + } + + string localizerWeaponName = Localizer[weaponName]; + bool IsVIP = AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag); + if (CheckIsWeaponRestricted(weaponName, IsVIP, player.Team)) + { + if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) + player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); + + var restrictInfo = GetRestrictData(weaponName, IsVIP, player.Team); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsRestricted", localizerWeaponName, restrictInfo.Item1, restrictInfo.Item2]}"); + player.RemoveItemByDesignerName(weaponName, true); + return HookResult.Continue; + } + + bool IsPrimary = AllowedPrimaryWeaponsList.Contains(weaponName); + if (IsPrimary) + { + if (weaponName == playerData[player].PrimaryWeapon) + { + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsIsAlreadySet", localizerWeaponName]}"); + return HookResult.Continue; + } + if (!Config.Gameplay.SwitchWeapons) + { + player.RemoveWeapons(); + GivePlayerWeapons(player, false, false); + return HookResult.Continue; + } + playerData[player].PrimaryWeapon = weaponName; + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.PrimaryWeaponSet", localizerWeaponName]}"); + } + else + { + if (weaponName == playerData[player].SecondaryWeapon) + { + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsIsAlreadySet", localizerWeaponName]}"); + return HookResult.Continue; + } + if (!Config.Gameplay.SwitchWeapons) + { + player.RemoveWeapons(); + GivePlayerWeapons(player, false, false); + return HookResult.Continue; + } + playerData[player].SecondaryWeapon = weaponName; + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SecondaryWeaponSet", localizerWeaponName]}"); + } + } + return HookResult.Continue; + } + private HookResult OnPlayerRadioMessage(CCSPlayerController? player, CommandInfo info) { if (Config.General.BlockRadioMessage) @@ -186,6 +287,7 @@ private HookResult OnRandomWeapons(CCSPlayerController? player, CommandInfo info { return HookResult.Stop; } + private HookResult OnTakeDamage(DynamicHook hook) { var damageInfo = hook.GetParam(1); @@ -215,6 +317,7 @@ private HookResult OnTakeDamage(DynamicHook hook) } return HookResult.Continue; } + private HookResult OnWeaponCanAcquire(DynamicHook hook) { var vdata = GetCSWeaponDataFromKeyFunc?.Invoke(-1, hook.GetParam(1).ItemDefinitionIndex.ToString()); @@ -223,9 +326,10 @@ private HookResult OnWeaponCanAcquire(DynamicHook hook) if (vdata == null) return HookResult.Continue; - CCSPlayerController? player = null; - if (controller != null) - player = controller.As(); + if (controller == null) + return HookResult.Continue; + + var player = controller.As(); if (player == null || !player.IsValid || !player.PawnIsAlive) return HookResult.Continue; @@ -234,7 +338,7 @@ private HookResult OnWeaponCanAcquire(DynamicHook hook) { if (!AllowedPrimaryWeaponsList.Contains(vdata.Name) && !AllowedSecondaryWeaponsList.Contains(vdata.Name)) { - if (vdata.Name.Contains("knife") || vdata.Name.Contains("bayonet")) + if (vdata.Name.Contains("knife") || vdata.Name.Contains("bayonet") || (ActiveMode != null && ActiveMode.Utilities != null && ActiveMode.Utilities.Contains(vdata.Name))) return HookResult.Continue; hook.SetReturn(AcquireResult.AlreadyOwned); @@ -298,7 +402,9 @@ private HookResult OnWeaponCanAcquire(DynamicHook hook) } playerData[player].PrimaryWeapon = vdata.Name; player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.PrimaryWeaponSet", localizerWeaponName]}"); - if (!Config.Gameplay.SwitchWeapons && IsHaveWeaponFromSlot(player, 1) == 1) + + var weapon = GetWeaponFromSlot(player, gear_slot_t.GEAR_SLOT_RIFLE); + if (!Config.Gameplay.SwitchWeapons && weapon != null) { hook.SetReturn(AcquireResult.AlreadyOwned); return HookResult.Stop; @@ -314,7 +420,9 @@ private HookResult OnWeaponCanAcquire(DynamicHook hook) } playerData[player].SecondaryWeapon = vdata.Name; player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SecondaryWeaponSet", localizerWeaponName]}"); - if (!Config.Gameplay.SwitchWeapons && IsHaveWeaponFromSlot(player, 2) == 2) + + var weapon = GetWeaponFromSlot(player, gear_slot_t.GEAR_SLOT_PISTOL); + if (!Config.Gameplay.SwitchWeapons && weapon != null) { hook.SetReturn(AcquireResult.AlreadyOwned); return HookResult.Stop; diff --git a/source/Functions/Commands.cs b/source/Deathmatch/Functions/Commands.cs similarity index 100% rename from source/Functions/Commands.cs rename to source/Deathmatch/Functions/Commands.cs diff --git a/source/Functions/Entities.cs b/source/Deathmatch/Functions/Entities.cs similarity index 100% rename from source/Functions/Entities.cs rename to source/Deathmatch/Functions/Entities.cs diff --git a/source/Functions/Menus.cs b/source/Deathmatch/Functions/Menus.cs similarity index 100% rename from source/Functions/Menus.cs rename to source/Deathmatch/Functions/Menus.cs diff --git a/source/Functions/Players.cs b/source/Deathmatch/Functions/Players.cs similarity index 79% rename from source/Functions/Players.cs rename to source/Deathmatch/Functions/Players.cs index 3e6ffe5..66a775b 100644 --- a/source/Functions/Players.cs +++ b/source/Deathmatch/Functions/Players.cs @@ -21,13 +21,9 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co foreach (string weapon in AllowedPrimaryWeaponsList) { if (string.IsNullOrEmpty(primaryWeapons)) - { primaryWeapons = $"{ChatColors.Green} {Localizer[weapon]}"; - } else - { primaryWeapons = $"{primaryWeapons}{ChatColors.Default}, {ChatColors.Green}{Localizer[weapon]}"; - } } info.ReplyToCommand($"{Localizer["Chat.ListOfAllowedWeapons"]}"); info.ReplyToCommand($"{ChatColors.DarkRed}• {primaryWeapons.ToUpper()}"); @@ -37,13 +33,9 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co foreach (string weapon in AllowedSecondaryWeaponsList) { if (string.IsNullOrEmpty(secondaryWeapons)) - { secondaryWeapons = $"{ChatColors.Green} {Localizer[weapon]}"; - } else - { secondaryWeapons = $"{secondaryWeapons}{ChatColors.Default}, {ChatColors.Green}{Localizer[weapon]}"; - } } info.ReplyToCommand($"{Localizer["Chat.ListOfAllowedSecondaryWeapons"]}"); info.ReplyToCommand($"{ChatColors.DarkRed}• {secondaryWeapons.ToUpper()}"); @@ -98,6 +90,7 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponNotFound", weaponName]}"); return; } + bool IsVIP = AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag); if (AllowedPrimaryWeaponsList.Contains(weaponName)) { @@ -118,21 +111,22 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsRestricted", localizerWeaponName, restrictInfo.Item1, restrictInfo.Item2]}"); return; } + playerData[player].PrimaryWeapon = weaponName; info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.PrimaryWeaponSet", localizerWeaponName]}"); - if (player.PawnIsAlive && IsHaveWeaponFromSlot(player, 1) != 1) + + var weapon = GetWeaponFromSlot(player, gear_slot_t.GEAR_SLOT_RIFLE); + if (player.PawnIsAlive && weapon == null) { player.GiveNamedItem(weaponName); } else if (Config.Gameplay.SwitchWeapons && player.PawnIsAlive) { - string weapon = GetWeaponFromSlot(player, 2); - player.RemoveWeapons(); player.GiveNamedItem("weapon_knife"); player.GiveNamedItem(weaponName); - if (!string.IsNullOrEmpty(weapon)) - player.GiveNamedItem(weapon); + if (weapon != null) + player.GiveNamedItem(weapon.DesignerName); } return; } @@ -155,21 +149,22 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsRestricted", localizerWeaponName, restrictInfo.Item1, restrictInfo.Item2]}"); return; } + playerData[player].SecondaryWeapon = weaponName; info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SecondaryWeaponSet", localizerWeaponName]}"); - if (player.PawnIsAlive && IsHaveWeaponFromSlot(player, 2) != 2) + + var weapon = GetWeaponFromSlot(player, gear_slot_t.GEAR_SLOT_PISTOL); + if (player.PawnIsAlive && weapon == null) { player.GiveNamedItem(weaponName); } else if (Config.Gameplay.SwitchWeapons && player.PawnIsAlive) { - string weapon = GetWeaponFromSlot(player, 1); - player.RemoveWeapons(); player.GiveNamedItem("weapon_knife"); player.GiveNamedItem(weaponName); - if (!string.IsNullOrEmpty(weapon)) - player.GiveNamedItem(weapon); + if (weapon != null) + player.GiveNamedItem(weapon.DesignerName); } return; } @@ -182,8 +177,10 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co return; } } - public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) + public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode, bool giveUtilities = true) { + string PrimaryWeapon = ""; + string SecondaryWeapon = ""; if (playerData.ContainsPlayer(player) && player.PlayerPawn.Value != null) { player.InGameMoneyServices!.Account = Config.Gameplay.AllowBuyMenu ? 16000 : 0; @@ -217,14 +214,14 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) } } - int slot = IsHaveWeaponFromSlot(player, 0); - if (slot == 1 || slot == 2 || ActiveMode == null) + if (ActiveMode == null) return; bool IsVIP = AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag); + if (AllowedPrimaryWeaponsList.Count != 0) { - string PrimaryWeapon = playerData[player].PrimaryWeapon; + PrimaryWeapon = playerData[player].PrimaryWeapon; if (ActiveMode.RandomWeapons) { PrimaryWeapon = GetRandomWeaponFromList(AllowedPrimaryWeaponsList, IsVIP, player.Team); @@ -242,37 +239,11 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) } }; } - else - { - if (CheckIsWeaponRestricted(PrimaryWeapon, IsVIP, player.Team)) - { - playerData[player].PrimaryWeapon = ""; - string localizerWeaponName = Localizer[PrimaryWeapon]; - var restrictInfo = GetRestrictData(PrimaryWeapon, IsVIP, player.Team); - player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsRestricted", localizerWeaponName, restrictInfo.Item1, restrictInfo.Item2]}"); - - PrimaryWeapon = Config.Gameplay.DefaultModeWeapons switch - { - 2 => GetRandomWeaponFromList(AllowedPrimaryWeaponsList, IsVIP, player.Team), - 1 => AllowedPrimaryWeaponsList[0], - _ => "" - }; - } - } - - if (string.IsNullOrEmpty(PrimaryWeapon)) - { - player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SetupWeaponsCommand"]}"); - } - else - { - player.GiveNamedItem(PrimaryWeapon); - } } if (AllowedSecondaryWeaponsList.Count != 0) { - string SecondaryWeapon = playerData[player].SecondaryWeapon; + SecondaryWeapon = playerData[player].SecondaryWeapon; if (ActiveMode.RandomWeapons) { SecondaryWeapon = GetRandomWeaponFromList(AllowedSecondaryWeaponsList, IsVIP, player.Team); @@ -290,41 +261,17 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) } }; } - else - { - if (CheckIsWeaponRestricted(SecondaryWeapon, IsVIP, player.Team)) - { - playerData[player].SecondaryWeapon = ""; - string localizerWeaponName = Localizer[SecondaryWeapon]; - - var restrictInfo = GetRestrictData(SecondaryWeapon, IsVIP, player.Team); - player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsRestricted", localizerWeaponName, restrictInfo.Item1, restrictInfo.Item2]}"); - - SecondaryWeapon = Config.Gameplay.DefaultModeWeapons switch - { - 2 => GetRandomWeaponFromList(AllowedSecondaryWeaponsList, IsVIP, player.Team), - 1 => AllowedSecondaryWeaponsList[0], - _ => "" - }; - } - } - - if (string.IsNullOrEmpty(SecondaryWeapon)) - { - player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SetupWeaponsCommand"]}"); - } - else - { - player.GiveNamedItem(SecondaryWeapon); - } } - player.GiveNamedItem("weapon_knife"); - if (ActiveMode.Utilities != null && ActiveMode.Utilities.Count() > 0) + Server.NextFrame(() => { - foreach (var item in ActiveMode.Utilities) - player.GiveNamedItem(item); - } + GiveOrReplaceWeapons(player, PrimaryWeapon, SecondaryWeapon); + if (giveUtilities && ActiveMode.Utilities != null && ActiveMode.Utilities.Count() > 0) + { + foreach (var item in ActiveMode.Utilities) + player.GiveNamedItem(item); + } + }); return; } @@ -336,18 +283,16 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) if (player.InGameMoneyServices != null) player.InGameMoneyServices.Account = 0; - int slot = IsHaveWeaponFromSlot(player, slot: 0); - if (slot == 1 || slot == 2) - return; - if (AllowedPrimaryWeaponsList.Count != 0) { - player.GiveNamedItem(GetRandomWeaponFromList(AllowedPrimaryWeaponsList, false, player.Team)); + PrimaryWeapon = GetRandomWeaponFromList(AllowedPrimaryWeaponsList, false, player.Team); } if (AllowedSecondaryWeaponsList.Count != 0) { - player.GiveNamedItem(GetRandomWeaponFromList(AllowedSecondaryWeaponsList, false, player.Team)); + SecondaryWeapon = GetRandomWeaponFromList(AllowedSecondaryWeaponsList, false, player.Team); } + + GiveOrReplaceWeapons(player, PrimaryWeapon, SecondaryWeapon); }, TimerFlags.STOP_ON_MAPCHANGE); } public static bool IsPlayerValid(CCSPlayerController player) @@ -418,7 +363,7 @@ private void SwitchPrefsValue(CCSPlayerController player, int preference) //https://github.com/K4ryuu/K4-System/blob/dev/src/Plugin/PluginCache.cs public class PlayerCache : Dictionary { - public T this[CCSPlayerController controller] + public T this[CCSPlayerController? controller] { get { @@ -460,7 +405,7 @@ public T this[CCSPlayerController controller] } } - public bool ContainsPlayer(CCSPlayerController player) + public bool ContainsPlayer(CCSPlayerController? player) { if (player == null || !player.IsValid || !player.PlayerPawn.IsValid || player.SteamID.ToString().Length != 17) return false; @@ -471,17 +416,13 @@ public bool ContainsPlayer(CCSPlayerController player) return ContainsKey(player.Slot); } - public bool RemovePlayer(CCSPlayerController player) + public bool RemovePlayer(CCSPlayerController? player) { if (player == null || !player.IsValid || !player.PlayerPawn.IsValid || player.SteamID.ToString().Length != 17) - { - throw new ArgumentException("Invalid player controller"); - } + return false; if (player.IsBot || player.IsHLTV) - { - throw new ArgumentException("Player controller is BOT or HLTV"); - } + return false; return Remove(player.Slot); } diff --git a/source/Functions/Spawns.cs b/source/Deathmatch/Functions/Spawns.cs similarity index 88% rename from source/Functions/Spawns.cs rename to source/Deathmatch/Functions/Spawns.cs index 4bf476e..670fc43 100644 --- a/source/Functions/Spawns.cs +++ b/source/Deathmatch/Functions/Spawns.cs @@ -31,8 +31,7 @@ public void PerformRespawn(CCSPlayerController player, CsTeam team, bool IsBot) if (GameRules().WarmupPeriod || !Config.Gameplay.CheckDistance) { - Random random = new Random(); - var randomSpawn = spawnsDictionary.ElementAt(random.Next(spawnsDictionary.Count)); + var randomSpawn = spawnsDictionary.ElementAt(Random.Next(spawnsDictionary.Count)); if (!IsBot) playerData[player].LastSpawn = randomSpawn.Key; @@ -69,11 +68,10 @@ private KeyValuePair GetAvailableSpawn(CCSPlayerController playe .Select(p => p.PlayerPawn.Value!.AbsOrigin) .ToList(); - var availableSpawns = new Dictionary(); + var availableSpawns = new List>(); int spawnCount = 0; foreach (KeyValuePair spawn in spawnsList) { - spawnCount++; double closestDistance = 4000; foreach (var playerPos in playerPositions) @@ -89,22 +87,21 @@ private KeyValuePair GetAvailableSpawn(CCSPlayerController playe } } } - if (closestDistance > Config.Gameplay.DistanceRespawn) + if (closestDistance > CheckedEnemiesDistance) { //Console.WriteLine($"closestDistance {closestDistance} > DistanceRespawn {Config.Gameplay.DistanceRespawn}"); - availableSpawns.Add(spawn.Key, spawn.Value); + availableSpawns.Add(spawn); } } - Random random = new Random(); if (availableSpawns.Count > 0) { //SendConsoleMessage($"[Deathmatch] Player {player.PlayerName} was respawned, available spawns found: {availableSpawns.Count})", ConsoleColor.DarkYellow); - var randomAvailableSpawn = availableSpawns.ElementAt(random.Next(availableSpawns.Count)); + var randomAvailableSpawn = availableSpawns.ElementAt(Random.Next(availableSpawns.Count)); return randomAvailableSpawn; } SendConsoleMessage($"[Deathmatch] Player {player.PlayerName} was respawned, but no available spawn point was found! Therefore, a random spawn was selected. (T {spawnPositionsT.Count()} : CT {spawnPositionsCT.Count()})", ConsoleColor.DarkYellow); - var randomSpawn = spawnsList.ElementAt(random.Next(spawnsList.Count)); + var randomSpawn = spawnsList.ElementAt(Random.Next(spawnsList.Count)); return randomSpawn; } @@ -150,17 +147,24 @@ public void AddNewSpawnPoint(string filepath, string posValue, string angleValue public bool RemoveSpawnPoint(string filepath, string posValue) { - if (!File.Exists(filepath)) + try { - return false; - } - string jsonContent = File.ReadAllText(filepath); - JObject jsonData = JObject.Parse(jsonContent); + if (!File.Exists(filepath)) + { + return false; + } + string jsonContent = File.ReadAllText(filepath); + JObject jsonData = JObject.Parse(jsonContent); - JArray spawnpointsArray = (JArray)jsonData["spawnpoints"]!; - RemoveSpawnpointByPos(spawnpointsArray, posValue); - File.WriteAllText(filepath, jsonData.ToString()); - return true; + JArray spawnpointsArray = (JArray)jsonData["spawnpoints"]!; + RemoveSpawnpointByPos(spawnpointsArray, posValue); + File.WriteAllText(filepath, jsonData.ToString()); + return true; + } + catch (Exception ex) + { + throw new Exception($"An error occurred while removing a spawn point: {ex.Message}"); + } } static void RemoveSpawnpointByPos(JArray spawnpointsArray, string posToRemove) @@ -177,7 +181,7 @@ static void RemoveSpawnpointByPos(JArray spawnpointsArray, string posToRemove) public string GetNearestSpawnPoint(Vector? playerPos) { if (playerPos == null) - return "Spawn point cannot be deleted!"; + return "Spawn point cannot be deleted! Your Position is not valid!"; double lowestDistance = float.MaxValue; Vector? nearestSpawn = null; @@ -213,7 +217,7 @@ public string GetNearestSpawnPoint(Vector? playerPos) } else { - return "Spawn point cannot be deleted!"; + return "Spawn point cannot be deleted! (No spawn found)"; } } public void ShowAllSpawnPoints() @@ -314,12 +318,7 @@ public static void CreateCustomMapSpawns() foreach (var spawn in spawnPositionsCT) { - CBaseEntity entity; - if (IsCasualGamemode) - entity = Utilities.CreateEntityByName(infoPlayerCT)!; - else - entity = Utilities.CreateEntityByName(infoPlayerCT)!; - + var entity = Utilities.CreateEntityByName(infoPlayerCT); if (entity == null) { SendConsoleMessage($"[Deathmatch] Failed to create spawn point for CT", ConsoleColor.DarkYellow); @@ -331,11 +330,7 @@ public static void CreateCustomMapSpawns() foreach (var spawn in spawnPositionsT) { - CBaseEntity entity; - if (IsCasualGamemode) - entity = Utilities.CreateEntityByName(infoPlayerT)!; - else - entity = Utilities.CreateEntityByName(infoPlayerT)!; + var entity = Utilities.CreateEntityByName(infoPlayerT); if (entity == null) { SendConsoleMessage($"[Deathmatch] Failed to create spawn point for T", ConsoleColor.DarkYellow); @@ -363,6 +358,7 @@ public void LoadMapSpawns(string filePath, bool mapstart) } else { + SendConsoleMessage($"[Deathmatch] Loading Custom Map Spawns..", ConsoleColor.DarkYellow); var jsonContent = File.ReadAllText(filePath); JObject jsonData = JsonConvert.DeserializeObject(jsonContent)!; @@ -383,7 +379,7 @@ public void LoadMapSpawns(string filePath, bool mapstart) } } - SendConsoleMessage($"[Deathmatch] Total Loaded Spawns: CT {spawnPositionsCT.Count} | T {spawnPositionsT.Count}", ConsoleColor.Green); + SendConsoleMessage($"[Deathmatch] Total Loaded Custom Spawns: CT {spawnPositionsCT.Count} | T {spawnPositionsT.Count}", ConsoleColor.Green); if (mapstart) RemoveMapDefaulSpawns(); } @@ -430,39 +426,43 @@ public void addDefaultSpawnsToList() { if (IsCasualGamemode) { - foreach (var spawn in Utilities.FindAllEntitiesByDesignerName("info_player_counterterrorist")) + SendConsoleMessage($"[Deathmatch] Loading Default Map Spawns..", ConsoleColor.DarkYellow); + foreach (var spawn in Utilities.FindAllEntitiesByDesignerName("info_player_counterterrorist")) { if (spawn == null || spawn.AbsOrigin == null || spawn.AbsRotation == null) - return; + continue; + spawnPositionsCT.Add(spawn.AbsOrigin, spawn.AbsRotation); } - foreach (var spawn in Utilities.FindAllEntitiesByDesignerName("info_player_terrorist")) + foreach (var spawn in Utilities.FindAllEntitiesByDesignerName("info_player_terrorist")) { if (spawn == null || spawn.AbsOrigin == null || spawn.AbsRotation == null) - return; + continue; spawnPositionsT.Add(spawn.AbsOrigin, spawn.AbsRotation); } } else { + SendConsoleMessage($"[Deathmatch] Loading Default Deathmatch Map Spawns..", ConsoleColor.DarkYellow); int randomizer = 0; - foreach (var spawn in Utilities.FindAllEntitiesByDesignerName("info_deathmatch_spawn")) + foreach (var spawn in Utilities.FindAllEntitiesByDesignerName("info_deathmatch_spawn")) { randomizer++; if (randomizer % 2 == 0) { if (spawn == null || spawn.AbsOrigin == null || spawn.AbsRotation == null) - return; + continue; spawnPositionsT.Add(spawn.AbsOrigin, spawn.AbsRotation); } else { if (spawn == null || spawn.AbsOrigin == null || spawn.AbsRotation == null) - return; + continue; spawnPositionsCT.Add(spawn.AbsOrigin, spawn.AbsRotation); } } } + SendConsoleMessage($"[Deathmatch] Total Loaded Spawns: CT {spawnPositionsCT.Count} | T {spawnPositionsT.Count}", ConsoleColor.Green); } } } \ No newline at end of file diff --git a/source/Functions/Weapons.cs b/source/Deathmatch/Functions/Weapons.cs similarity index 62% rename from source/Functions/Weapons.cs rename to source/Deathmatch/Functions/Weapons.cs index 8ab0807..eaeafeb 100644 --- a/source/Functions/Weapons.cs +++ b/source/Deathmatch/Functions/Weapons.cs @@ -74,63 +74,78 @@ public bool CheckIsWeaponRestricted(string weaponName, bool isVIP, CsTeam team) return false; } - public string GetWeaponFromSlot(CCSPlayerController player, int slot) + public CBasePlayerWeapon? GetWeaponFromSlot(CCSPlayerController player, gear_slot_t slot) { if (player.PlayerPawn == null || player.PlayerPawn.Value == null || !player.PlayerPawn.IsValid || player.PlayerPawn.Value.WeaponServices == null) - return null!; + return null; - foreach (var weapon in player.PlayerPawn.Value.WeaponServices.MyWeapons) + return player.PlayerPawn.Value.WeaponServices.MyWeapons + .Select(weapon => weapon.Value?.As()) + .Where(weaponBase => weaponBase != null && weaponBase.VData != null && weaponBase.VData.GearSlot == slot) + .FirstOrDefault(); + } + + public void GiveOrReplaceWeapons(CCSPlayerController player, string PrimaryWeapon, string SecondaryWeapon) + { + if (player == null || !player.IsValid || player.PlayerPawn == null || player.PlayerPawn.Value == null || !player.PawnIsAlive) + return; + + var weaponServices = player.PlayerPawn.Value.WeaponServices; + if (weaponServices == null) + return; + var weaponsList = weaponServices.MyWeapons.Select(weapon => weapon.Value?.As()).ToList(); + if (weaponsList == null) + return; + + var weapon = weaponsList + .Where(weaponBase => weaponBase != null && weaponBase.VData != null && weaponBase.VData.GearSlot == gear_slot_t.GEAR_SLOT_RIFLE) + .FirstOrDefault(); + + if (weapon == null) { - if (weapon != null && weapon.IsValid) + if (string.IsNullOrEmpty(PrimaryWeapon)) + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SetupWeaponsCommand"]}"); + else + player.GiveNamedItem(PrimaryWeapon); + } + else + { + if (string.IsNullOrEmpty(PrimaryWeapon)) + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SetupWeaponsCommand"]}"); + else { - if (slot == 1) - { - if (PrimaryWeaponsList.Contains(weapon.Value!.DesignerName)) - { - return weapon.Value!.DesignerName; - } - } - else if (slot == 2) - { - if (SecondaryWeaponsList.Contains(weapon.Value!.DesignerName)) - { - return weapon.Value!.DesignerName; - } - } + player.RemoveItemByDesignerName(weapon.DesignerName, false); + player.GiveNamedItem(PrimaryWeapon); } } - return null!; - } - - public int IsHaveWeaponFromSlot(CCSPlayerController player, int slot) - { - if (player == null || !player.IsValid || player.PlayerPawn == null || player.PlayerPawn.Value == null || player.PlayerPawn.Value.WeaponServices == null || !player.PawnIsAlive) - return 3; + + weapon = weaponsList + .Where(weaponBase => weaponBase != null && weaponBase.VData != null && weaponBase.VData.GearSlot == gear_slot_t.GEAR_SLOT_PISTOL) + .FirstOrDefault(); - foreach (var weapon in player.PlayerPawn.Value.WeaponServices.MyWeapons) + if (weapon == null) { - if (weapon != null && weapon.IsValid) + if (string.IsNullOrEmpty(SecondaryWeapon)) + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SetupWeaponsCommand"]}"); + else + player.GiveNamedItem(SecondaryWeapon); + } + else + { + if (string.IsNullOrEmpty(SecondaryWeapon)) + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SetupWeaponsCommand"]}"); + else { - switch (slot) - { - case 0: - if (SecondaryWeaponsList.Contains(weapon.Value!.DesignerName)) - return 2; - else if (PrimaryWeaponsList.Contains(weapon.Value!.DesignerName)) - return 1; - break; - case 1: - if (PrimaryWeaponsList.Contains(weapon.Value!.DesignerName)) - return 1; - break; - case 2: - if (SecondaryWeaponsList.Contains(weapon.Value!.DesignerName)) - return 2; - break; - } + player.RemoveItemByDesignerName(weapon.DesignerName, false); + player.GiveNamedItem(SecondaryWeapon); } } - return 3; + + weapon = weaponsList + .Where(weaponBase => weaponBase != null && weaponBase.VData != null && weaponBase.VData.GearSlot == gear_slot_t.GEAR_SLOT_KNIFE) + .FirstOrDefault(); + if (weapon == null) + player.GiveNamedItem("weapon_knife"); } private string GetRandomWeaponFromList(List weaponsList, bool isVIP, CsTeam team) @@ -143,8 +158,7 @@ private string GetRandomWeaponFromList(List weaponsList, bool isVIP, CsT weaponsList.Remove(weapon); } } - Random rand = new Random(); - int index = rand.Next(weaponsList.Count); + int index = Random.Next(weaponsList.Count); return weaponsList[index]; }