diff --git a/Custom Modes Examples/Only_AK47.md b/Custom Modes Examples/Only_AK47.md index dfede8c..4654a88 100644 --- a/Custom Modes Examples/Only_AK47.md +++ b/Custom Modes Examples/Only_AK47.md @@ -1,20 +1,20 @@

IN THIS MODE, PLAYERS CAN USE ONLY AK47 AND CAN SHOOT ONLY HEADSHOT

-- Add this in your `custom_modes.json` file and edit YOUR MODE ID for valid value +- Add this in your config file (`counterstrikesharp/configs/plugins/Deathmatch/Deathmatch.json`) and edit YOUR MODE ID for valid value ``` "YOUR MODE ID": { - "mode_name": "Only AK47 & Headshot", - "mode_interval": 300, - "armor": 1, - "only_hs": true, - "allow_knife_damage": false, - "random_weapons": false, - "allow_center_message": true, - "center_message_text": "Only AK47 & Headshot", - "primary_weapons": [ + "Name": "Only AK47 & Headshot", + "Interval": 300, + "Armor": 1, + "OnlyHS": true, + "KnifeDamage": false, + "RandomWeapons": false, + "CenterMessageText": "Only AK47 & Headshot", + "PrimaryWeapons": [ "weapon_ak47" ], - "secondary_weapons": [] + "SecondaryWeapons": [], + "Utilities": [] } ``` \ No newline at end of file diff --git a/Custom Modes Examples/Only_awp.md b/Custom Modes Examples/Only_awp.md index 5fc9e2d..0300f21 100644 --- a/Custom Modes Examples/Only_awp.md +++ b/Custom Modes Examples/Only_awp.md @@ -1,19 +1,21 @@ -

IN THIS MODE, PLAYERS CAN USE ONLY AWP

+

IN THIS MODE, PLAYERS CAN USE ONLY AWP AND GET FLASH

-- Add this in your `custom_modes.json` file and edit YOUR MODE ID for valid value +- Add this in your config file (`counterstrikesharp/configs/plugins/Deathmatch/Deathmatch.json`) and edit YOUR MODE ID for valid value ``` "YOUR MODE ID": { - "mode_name": "Only AWP", - "mode_interval": 300, - "armor": 1, - "only_hs": false, - "allow_knife_damage": false, - "random_weapons": false, - "allow_center_message": true, - "center_message_text": "Only AWP", - "primary_weapons": [ + "Name": "Only AWP", + "Interval": 300, + "Armor": 1, + "OnlyHS": false, + "KnifeDamage": false, + "RandomWeapons": false, + "CenterMessageText": "Only AWP", + "PrimaryWeapons": [ "weapon_awp" ], - "secondary_weapons": [] + "SecondaryWeapons": [], + "Utilities": [ + "weapon_flashbang" + ] } ``` diff --git a/Custom Modes Examples/Only_pistols.md b/Custom Modes Examples/Only_pistols.md index 859306a..0f52c20 100644 --- a/Custom Modes Examples/Only_pistols.md +++ b/Custom Modes Examples/Only_pistols.md @@ -1,18 +1,17 @@ -

IN THIS MODE, PLAYERS CAN USE ALL PISTOLS EXPECT THE DEAGLE

+

IN THIS MODE, PLAYERS CAN USE ALL PISTOLS EXPECT THE DEAGLE AND GET GRENADE+FLASH

-- Add this in your `custom_modes.json` file and edit YOUR MODE ID for valid value +- Add this in your config file (`counterstrikesharp/configs/plugins/Deathmatch/Deathmatch.json`) and edit YOUR MODE ID for valid value ``` "YOUR MODE ID": { - "mode_name": "Only Pistols", - "mode_interval": 300, - "armor": 1, - "only_hs": false, - "allow_knife_damage": true, - "random_weapons": false, - "allow_center_message": true, - "center_message_text": "Only Pistols", - "primary_weapons": [], - "secondary_weapons": [ + "Name": "Only Pistols", + "Interval": 300, + "Armor": 1, + "OnlyHS": false, + "KnifeDamage": true, + "RandomWeapons": false, + "CenterMessageText": "Only Pistols", + "PrimaryWeapons": [], + "SecondaryWeapons": [ "weapon_usp_silencer", "weapon_p250", "weapon_glock", @@ -21,6 +20,10 @@ "weapon_fiveseven", "weapon_hkp2000", "weapon_tec9" + ], + "Utilities": [ + "weapon_flashbang", + "weapon_hegrenade ] } ``` diff --git a/Custom Modes Examples/Only_rifles.md b/Custom Modes Examples/Only_rifles.md index 45b97a1..772ad70 100644 --- a/Custom Modes Examples/Only_rifles.md +++ b/Custom Modes Examples/Only_rifles.md @@ -1,23 +1,23 @@

IN THIS MODE, PLAYERS CAN USE ALL RIFLES EXPECT THE FAMAS AND GALILAR

-- Add this in your custom_modes.json file and edit YOUR MODE ID for valid value +- Add this in your config file (`counterstrikesharp/configs/plugins/Deathmatch/Deathmatch.json`) and edit YOUR MODE ID for valid value ``` "YOUR MODE ID": { - "mode_name": "Only Rifles", - "mode_interval": 300, - "armor": 1, - "only_hs": false, - "allow_knife_damage": true, - "random_weapons": false, - "allow_center_message": true, - "center_message_text": "Only Rifles", - "primary_weapons": [ + "Name": "Only Rifles", + "Interval": 300, + "Armor": 1, + "OnlyHS": false, + "KnifeDamage": true, + "RandomWeapons": false, + "CenterMessageText": "Only Rifles", + "PrimaryWeapons": [ "weapon_ak47", "weapon_m4a1", "weapon_m4a1_silencer", "weapon_aug", "weapon_sg556" ], - "secondary_weapons": [] + "SecondaryWeapons": [], + "Utilities": [] } ``` \ No newline at end of file diff --git a/Custom Modes Examples/Only_shotguns.md b/Custom Modes Examples/Only_shotguns.md index 5c08e2b..8869715 100644 --- a/Custom Modes Examples/Only_shotguns.md +++ b/Custom Modes Examples/Only_shotguns.md @@ -1,22 +1,22 @@

IN THIS MODE, PLAYERS CAN USE ALL SHOTGUNS AND PLAYERS CANT SELECT THEIR WEAPONS (PLAYER WILL GET RANDOM SHOTGUN EVERY SPAWN)

-- Add this in your custom_modes.json file and edit YOUR MODE ID for valid value +- Add this in your config file (`counterstrikesharp/configs/plugins/Deathmatch/Deathmatch.json`) and edit YOUR MODE ID for valid value ``` "YOUR MODE ID": { - "mode_name": "Only Shotguns", - "mode_interval": 300, - "armor": 2, - "only_hs": false, - "allow_knife_damage": false, - "random_weapons": true, - "allow_center_message": true, - "center_message_text": "Only Shotguns", - "primary_weapons": [ + "Name": "Only Shotguns", + "Interval": 300, + "Armor": 2, + "OnlyHS": false, + "KnifeDamage": false, + "RandomWeapons": true, + "CenterMessageText": "Only Shotguns", + "PrimaryWeapons": [ "weapon_mag7", "weapon_sawedoff", "weapon_nova", "weapon_xm1014" ], - "secondary_weapons": [] + "SecondaryWeapons": [], + "Utilities": [] } ``` \ No newline at end of file diff --git a/Lang/pl.json b/Lang/pl.json deleted file mode 100644 index 1e77579..0000000 --- a/Lang/pl.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "Prefix": "{darkred}[Deathmatch]{default}", - "Knife_damage_disabled": "W tym trybie obrażenia noża są wyłączone!", - "New_mode": "Uruchamianie nowego trybu typu {green}{0}{default}!", - "PrimaryWeapon_Set": "Twoja główna broń została ustawiona na {green}{0}", - "PrimaryWeapon_Disabled": "Twoja główna broń {green}{0}{default} jest wyłączona w tym trybie! Ustaw inną.", - "SecondaryWeapon_Set": "Twoja broń dodatkowa została ustawiona na {green}{0}", - "SecondaryWeapon_Disabled": "Twoja broń dodatkowa {green}{0}{default} jest wyłączona w tym trybie! Ustaw inną.", - "Weapon_Disabled": "Broń {green}{0}{default} jest wyłączona w tym trybie!", - "Multiple_Weapon_Select": "Znaleziono wiele dopasowań dla tej nazwy broni.", - "Weapon_Name_Not_Found": "Nie znaleziono broni o nazwie '{green}{0}{default}'.", - "Weapon_Select_Is_Disabled": "W tym trybie nie możesz ustawić swojej broni.", - "Weapon_Is_Already_Set": "Broń '{green}{0}{default}' jest już ustawiona.", - "Allowed_Primary_Weapons": "Dozwolone podstawowe bronie:", - "Allowed_Secondary_Weapons": "Dozwolone dodatkowe bronie:", - "Setup_Weapons_By_Command": "Możesz ustawić broń za pomocą polecenia {green}/gun", - "weapon_mag7": "MAG-7", - "weapon_nova": "Nova", - "weapon_sawedoff": "Sawed-Off", - "weapon_xm1014": "XM1014", - "weapon_m249": "M249", - "weapon_negev": "Negev", - "weapon_mac10": "MAC-10", - "weapon_mp5sd": "MP5-SD", - "weapon_mp7": "MP7", - "weapon_mp9": "MP9", - "weapon_p90": "P90", - "weapon_bizon": "PP-Bizon", - "weapon_ump45": "UMP45", - "weapon_ak47": "AK47", - "weapon_aug": "AUG", - "weapon_famas": "FAMAS", - "weapon_galilar": "Galil AR", - "weapon_m4a1_silencer": "M4A1-S", - "weapon_m4a1": "M4A4", - "weapon_sg556": "SG 553", - "weapon_awp": "AWP", - "weapon_g3sg1": "G3SG1", - "weapon_scar20": "SCAR-20", - "weapon_ssg08": "SSG-08", - "weapon_hkp2000": "P2000", - "weapon_cz75a": "CZ75-Auto", - "weapon_deagle": "Deagle", - "weapon_elite": "Dual Berretas", - "weapon_fiveseven": "Five-seveN", - "weapon_glock": "Glock", - "weapon_p250": "P250", - "weapon_revolver": "Revolver", - "weapon_tec9": "Tec-9", - "weapon_usp_silencer": "USP" -} diff --git a/Lang/ua.json b/Lang/ua.json deleted file mode 100644 index cfa8746..0000000 --- a/Lang/ua.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "Prefix": "{darkred}[Deathmatch]{default}", - "Knife_damage_disabled": "Пошкодження ножа вимкнено в цьому режимі!", - "New_mode": "Починається новий тип режиму {green}{0}{default}!", - "PrimaryWeapon_Set": "Ваша основна зброя встановлена на {green}{0}", - "PrimaryWeapon_Disabled": "Ваша основна зброя {green}{0}{default} вимкнена в цьому режимі! Встановте іншу.", - "SecondaryWeapon_Set": "Ваша другорядна зброя встановлена на {green}{0}", - "SecondaryWeapon_Disabled": "Ваша другорядна зброя {green}{0}{default} вимкнена в цьому режимі! Встановте іншу.", - "Weapon_Disabled": "Зброя {green}{0}{default} вимкнена в цьому режимі!", - "Multiple_Weapon_Select": "Знайдено кілька відповідностей для цього імені зброї.", - "Weapon_Name_Not_Found": "Зброя з іменем '{green}{0}{default}' не знайдена.", - "Weapon_Select_Is_Disabled": "Під час цього режиму ви не можете встановлювати свої зброї.", - "Weapon_Is_Already_Set": "Зброя '{green}{0}{default}' вже встановлена.", - "Maximum_Weapons_Buys": "Досягнуто максимальну кількість покупок ({green}{0}{default})! Ви зможете купити знову при наступному відновленні.", - - "weapon_mag7": "MAG-7", - "weapon_nova": "Nova", - "weapon_sawedoff": "Sawed-Off", - "weapon_xm1014": "XM1014", - "weapon_m249": "M249", - "weapon_negev": "Negev", - "weapon_mac10": "MAC-10", - "weapon_mp5sd": "MP5-SD", - "weapon_mp7": "MP7", - "weapon_mp9": "MP9", - "weapon_p90": "P90", - "weapon_bizon": "PP-Bizon", - "weapon_ump45": "UMP45", - "weapon_ak47": "AK47", - "weapon_aug": "AUG", - "weapon_famas": "FAMAS", - "weapon_galilar": "Galil AR", - "weapon_m4a1_silencer": "M4A1-S", - "weapon_m4a1": "M4A4", - "weapon_sg556": "SG 553", - "weapon_awp": "AWP", - "weapon_g3sg1": "G3SG1", - "weapon_scar20": "SCAR-20", - "weapon_ssg08": "SSG-08", - "weapon_hkp2000": "P2000", - "weapon_cz75a": "CZ75-Auto", - "weapon_deagle": "Deagle", - "weapon_elite": "Dual Berretas", - "weapon_fiveseven": "Five-seveN", - "weapon_glock": "Glock", - "weapon_p250": "P250", - "weapon_revolver": "Revolver", - "weapon_tec9": "Tec-9", - "weapon_usp_silencer": "USP" -} diff --git a/Lang/uz.json b/Lang/uz.json index d0dee84..f3f9217 100644 --- a/Lang/uz.json +++ b/Lang/uz.json @@ -1,22 +1,20 @@ { - "Prefix": "{darkred}[Deathmatch]{default}", - "Knife_damage_disabled": "Ushbu rejimda pichoq bilan zararlanish oʻchirilgan!", - "New_mode": "{green}{0}{default} yangi rejim ishga tushirilmoqda!", - "PrimaryWeapon_Set": "Sizning asosiy qurolingiz {green}{0}{default} ga oʻzgartirildi", - "PrimaryWeapon_Disabled": "Sizning asosiy qurolingiz {green}{0}{default} ushbu rejimda oʻchirib qoʻyilgan! Boshqasini tanlang.", - "SecondaryWeapon_Set": "Sizning ikkinchi qurolingiz {green}{0}{default} ga oʻzgartirildi", - "SecondaryWeapon_Disabled": "Sizning ikkinchi qurolingiz {green}{0}{default} ushbu rejimda oʻchirib qoʻyilgan! Boshqasini tanlang.", - "Weapon_Disabled": "Ushbu rejimda qurol {green}{0}{default} oʻchirib qoʻyilgan!", - "Weapon_Is_Restricted": "Qurol {green}{0}{default} hozirda {darkred}{1}{default} bilan cheklangan (VIP: {darkred}{2}{default}) va uni sozlash imkonsiz.", - "Multiple_Weapon_Select": "Bu qurol nomi uchun bir nechta moslik topildi.", - "Weapon_Name_Not_Found": "'{green}{0}{default}' nomli qurol topilmadi.", - "Weapon_Select_Is_Disabled": "Ushbu rejimda siz qurollaringizni sozlay olmaysiz.", - "Weapon_Is_Already_Set": "'{green}{0}{default}' quroli allaqachon oʻrnatilgan.", - "Allowed_Primary_Weapons": "RUXSAT BERILGAN ASOSIY QUROLLAR:", - "Allowed_Secondary_Weapons": "RUXSAT BERILGAN IKKINCHI QUROLLAR:", - "Setup_Weapons_By_Command": "Siz qurollarni {green}/gun{default} buyrugʻi orqali olishingiz mumkin", - "New_Mode_Starts_In": "Yangi rejim {0} soniyadan keyin boshlanadi!", - "New_Mode_Started": "Yangi rejim boshlandi!", + "Chat.Prefix": "{darkred}[Deathmatch]{default}", + "Chat.NewModeStarted": "{green}{0}{default} yangi rejim ishga tushirilmoqda!", + "Chat.PrimaryWeaponSet": "Sizning asosiy qurolingiz {green}{0}{default} ga oʻzgartirildi", + "Chat.SecondaryWeaponSet": "Sizning ikkinchi qurolingiz {green}{0}{default} ga oʻzgartirildi", + "Chat.WeaponIsDisabled": "Ushbu rejimda qurol {green}{0}{default} oʻchirib qoʻyilgan!", + "Chat.WeaponIsRestricted": "Qurol {green}{0}{default} hozirda {darkred}{1}{default} bilan cheklangan (VIP: {darkred}{2}{default}) va uni sozlash imkonsiz.", + "Chat.MultipleWeaponsSelected": "Bu qurol nomi uchun bir nechta moslik topildi.", + "Chat.WeaponNotFound": "'{green}{0}{default}' nomli qurol topilmadi.", + "Chat.WeaponsSelectIsDisabled": "Ushbu rejimda siz qurollaringizni sozlay olmaysiz.", + "Chat.WeaponsIsAlreadySet": "'{green}{0}{default}' quroli allaqachon oʻrnatilgan.", + "Chat.ListOfAllowedWeapons": "RUXSAT BERILGAN ASOSIY QUROLLAR:", + "Chat.ListOfAllowedSecondaryWeapons": "RUXSAT BERILGAN IKKINCHI QUROLLAR:", + "Chat.SetupWeaponsCommand": "Siz qurollarni {green}/gun{default} buyrugʻi orqali olishingiz mumkin", + "Hud.KnifeDamageIsDisabled": "Ushbu rejimda pichoq bilan zararlanish oʻchirilgan!", + "Hud.NewModeStarting": "Yangi rejim {0} soniyadan keyin boshlanadi!", + "Hud.NewModeStarted": "Yangi rejim boshlandi!", "Menu.Title": "Deathmatch menyusi", "Menu.SoundsTitle": "Deathmatch menyusi • Ovozlar", "Menu.FunctionsTitle": "Deathmatch menyusi • Funksiyalar", diff --git a/source/Common/Classes.cs b/source/Common/Classes.cs new file mode 100644 index 0000000..108862b --- /dev/null +++ b/source/Common/Classes.cs @@ -0,0 +1,44 @@ +using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; + +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 class DeathmatchPlayerData + { + public required string PrimaryWeapon { get; set; } + public required string SecondaryWeapon { get; set; } + public required bool SpawnProtection { get; set; } + public required int KillStreak { get; set; } + public required bool KillSound { get; set; } + public required bool HSKillSound { get; set; } + public required bool KnifeKillSound { get; set; } + public required bool HitSound { get; set; } + public required bool OnlyHS { get; set; } + public required bool HudMessages { get; set; } + public required Vector LastSpawn { get; set; } + public required int OpenedMenu { get; set; } + } + + public class RestrictData + { + public int CT { get; set; } + public int T { get; set; } + public int Global { get; set; } + } + } +} \ No newline at end of file diff --git a/source/Common/Collections.cs b/source/Common/Collections.cs new file mode 100644 index 0000000..c64195e --- /dev/null +++ b/source/Common/Collections.cs @@ -0,0 +1,55 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; + +namespace Deathmatch +{ + public partial class Deathmatch + { + public Dictionary CustomModes = new(); + public 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(); + + readonly Dictionary weaponSelectMapping = new Dictionary + { + { "m4a4", "weapon_m4a1" }, + { "weapon_m4a1", "weapon_m4a1" }, + { "m4a1_silencer", "weapon_m4a1_silencer" }, + { "m4a1", "weapon_m4a1_silencer" } + }; + + readonly HashSet SecondaryWeaponsList = new HashSet + { + "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 + { + "weapon_mag7", "weapon_nova", "weapon_sawedoff", "weapon_xm1014", + "weapon_m249", "weapon_negev", "weapon_mac10", "weapon_mp5sd", + "weapon_mp7", "weapon_mp9", "weapon_p90", "weapon_bizon", + "weapon_ump45", "weapon_ak47", "weapon_aug", "weapon_famas", + "weapon_galilar", "weapon_m4a1_silencer", "weapon_m4a1", "weapon_sg556", + "weapon_awp", "weapon_g3sg1", "weapon_scar20", "weapon_ssg08" + }; + + readonly HashSet RadioMessagesList = new HashSet + { + "coverme", "takepoint", "holdpos", "followme", + "regroup", "takingfire", "go", "fallback", + "enemydown", "sticktog", "stormfront", "cheer", + "compliment", "thanks", "roger", "enemyspot", + "needbackup", "sectorclear", "inposition", "negative", + "report", "getout" + }; + } +} \ No newline at end of file diff --git a/source/Common/Enums.cs b/source/Common/Enums.cs new file mode 100644 index 0000000..b7b64f7 --- /dev/null +++ b/source/Common/Enums.cs @@ -0,0 +1,32 @@ +namespace Deathmatch +{ + public partial class Deathmatch + { + public enum RestrictType + { + VIP, + NonVIP, + } + + public enum AcquireResult : int + { + Allowed = 0, + InvalidItem, + AlreadyOwned, + AlreadyPurchased, + ReachedGrenadeTypeLimit, + ReachedGrenadeTotalLimit, + NotAllowedByTeam, + NotAllowedByMap, + NotAllowedByMode, + NotAllowedForPurchase, + NotAllowedByProhibition, + }; + + public enum AcquireMethod : int + { + PickUp = 0, + Buy, + }; + } +} \ No newline at end of file diff --git a/source/Common/Globals.cs b/source/Common/Globals.cs new file mode 100644 index 0000000..1b2a17e --- /dev/null +++ b/source/Common/Globals.cs @@ -0,0 +1,20 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; + +namespace Deathmatch +{ + public partial class Deathmatch + { + public DeathmatchConfig Config { get; set; } = null!; + public static int ActiveCustomMode = 0; + public static int g_iModeTimer = 0; + public static int g_iRemainingTime = 500; + public static bool g_bIsActiveEditor = false; + public static bool g_bDefaultMapSpawnDisabled = false; + public static bool IsCasualGamemode; + public ModeData? ActiveMode; + public MemoryFunctionWithReturn? CCSPlayer_CanAcquireFunc; + public MemoryFunctionWithReturn? GetCSWeaponDataFromKeyFunc; + } +} \ No newline at end of file diff --git a/source/Configs.cs b/source/Configs.cs index b61553e..c71e952 100644 --- a/source/Configs.cs +++ b/source/Configs.cs @@ -1,6 +1,6 @@ using CounterStrikeSharp.API.Core; -using Newtonsoft.Json.Linq; using System.Text.Json.Serialization; +using static Deathmatch.Deathmatch; namespace Deathmatch; @@ -12,10 +12,8 @@ public class DeathmatchConfig : BasePluginConfig [JsonPropertyName("Custom Commands")] public CustomCommands CustomCommands { get; set; } = new CustomCommands(); [JsonPropertyName("Players Gameplay Settings")] public PlayersSettings PlayersSettings { get; set; } = new PlayersSettings(); [JsonPropertyName("Client Preferences")] public PlayersPreferences PlayersPreferences { get; set; } = new PlayersPreferences(); - - // BLOCK WEAPON BUY - // sounds/ui/weapon_cant_buy.vsnd_c - // sounds/buttons/button8.vsnd_c + [JsonPropertyName("Custom Modes")] public CustomModes CustomModes { get; set; } = new CustomModes(); + [JsonPropertyName("Weapons Restrict")] public WeaponsRestrict WeaponsRestrict { get; set; } = new WeaponsRestrict(); } public class SoundSettings @@ -138,120 +136,172 @@ public class PlayersSettings [JsonPropertyName("refill_health_headshot")] public int HeadshotHealth { get; set; } = 40; [JsonPropertyName("VIP_refill_health_headshot")] public int HeadshotHealthVIP { get; set; } = 50; } -public static class Configuration + +public class CustomModes { - public static JObject? JsonCustomModes { get; private set; } - public static List CustomCvarsList = new List(); - public static void CreateOrLoadCvars(string filepath) + [JsonPropertyName("0")] + public ModeData _0 { get; set; } = new ModeData { - if (!File.Exists(filepath)) - { - using (StreamWriter writer = new StreamWriter(filepath)) - { - writer.Write("sv_disable_radar 1\nmp_give_player_c4 0\nmp_playercashawards 0\nmp_teamcashawards 0\nmp_weapons_allow_zeus 0\nmp_buy_allow_grenades 0\nmp_max_armor 0\nmp_freezetime 0\nmp_death_drop_grenade 0\nmp_death_drop_gun 0\nmp_death_drop_healthshot 0\nmp_drop_grenade_enable 0\nmp_death_drop_c4 0\nmp_death_drop_taser 0\nmp_defuser_allocation 0\nmp_solid_teammates 1\nmp_weapons_allow_typecount -1\nmp_hostages_max 0"); - } - CustomCvarsList = new List(File.ReadLines(filepath)); - } - else - { - CustomCvarsList = new List(File.ReadLines(filepath)); - } - } + Name = "Default", + Interval = 300, + Armor = 1, + OnlyHS = false, + KnifeDamage = true, + RandomWeapons = false, + CenterMessageText = "", + PrimaryWeapons = new List { + "weapon_aug", "weapon_sg556", "weapon_xm1014", + "weapon_ak47", "weapon_famas", "weapon_galilar", + "weapon_m4a1", "weapon_m4a1_silencer", "weapon_mp5sd", + "weapon_mp7", "weapon_p90", "weapon_awp" + }, + SecondaryWeapons = new List { + "weapon_usp_silencer", "weapon_p250", "weapon_glock", + "weapon_fiveseven", "weapon_hkp2000", "weapon_deagle" + }, + Utilities = new List { + "weapon_flashbang" + }, + }; - public static void CreateOrLoadCustomModes(string filepath) + [JsonPropertyName("1")] + public ModeData _1 { get; set; } = new ModeData { - if (!File.Exists(filepath)) - { - JObject exampleData = new JObject - { - ["custom_modes"] = new JObject - { - ["0"] = new JObject - { - ["mode_name"] = "Default", - ["mode_interval"] = 300, - ["armor"] = 1, - ["only_hs"] = false, - ["allow_knife_damage"] = true, - ["random_weapons"] = false, - ["center_message_text"] = "", - ["primary_weapons"] = new JArray { "weapon_aug", "weapon_sg556", "weapon_xm1014", "weapon_ak47", "weapon_famas", "weapon_galilar", "weapon_m4a1", "weapon_m4a1_silencer", "weapon_mp5sd", "weapon_mp7", "weapon_p90" }, - ["secondary_weapons"] = new JArray { "weapon_usp_silencer", "weapon_p250", "weapon_glock", "weapon_fiveseven", "weapon_hkp2000", "weapon_deagle" } + Name = "Only Headshot", + Interval = 300, + Armor = 1, + OnlyHS = true, + KnifeDamage = false, + RandomWeapons = false, + CenterMessageText = "Only Headshot", + PrimaryWeapons = new List { + "weapon_aug", "weapon_sg556", "weapon_xm1014", + "weapon_ak47", "weapon_famas", "weapon_galilar", + "weapon_m4a1", "weapon_m4a1_silencer", "weapon_mp5sd", + "weapon_mp7", "weapon_p90" }, - ["1"] = new JObject - { - ["mode_name"] = "Only Headshot", - ["mode_interval"] = 300, - ["armor"] = 1, - ["only_hs"] = true, - ["allow_knife_damage"] = false, - ["random_weapons"] = false, - ["center_message_text"] = "Only Headshot", - ["primary_weapons"] = new JArray { "weapon_aug", "weapon_sg556", "weapon_xm1014", "weapon_ak47", "weapon_famas", "weapon_galilar", "weapon_m4a1", "weapon_m4a1_silencer", "weapon_mp5sd", "weapon_mp7", "weapon_p90" }, - ["secondary_weapons"] = new JArray { "weapon_usp_silencer", "weapon_p250", "weapon_glock", "weapon_fiveseven", "weapon_hkp2000", "weapon_deagle" }, + SecondaryWeapons = new List { + "weapon_usp_silencer", "weapon_p250", "weapon_glock", + "weapon_fiveseven", "weapon_hkp2000", "weapon_deagle" }, - ["2"] = new JObject - { - ["mode_name"] = "Only Deagle", - ["mode_interval"] = 120, - ["armor"] = 2, - ["only_hs"] = false, - ["allow_knife_damage"] = true, - ["random_weapons"] = false, - ["center_message_text"] = "Only Deagle", - ["primary_weapons"] = new JArray { }, - ["secondary_weapons"] = new JArray { "weapon_deagle" }, + }; + + [JsonPropertyName("2")] + public ModeData _2 { get; set; } = new ModeData + { + Name = "Only Deagle", + Interval = 120, + Armor = 2, + OnlyHS = false, + KnifeDamage = true, + RandomWeapons = false, + CenterMessageText = "Only Deagle", + PrimaryWeapons = new List(), + SecondaryWeapons = new List { + "weapon_deagle" }, - ["3"] = new JObject - { - ["mode_name"] = "Only Pistols", - ["mode_interval"] = 180, - ["armor"] = 1, - ["only_hs"] = false, - ["allow_knife_damage"] = true, - ["random_weapons"] = false, - ["center_message_text"] = "Only Pistols", - ["primary_weapons"] = new JArray { }, - ["secondary_weapons"] = new JArray { "weapon_usp_silencer", "weapon_p250", "weapon_glock", "weapon_cz75a", "weapon_elite", "weapon_fiveseven", "weapon_tec9", "weapon_hkp2000" } + Utilities = new List { + "weapon_flashbang" , "weapon_healthshot" }, - ["4"] = new JObject - { - ["mode_name"] = "Only SMG", - ["mode_interval"] = 200, - ["armor"] = 2, - ["only_hs"] = false, - ["allow_knife_damage"] = true, - ["random_weapons"] = true, - ["center_message_text"] = "Only SMG (Random Weapons)", - ["primary_weapons"] = new JArray { "weapon_p90", "weapon_bizon", "weapon_mp5sd", "weapon_mp7", "weapon_mp9", "weapon_mac10", "weapon_ump45" }, - ["secondary_weapons"] = new JArray { } - } - } - }; + }; - File.WriteAllText(filepath, exampleData.ToString()); - var jsonData = File.ReadAllText(filepath); - JsonCustomModes = JObject.Parse(jsonData); - } - else - { - var jsonData = File.ReadAllText(filepath); - JsonCustomModes = JObject.Parse(jsonData); - } + [JsonPropertyName("3")] + public ModeData _3 { get; set; } = new ModeData + { + Name = "Only Pistols", + Interval = 180, + Armor = 1, + OnlyHS = false, + KnifeDamage = true, + RandomWeapons = false, + CenterMessageText = "Only Pistols", + PrimaryWeapons = new List(), + SecondaryWeapons = new List { + "weapon_usp_silencer", "weapon_p250", "weapon_glock", + "weapon_cz75a", "weapon_elite", "weapon_fiveseven", + "weapon_tec9", "weapon_hkp2000" + }, + }; - if (JsonCustomModes != null && JsonCustomModes["custom_modes"] is JObject customModesObject) + [JsonPropertyName("4")] + public ModeData _4 { get; set; } = new ModeData + { + Name = "Only SMG", + Interval = 200, + Armor = 2, + OnlyHS = false, + KnifeDamage = true, + RandomWeapons = true, + CenterMessageText = "Only SMG (Random Weapons)", + PrimaryWeapons = new List { + "weapon_p90", "weapon_bizon", "weapon_mp5sd", + "weapon_mp7", "weapon_mp9", "weapon_mac10", + "weapon_ump45" + }, + SecondaryWeapons = new List(), + Utilities = new List { + "weapon_hegrenade", "weapon_flashbang", "weapon_healthshot" + }, + }; +} + +public class WeaponsRestrict +{ + [JsonPropertyName("Global Restrict")] public bool Global { get; set; } = true; + + [JsonPropertyName("Weapons")] + public Dictionary>> DefaultRestrictions { get; set; } = new() + { + ["weapon_ak47"] = new Dictionary>() { - DeathmatchCore.g_iTotalModes = customModesObject?.Count ?? 0; - if (DeathmatchCore.g_iTotalModes == 0) + ["0"] = new Dictionary() + { + [RestrictType.VIP] = new RestrictData() + { + CT = 6, + T = 6, + Global = 12 + }, + [RestrictType.NonVIP] = new RestrictData() + { + CT = 5, + T = 5, + Global = 10 + } + }, + ["1"] = new Dictionary() { - DeathmatchCore.SendConsoleMessage($"[Deathmatch] Wrong modes setup! (Deathmatch/custom_modes.json.json)", ConsoleColor.Red); - throw new Exception($"[Deathmatch] Wrong modes setup in custom_modes.json!"); + [RestrictType.VIP] = new RestrictData() + { + CT = 5, + T = 5, + Global = 7 + }, + [RestrictType.NonVIP] = new RestrictData() + { + CT = 4, + T = 4, + Global = 5 + } } - } - else + }, + ["weapon_awp"] = new Dictionary>() { - DeathmatchCore.SendConsoleMessage($"[Deathmatch] Wrong modes setup! (Deathmatch/custom_modes.json.json)", ConsoleColor.Red); - throw new Exception($"[Deathmatch] Wrong modes setup in custom_modes.json!"); + ["0"] = new Dictionary() + { + [RestrictType.VIP] = new RestrictData() + { + CT = 3, + T = 3, + Global = 4 + }, + [RestrictType.NonVIP] = new RestrictData() + { + CT = 2, + T = 2, + Global = 3 + } + } } - } -} + }; +} \ No newline at end of file diff --git a/source/Deathmatch.cs b/source/Deathmatch.cs index 49c84d0..26804f3 100644 --- a/source/Deathmatch.cs +++ b/source/Deathmatch.cs @@ -5,78 +5,18 @@ using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Cvars; -using Newtonsoft.Json.Linq; using CounterStrikeSharp.API.Modules.Entities.Constants; -using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Menu; +using Newtonsoft.Json; namespace Deathmatch; -[MinimumApiVersion(178)] -public partial class DeathmatchCore : BasePlugin, IPluginConfig +[MinimumApiVersion(216)] +public partial class Deathmatch : BasePlugin, IPluginConfig { public override string ModuleName => "Deathmatch Core"; public override string ModuleAuthor => "Nocky"; - public override string ModuleVersion => "1.1.1"; - public static DeathmatchCore Instance { get; set; } = new(); - public class ModeInfo - { - public string Name { get; set; } = ""; - public int Interval { get; set; } = 1; - public int Armor { get; set; } = 1; - public bool OnlyHS { get; set; } = false; - public bool KnifeDamage { get; set; } = true; - public bool RandomWeapons { get; set; } = true; - public string CenterMessageText { get; set; } = ""; - } - - public enum AcquireResult : int - { - Allowed = 0, - InvalidItem, - AlreadyOwned, - AlreadyPurchased, - ReachedGrenadeTypeLimit, - ReachedGrenadeTotalLimit, - NotAllowedByTeam, - NotAllowedByMap, - NotAllowedByMode, - NotAllowedForPurchase, - NotAllowedByProhibition, - }; - - public enum AcquireMethod : int - { - PickUp = 0, - Buy, - }; - - public static CounterStrikeSharp.API.Modules.Timers.Timer? modeTimer; - internal static PlayerCache playerData = new PlayerCache(); - public static ModeInfo ModeData = new ModeInfo(); - public DeathmatchConfig Config { get; set; } = null!; - public static int g_iTotalModes = 0; - public static int g_iTotalCTSpawns = 0; - public static int g_iTotalTSpawns = 0; - public static int g_iActiveMode = 0; - public static int g_iModeTimer = 0; - public static int g_iRemainingTime = 500; - public static bool g_bIsPrimarySet = false; - public static bool g_bIsActiveEditor = false; - public static bool g_bDefaultMapSpawnDisabled = false; - public static bool g_bWeaponRestrictGlobal; - public static bool IsCasualGamemode; - - public MemoryFunctionWithReturn? CCSPlayer_CanAcquireFunc; - public MemoryFunctionWithReturn? GetCSWeaponDataFromKeyFunc; - - HashSet RadioMessagesList = new HashSet { - "coverme", "takepoint", "holdpos", "followme", - "regroup", "takingfire", "go", "fallback", - "enemydown", "sticktog", "stormfront", "cheer", - "compliment", "thanks", "roger", "enemyspot", - "needbackup", "sectorclear", "inposition", "negative", - "report", "getout" }; + public override string ModuleVersion => "1.1.2"; public void OnConfigParsed(DeathmatchConfig config) { @@ -88,11 +28,10 @@ public override void Load(bool hotReload) CCSPlayer_CanAcquireFunc = new(GameData.GetSignature("CCSPlayer_CanAcquire")); CCSPlayer_CanAcquireFunc.Hook(OnWeaponCanAcquire, HookMode.Pre); VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); - Configuration.CreateOrLoadCustomModes(ModuleDirectory + "/custom_modes.json"); - Configuration.CreateOrLoadCvars(ModuleDirectory + "/deathmatch_cvars.txt"); - LoadWeaponsRestrict(ModuleDirectory + "/weapons_restrict.json"); - customShortcuts.Clear(); + LoadCustomModes(); + LoadWeaponsRestrict(); + string[] Shortcuts = Config.CustomCommands.CustomShortcuts.Split(','); string[] WSelect = Config.CustomCommands.WeaponSelectCmds.Split(','); string[] DeathmatchMenus = Config.CustomCommands.DeatmatchMenuCmds.Split(','); @@ -101,7 +40,6 @@ public override void Load(bool hotReload) string[] Value = weapon.Split(':'); if (Value.Length == 2) { - customShortcuts.Add(Value[1], Value[0]); AddCustomCommands(Value[1], Value[0], 1); } } @@ -113,28 +51,33 @@ public override void Load(bool hotReload) AddCommandListener(radioName, OnPlayerRadioMessage); AddCommandListener("autobuy", OnRandomWeapons); - RegisterListener(() => { modeTimer?.Kill(); }); RegisterListener(mapName => { g_bDefaultMapSpawnDisabled = false; Server.NextFrame(() => { + SetupCustomMode(Config.Gameplay.MapStartMode.ToString()); + RemoveEntities(); + SetupDeathMatchConfigValues(); + SetupDeathmatchMenus(); + LoadMapSpawns(ModuleDirectory + $"/spawns/{mapName}.json", true); + LoadCustomConfigFile(); + if (Config.Gameplay.IsCustomModes) { - modeTimer?.Kill(); - modeTimer = AddTimer(1.0f, () => + AddTimer(1.0f, () => { - if (!GameRules().WarmupPeriod) + if (!GameRules().WarmupPeriod && ActiveMode != null) { g_iModeTimer++; - g_iRemainingTime = ModeData.Interval - g_iModeTimer; + g_iRemainingTime = ActiveMode.Interval - g_iModeTimer; if (g_iRemainingTime == 0) { - var mode = GetModeType().ToString(); - SetupCustomMode(mode); + SetupCustomMode(GetModeType().ToString()); } + } - }, TimerFlags.REPEAT); + }, TimerFlags.REPEAT | TimerFlags.STOP_ON_MAPCHANGE); } if (Config.General.ForceMapEnd) { @@ -153,11 +96,6 @@ public override void Load(bool hotReload) }, TimerFlags.REPEAT | TimerFlags.STOP_ON_MAPCHANGE); } - RemoveEntities(); - SetupDeathMatchConfigValues(); - SetupCustomMode(Config.Gameplay.MapStartMode.ToString()); - SetupDeathmatchMenus(); - LoadMapSpawns(ModuleDirectory + $"/spawns/{mapName}.json", true); }); }); RegisterListener(() => @@ -166,8 +104,8 @@ public override void Load(bool hotReload) { foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && !p.IsBot && !p.IsHLTV && AdminManager.PlayerHasPermissions(p, "@css/root"))) { - string CTSpawns = $"CT Spawns: {g_iTotalCTSpawns}"; - string TSpawns = $"T Spawns: {g_iTotalTSpawns}"; + string CTSpawns = $"CT Spawns: {spawnPositionsCT.Count}"; + string TSpawns = $"T Spawns: {spawnPositionsT.Count}"; p.PrintToCenterHtml($"Spawns Editor
{CTSpawns}
{TSpawns}
"); } } @@ -175,19 +113,19 @@ public override void Load(bool hotReload) { foreach (var p in Utilities.GetPlayers().Where(p => playerData.ContainsPlayer(p) && playerData[p].HudMessages)) { - if (!string.IsNullOrEmpty(ModeData.CenterMessageText) && MenuManager.GetActiveMenu(p) == null) + if (ActiveMode != null && !string.IsNullOrEmpty(ActiveMode.CenterMessageText) && MenuManager.GetActiveMenu(p) == null) { - p.PrintToCenterHtml($"{ModeData.CenterMessageText}"); + p.PrintToCenterHtml($"{ActiveMode.CenterMessageText}"); } if (g_iRemainingTime <= Config.Gameplay.NewModeCountdown && Config.Gameplay.NewModeCountdown > 0) { if (g_iRemainingTime == 0) { - p.PrintToCenter($"{Localizer["New_Mode_Started"]}"); + p.PrintToCenter($"{Localizer["Hud.NewModeStarted"]}"); } else { - p.PrintToCenter($"{Localizer["New_Mode_Starts_In", g_iRemainingTime]}"); + p.PrintToCenter($"{Localizer["Hud.NewModeStarting", g_iRemainingTime]}"); } } } @@ -202,85 +140,44 @@ public override void Unload(bool hotReload) AllowedPrimaryWeaponsList.Clear(); AllowedSecondaryWeaponsList.Clear(); } - public void SetupCustomMode(string modetype) + public void SetupCustomMode(string modeId) { + ActiveMode = CustomModes[modeId]; bool bNewmode = true; - AllowedSecondaryWeaponsList.Clear(); - AllowedPrimaryWeaponsList.Clear(); - RestrictedWeapons.Clear(); - if (modetype == g_iActiveMode.ToString()) - bNewmode = false; - if (Configuration.JsonCustomModes != null && Configuration.JsonCustomModes.TryGetValue(propertyName: "custom_modes", out var data) && data is JObject dataObject) - { - if (dataObject.TryGetValue(modetype, out var modeValue) && modeValue is JObject) - { - ModeData.Name = modeValue["mode_name"]?.ToString() ?? $"{modetype}"; - ModeData.Interval = modeValue["mode_interval"]?.Value() ?? 500; - ModeData.Armor = modeValue["armor"]?.Value() ?? 1; - ModeData.OnlyHS = modeValue["only_hs"]?.Value() ?? false; - ModeData.KnifeDamage = modeValue["allow_knife_damage"]?.Value() ?? true; - ModeData.RandomWeapons = modeValue["random_weapons"]?.Value() ?? false; - ModeData.CenterMessageText = modeValue["center_message_text"]?.ToString() ?? ""; - g_iActiveMode = int.Parse(modetype); - - if (ModeData.Armor < 0 || ModeData.Armor > 2) - { - SendConsoleMessage($"[Deathmatch] Wrong value in Armor! (Mode ID: {modetype}) | Allowed options: 0 , 1 , 2", ConsoleColor.Red); - throw new Exception($"[Deathmatch] Wrong value in Armor! (Mode ID: {modetype}) | Allowed options: 0 , 1 , 2"); - } + if (ActiveMode.SecondaryWeapons != null && ActiveMode.SecondaryWeapons.Count() > 0) + AllowedSecondaryWeaponsList = new(ActiveMode.SecondaryWeapons); + else + AllowedSecondaryWeaponsList.Clear(); - JArray primaryWeaponsArray = (JArray)modeValue["primary_weapons"]!; - JArray secondaryWeaponsArray = (JArray)modeValue["secondary_weapons"]!; - if (primaryWeaponsArray != null && primaryWeaponsArray.Count > 0) - { - foreach (string? weapon in primaryWeaponsArray) - { - AllowedPrimaryWeaponsList.Add(weapon!); - } - CheckIsValidWeaponsInList(AllowedPrimaryWeaponsList, PrimaryWeaponsList); - } - if (secondaryWeaponsArray != null && secondaryWeaponsArray.Count > 0) - { - foreach (string? weapon in secondaryWeaponsArray) - { - AllowedSecondaryWeaponsList.Add(weapon!); - } - CheckIsValidWeaponsInList(AllowedSecondaryWeaponsList, SecondaryWeaponsList); - } - SetupDeathmatchConfiguration(bNewmode); - return; - } - else - { - SendConsoleMessage($"[Deathmatch] Mode with id {modetype} is not found!", ConsoleColor.Red); - throw new Exception($"[Deathmatch] Mode with id {modetype} is not found!"); - } - } + if (ActiveMode.PrimaryWeapons != null && ActiveMode.PrimaryWeapons.Count() > 0) + AllowedPrimaryWeaponsList = new(ActiveMode.PrimaryWeapons); else - { - SendConsoleMessage($"[Deathmatch] Wrong code in custom_modes.json!", ConsoleColor.Red); - throw new Exception($"[Deathmatch] Wrong code in custom_modes.json!"); - } + AllowedPrimaryWeaponsList.Clear(); + + if (modeId.Equals(ActiveCustomMode.ToString())) + bNewmode = false; + ActiveCustomMode = int.Parse(modeId); + SetupDeathmatchConfiguration(ActiveMode, bNewmode); } - public void SetupDeathmatchConfiguration(bool isNewMode) + public void SetupDeathmatchConfiguration(ModeData mode, bool isNewMode) { g_iModeTimer = 0; if (isNewMode) - Server.PrintToChatAll($"{Localizer["Prefix"]} {Localizer["New_mode", ModeData.Name]}"); + Server.PrintToChatAll($"{Localizer["Chat.Prefix"]} {Localizer["Chat.NewModeStarted", mode.Name]}"); - Server.ExecuteCommand($"mp_free_armor {ModeData.Armor};mp_damage_headshot_only {ModeData.OnlyHS};mp_ct_default_primary \"\";mp_t_default_primary \"\";mp_ct_default_secondary \"\";mp_t_default_secondary \"\""); + Server.ExecuteCommand($"mp_free_armor {mode.Armor};mp_damage_headshot_only {mode.OnlyHS};mp_ct_default_primary \"\";mp_t_default_primary \"\";mp_ct_default_secondary \"\";mp_t_default_secondary \"\""); foreach (var p in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.PawnIsAlive)) { p.RemoveWeapons(); GivePlayerWeapons(p, true); - if (ModeData.Armor != 0) + if (mode.Armor != 0) { - string armor = ModeData.Armor == 1 ? "item_kevlar" : "item_assaultsuit"; + string armor = mode.Armor == 1 ? "item_kevlar" : "item_assaultsuit"; p.GiveNamedItem(armor); } if (!p.IsBot) @@ -293,20 +190,122 @@ public void SetupDeathmatchConfiguration(bool isNewMode) p.Respawn(); } } + public void LoadCustomConfigFile() + { + string path = Server.GameDirectory + "/csgo/cfg/deathmatch/"; + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + + if (!File.Exists(path + "deathmatch.cfg")) + { + var content = @" +// Things you can customize and add your own cvars +mp_timelimit 30 +mp_maxrounds 0 +sv_disable_radar 1 +sv_alltalk 1 +mp_warmuptime 20 +mp_freezetime 1 +mp_death_drop_grenade 0 +mp_death_drop_gun 0 +mp_death_drop_healthshot 0 +mp_drop_grenade_enable 0 +mp_death_drop_c4 0 +mp_death_drop_taser 0 +mp_defuser_allocation 0 +mp_solid_teammates 1 +mp_give_player_c4 0 +mp_playercashawards 0 +mp_teamcashawards 0 +cash_team_bonus_shorthanded 0 +mp_autokick 0 +mp_match_restart_delay 10 + +//Do not change or delete!! +mp_max_armor 0 +mp_weapons_allow_typecount -1 +mp_hostages_max 0 +mp_weapons_allow_zeus 0 +mp_buy_allow_grenades 0 + "; + + using (StreamWriter writer = new StreamWriter(path + "deathmatch.cfg")) + { + writer.Write(content); + } + } + Server.ExecuteCommand("exec deathmatch/deathmatch.cfg"); + } + public void LoadCustomModes() + { + string filePath = Server.GameDirectory + "/csgo/addons/counterstrikesharp/configs/plugins/Deathmatch/Deathmatch.json"; + if (File.Exists(filePath)) + { + try + { + var jsonData = File.ReadAllText(filePath); + dynamic deserializedJson = JsonConvert.DeserializeObject(jsonData)!; + var modes = deserializedJson["Custom Modes"].ToObject>(); + CustomModes = new Dictionary(modes); + SendConsoleMessage($"[Deathmatch] Loaded {CustomModes.Count()} Custom Modes", ConsoleColor.Green); + + } + catch (Exception ex) + { + SendConsoleMessage($"[Deathmatch] An error occurred while loading Custom Modes: {ex.Message}", ConsoleColor.Red); + throw new Exception($"An error occurred while loading Custom Modes: {ex.Message}"); + } + } + } + + public void LoadWeaponsRestrict() + { + string filePath = Server.GameDirectory + "/csgo/addons/counterstrikesharp/configs/plugins/Deathmatch/Deathmatch.json"; + if (File.Exists(filePath)) + { + try + { + var jsonData = File.ReadAllText(filePath); + dynamic deserializedJson = JsonConvert.DeserializeObject(jsonData)!; + var weapons = deserializedJson["Weapons Restrict"]["Weapons"].ToObject>>>(); + RestrictedWeapons = new(weapons); + SendConsoleMessage($"[Deathmatch] Total Restricted Weapons: {RestrictedWeapons.Count()}", ConsoleColor.Green); + /*foreach (var item in RestrictedWeapons) + { + SendConsoleMessage(item.Key, ConsoleColor.Magenta); + foreach (var mode in item.Value) + { + SendConsoleMessage(mode.Key, ConsoleColor.Magenta); + foreach (var type in mode.Value) + { + SendConsoleMessage($"type - {type.Key}", ConsoleColor.Magenta); + var data = type.Value; + SendConsoleMessage($"data T - {data.T}", ConsoleColor.Magenta); + SendConsoleMessage($"data CT - {data.CT}", ConsoleColor.Magenta); + SendConsoleMessage($"data GLOBAL - {data.Global}", ConsoleColor.Magenta); + } + } + }*/ + } + catch (Exception ex) + { + SendConsoleMessage($"[Deathmatch] An error occurred while loading Weapons Restrictions: {ex.Message}", ConsoleColor.Red); + throw new Exception($"An error occurred while loading Weapons Restrictions: {ex.Message}"); + } + } + } + public void SetupDeathMatchConfigValues() { var gameType = ConVar.Find("game_type")!.GetPrimitiveValue(); - Server.PrintToConsole($"gametype {gameType}"); + IsCasualGamemode = gameType != 1; var iHideSecond = Config.General.HideRoundSeconds ? 1 : 0; var time = ConVar.Find("mp_timelimit")!.GetPrimitiveValue(); var iFFA = Config.Gameplay.IsFFA ? 1 : 0; Server.ExecuteCommand($"mp_teammates_are_enemies {iFFA};sv_hide_roundtime_until_seconds {iHideSecond};mp_roundtime_defuse {time};mp_roundtime {time};mp_roundtime_deployment {time};mp_roundtime_hostage {time};mp_respawn_on_death_ct 1;mp_respawn_on_death_t 1"); - foreach (var cvar in Configuration.CustomCvarsList) - { - Server.ExecuteCommand(cvar); - } + if (Config.Gameplay.AllowBuyMenu) Server.ExecuteCommand("mp_buy_anywhere 1;mp_buytime 60000;mp_buy_during_immunity 0"); else @@ -328,14 +327,14 @@ public int GetModeType() int iRandomMode; do { - iRandomMode = random.Next(0, g_iTotalModes); - } while (iRandomMode == g_iActiveMode); + iRandomMode = random.Next(0, CustomModes.Count); + } while (iRandomMode == ActiveCustomMode); return iRandomMode; } else { - if (g_iActiveMode + 1 != g_iTotalModes && g_iActiveMode + 1 < g_iTotalModes) - return g_iActiveMode + 1; + if (ActiveCustomMode + 1 != CustomModes.Count && ActiveCustomMode + 1 < CustomModes.Count) + return ActiveCustomMode + 1; return 0; } } diff --git a/source/Deathmatch.csproj b/source/Deathmatch.csproj index ee95c52..0dd16a4 100644 --- a/source/Deathmatch.csproj +++ b/source/Deathmatch.csproj @@ -1,13 +1,13 @@ - net7.0 + net8.0 enable enable - + diff --git a/source/Events.cs b/source/Events.cs index 0deb656..60b90e3 100644 --- a/source/Events.cs +++ b/source/Events.cs @@ -8,7 +8,7 @@ namespace Deathmatch { - public partial class DeathmatchCore + public partial class Deathmatch { [GameEventHandler] public HookResult OnPlayerConnectFull(EventPlayerConnectFull @event, GameEventInfo info) @@ -30,7 +30,7 @@ public HookResult OnPlayerConnectFull(EventPlayerConnectFull @event, GameEventIn HudMessages = Config.PlayersPreferences.HudMessages.Enabled ? ((Config.PlayersPreferences.HudMessages.OnlyVIP && IsVIP ? Config.PlayersPreferences.HudMessages.DefaultValue : false) || (!Config.PlayersPreferences.HudMessages.OnlyVIP ? Config.PlayersPreferences.HudMessages.DefaultValue : false)) : false, SpawnProtection = false, OpenedMenu = 0, - LastSpawn = "0" + LastSpawn = null! }; playerData[player] = setupPlayerData; } @@ -54,9 +54,9 @@ public HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) CCSPlayerController attacker = @event.Attacker; CCSPlayerController player = @event.Userid; - if (playerData.ContainsPlayer(attacker)) + if (ActiveMode != null && playerData.ContainsPlayer(attacker)) { - if (ModeData.OnlyHS) + if (ActiveMode.OnlyHS) { if (@event.Hitgroup == 1 && (!@event.Weapon.Contains("knife") || !@event.Weapon.Contains("bayonet")) && playerData[attacker].HitSound) attacker.ExecuteClientCommand("play " + Config.PlayersPreferences.HitSound.Path); @@ -104,7 +104,7 @@ public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) AddTimer(timer, () => { if (player != null && player.IsValid && !player.PawnIsAlive) - PerformRespawn(player, player.TeamNum, IsBot); + PerformRespawn(player, player.Team, IsBot); }, TimerFlags.STOP_ON_MAPCHANGE); if (attacker != player && playerData.ContainsPlayer(attacker) && attacker.PlayerPawn.Value != null) @@ -145,6 +145,12 @@ public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) attacker.PlayerPawn.Value.Health += giveHP; Utilities.SetStateChanged(attacker.PlayerPawn.Value, "CBaseEntity", "m_iHealth"); } + + if (ActiveMode != null && ActiveMode.Armor != 0) + { + string armor = ActiveMode.Armor == 1 ? "item_kevlar" : "item_assaultsuit"; + attacker.GiveNamedItem(armor); + } @event.FireEventToClient(attacker); } return HookResult.Continue; @@ -184,7 +190,7 @@ private HookResult OnTakeDamage(DynamicHook hook) var player = new CCSPlayerController(new CCSPlayerPawn(hook.GetParam(0).Handle).Controller.Value!.Handle); var attacker = new CCSPlayerController(new CCSPlayerPawn(damageInfo.Attacker.Value!.Handle).Controller.Value!.Handle); - if (player == null || !player.IsValid || attacker == null || !attacker.IsValid) + if (player == null || !player.IsValid || attacker == null || !attacker.IsValid || ActiveMode == null) return HookResult.Continue; if (playerData.ContainsPlayer(player) && playerData[player].SpawnProtection) @@ -192,9 +198,9 @@ private HookResult OnTakeDamage(DynamicHook hook) damageInfo.Damage = 0; return HookResult.Continue; } - if (!ModeData.KnifeDamage && damageInfo.Ability.IsValid && (damageInfo.Ability.Value!.DesignerName.Contains("knife") || damageInfo.Ability.Value!.DesignerName.Contains("bayonet"))) + if (!ActiveMode.KnifeDamage && damageInfo.Ability.IsValid && (damageInfo.Ability.Value!.DesignerName.Contains("knife") || damageInfo.Ability.Value!.DesignerName.Contains("bayonet"))) { - attacker.PrintToCenter(Localizer["Knife_damage_disabled"]); + attacker.PrintToCenter(Localizer["Hud.KnifeDamageIsDisabled"]); damageInfo.Damage = 0; } return HookResult.Continue; @@ -226,11 +232,11 @@ private HookResult OnWeaponCanAcquire(DynamicHook hook) return HookResult.Stop; } - if (ModeData.RandomWeapons) + if (ActiveMode != null && ActiveMode.RandomWeapons) { if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Weapon_Select_Is_Disabled"]}"); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsSelectIsDisabled"]}"); hook.SetReturn(AcquireResult.AlreadyPurchased); return HookResult.Stop; } @@ -243,7 +249,7 @@ private HookResult OnWeaponCanAcquire(DynamicHook hook) player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); string replacedweaponName = Localizer[vdata.Name]; - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Weapon_Disabled", replacedweaponName]}"); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsDisabled", replacedweaponName]}"); } hook.SetReturn(AcquireResult.AlreadyPurchased); return HookResult.Stop; @@ -252,13 +258,14 @@ private HookResult OnWeaponCanAcquire(DynamicHook hook) if (playerData.ContainsPlayer(player)) { string localizerWeaponName = Localizer[vdata.Name]; - if (CheckIsWeaponRestricted(vdata.Name, AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag), player.TeamNum)) + bool IsVIP = AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag); + if (CheckIsWeaponRestricted(vdata.Name, IsVIP, player.Team)) { if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); - RestrictedWeaponsInfo restrict = RestrictedWeapons[vdata.Name]; - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Weapon_Is_Restricted", localizerWeaponName, restrict.nonVIPRestrict, restrict.VIPRestrict]}"); + var restrictInfo = GetRestrictData(vdata.Name, IsVIP, player.Team); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsRestricted", localizerWeaponName, restrictInfo.Item1, restrictInfo.Item2]}"); hook.SetReturn(AcquireResult.NotAllowedByMode); return HookResult.Stop; } @@ -268,12 +275,12 @@ private HookResult OnWeaponCanAcquire(DynamicHook hook) { if (vdata.Name == playerData[player].PrimaryWeapon) { - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Weapon_Is_Already_Set", localizerWeaponName]}"); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsIsAlreadySet", localizerWeaponName]}"); hook.SetReturn(AcquireResult.AlreadyOwned); return HookResult.Stop; } playerData[player].PrimaryWeapon = vdata.Name; - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["PrimaryWeapon_Set", localizerWeaponName]}"); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.PrimaryWeaponSet", localizerWeaponName]}"); if (!Config.Gameplay.SwitchWeapons && IsHaveWeaponFromSlot(player, 1) == 1) { hook.SetReturn(AcquireResult.AlreadyOwned); @@ -284,12 +291,12 @@ private HookResult OnWeaponCanAcquire(DynamicHook hook) { if (vdata.Name == playerData[player].SecondaryWeapon) { - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Weapon_Is_Already_Set", localizerWeaponName]}"); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsIsAlreadySet", localizerWeaponName]}"); hook.SetReturn(AcquireResult.AlreadyOwned); return HookResult.Stop; } playerData[player].SecondaryWeapon = vdata.Name; - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["SecondaryWeapon_Set", localizerWeaponName]}"); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SecondaryWeaponSet", localizerWeaponName]}"); if (!Config.Gameplay.SwitchWeapons && IsHaveWeaponFromSlot(player, 2) == 2) { hook.SetReturn(AcquireResult.AlreadyOwned); diff --git a/source/Commands.cs b/source/Functions/Commands.cs similarity index 65% rename from source/Commands.cs rename to source/Functions/Commands.cs index 14415ab..11a36a5 100644 --- a/source/Commands.cs +++ b/source/Functions/Commands.cs @@ -9,46 +9,49 @@ namespace Deathmatch { - public partial class DeathmatchCore + public partial class Deathmatch { - Dictionary customShortcuts = new Dictionary(); private void AddCustomCommands(string command, string weapon_name, int type) { string cmdName = $"css_{command}"; switch (type) { case 1: - AddCommand(cmdName, weapon_name, (player, info) => + AddCommand(cmdName, $"Weapon Shortcut: {weapon_name}", (player, info) => { if (!playerData.ContainsPlayer(player!)) return; - if (ModeData.RandomWeapons) + if (ActiveMode == null) { - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["Weapon_Select_Is_Disabled"]}"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} Custom Mode is not active, contact the Administrator!"); return; } - string weaponName = info.GetArg(0).ToLower(); - weaponName = weaponName.Replace("css_", ""); - if (customShortcuts.ContainsKey(weaponName)) + if (ActiveMode.RandomWeapons) { - string weaponID = customShortcuts.FirstOrDefault(x => x.Key == weaponName).Value; - SetupPlayerWeapons(player!, weaponID, info); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsSelectIsDisabled"]}"); + return; } + SetupPlayerWeapons(player!, weapon_name, info); }); break; case 2: AddCommand(cmdName, "Select a weapon by command", (player, info) => { - string weaponName = info.GetArg(1).ToLower(); if (!playerData.ContainsPlayer(player!)) return; - - if (ModeData.RandomWeapons) + if (ActiveMode == null) + { + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} Custom Mode is not active, contact the Administrator!"); + return; + } + if (ActiveMode.RandomWeapons) { - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["Weapon_Select_Is_Disabled"]}"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsSelectIsDisabled"]}"); return; } + + string weaponName = info.GetArg(1).ToLower(); SetupPlayerWeapons(player!, weaponName, info); }); break; @@ -85,13 +88,13 @@ public void OnCheckDistance_CMD(CCSPlayerController player, CommandInfo info) { if (player.IsValid && !player.PawnIsAlive) { - info.ReplyToCommand($"{Localizer["Prefix"]} You have to be alive to add a new spawn!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} You have to be alive to add a new spawn!"); return; } var distance = info.GetArg(1); if (!int.TryParse(distance, out int radius)) { - info.ReplyToCommand($"{Localizer["Prefix"]} The distance must be a number!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} The distance must be a number!"); return; } var position = player.PlayerPawn.Value!.AbsOrigin!; @@ -123,6 +126,19 @@ public void OnCheckDistance_CMD(CCSPlayerController player, CommandInfo info) public void OnStartMode_CMD(CCSPlayerController player, CommandInfo info) { string modeid = info.GetArg(1); + if (int.TryParse(modeid, out _)) + { + if (!CustomModes.ContainsKey(modeid)) + { + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} A mod with a number doesn't exist!"); + return; + } + } + else + { + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} Mode ID must be a number!"); + return; + } SetupCustomMode(modeid); } @@ -133,11 +149,11 @@ public void OnEditor_CMD(CCSPlayerController player, CommandInfo info) { if (Config.Gameplay.DefaultSpawns) { - info.ReplyToCommand($"{Localizer["Prefix"]} The Spawn Editor cannot be used if you are using the default spawns!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} The Spawn Editor cannot be used if you are using the default spawns!"); return; } g_bIsActiveEditor = !g_bIsActiveEditor; - info.ReplyToCommand($"{Localizer["Prefix"]} Spawn Editor has been {ChatColors.Green}{(g_bIsActiveEditor ? "Enabled" : "Disabled")}"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} Spawn Editor has been {ChatColors.Green}{(g_bIsActiveEditor ? "Enabled" : "Disabled")}"); if (g_bIsActiveEditor) { ShowAllSpawnPoints(); @@ -156,19 +172,20 @@ public void OnAddSpawnCT_CMD(CCSPlayerController player, CommandInfo info) { if (!g_bIsActiveEditor) { - info.ReplyToCommand($"{Localizer["Prefix"]} Spawn Editor is disabled!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} Spawn Editor is disabled!"); return; } if (player.IsValid && !player.PawnIsAlive) { - info.ReplyToCommand($"{Localizer["Prefix"]} You have to be alive to add a new spawn!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} You have to be alive to add a new spawn!"); return; } var position = player.PlayerPawn.Value!.AbsOrigin; var angle = player.PlayerPawn.Value.AbsRotation; AddNewSpawnPoint(ModuleDirectory + $"/spawns/{Server.MapName}.json", $"{position}", $"{angle}", "ct"); - info.ReplyToCommand($"{Localizer["Prefix"]} Spawn for the CT team has been added. (Total: {ChatColors.Green}{g_iTotalCTSpawns}{ChatColors.Default})"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} Spawn for the CT team has been added. (Total: {ChatColors.Green}{spawnPositionsCT.Count}{ChatColors.Default})"); } + [ConsoleCommand("css_dm_addspawn_t", "Add the new T spawn point")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] [RequiresPermissions("@css/root")] @@ -176,19 +193,20 @@ public void OnAddSpawnT_CMD(CCSPlayerController player, CommandInfo info) { if (!g_bIsActiveEditor) { - info.ReplyToCommand($"{Localizer["Prefix"]} Spawn Editor is disabled!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} Spawn Editor is disabled!"); return; } if (player.IsValid && !player.PawnIsAlive) { - info.ReplyToCommand($"{Localizer["Prefix"]} You have to be alive to add a new spawn!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} You have to be alive to add a new spawn!"); return; } var position = player.PlayerPawn.Value!.AbsOrigin; var angle = player.PlayerPawn.Value.AbsRotation; AddNewSpawnPoint(ModuleDirectory + $"/spawns/{Server.MapName}.json", $"{position}", $"{angle}", "t"); - info.ReplyToCommand($"{Localizer["Prefix"]} Spawn for the T team has been added. (Total: {ChatColors.Green}{g_iTotalTSpawns}{ChatColors.Default})"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} Spawn for the T team has been added. (Total: {ChatColors.Green}{spawnPositionsT.Count}{ChatColors.Default})"); } + [ConsoleCommand("css_dm_removespawn", "Remove the nearest spawn point")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] [RequiresPermissions("@css/root")] @@ -196,23 +214,28 @@ public void OnRemoveSpawn_CMD(CCSPlayerController player, CommandInfo info) { if (!g_bIsActiveEditor) { - info.ReplyToCommand($"{Localizer["Prefix"]} Spawn Editor is disabled!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} Spawn Editor is disabled!"); return; } if (player.IsValid && !player.PawnIsAlive) { - info.ReplyToCommand($"{Localizer["Prefix"]} You have to be alive to remove a spawn!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} You have to be alive to remove a spawn!"); return; } - if (g_iTotalCTSpawns < 1 && g_iTotalTSpawns < 1) + if (spawnPositionsCT.Count() < 1 && spawnPositionsT.Count() < 1) { - info.ReplyToCommand($"{Localizer["Prefix"]} No spawns found!"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} No spawns found!"); return; } - var position = player.PlayerPawn.Value!.AbsOrigin!; + if (player.PlayerPawn.Value == null) + { + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} No spawns found!"); + return; + } + var position = player.PlayerPawn.Value.AbsOrigin; - string deleted = GetNearestSpawnPoint(position[0], position[1], position[2]); - player.PrintToChat($"{Localizer["Prefix"]} {ChatColors.Default}{deleted}"); + string deleted = GetNearestSpawnPoint(position); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {ChatColors.Default}{deleted}"); } } } \ No newline at end of file diff --git a/source/Functions/Entities.cs b/source/Functions/Entities.cs index 15fa01f..03923bc 100644 --- a/source/Functions/Entities.cs +++ b/source/Functions/Entities.cs @@ -3,9 +3,8 @@ namespace Deathmatch { - public partial class DeathmatchCore + public partial class Deathmatch { - public void RemoveEntities() { var bombSites = Utilities.FindAllEntitiesByDesignerName("func_bomb_target"); diff --git a/source/Functions/Menus.cs b/source/Functions/Menus.cs index 20784bd..5989141 100644 --- a/source/Functions/Menus.cs +++ b/source/Functions/Menus.cs @@ -1,21 +1,11 @@ -using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Core.Attributes.Registration; -using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Admin; -using CounterStrikeSharp.API.Modules.Utils; -using CounterStrikeSharp.API.Modules.Timers; -using System.Drawing; using CounterStrikeSharp.API.Modules.Menu; -using System.Collections.Generic; namespace Deathmatch { - public partial class DeathmatchCore + public partial class Deathmatch { - List<(string, bool, int)> PrefsMenuSounds = new List<(string, bool, int)>(); - List<(string, bool, int)> PrefsMenuFunctions = new List<(string, bool, int)>(); - private void OnSelectSubMenu(CCSPlayerController player, ChatMenuOption option, int menutype) { playerData[player].OpenedMenu = menutype; @@ -29,11 +19,11 @@ public void OpenMainMenu(CCSPlayerController player) { playerData[player].OpenedMenu = 0; - var Menu = new CenterHtmlMenu($"{Localizer["Menu.Title"]}
"); + var Menu = new CenterHtmlMenu($"{Localizer["Menu.Title"]}
", this); Menu.AddMenuOption($"{Localizer["Menu.Functions"]}", (player, opt) => OnSelectSubMenu(player, opt, 2)); Menu.AddMenuOption($"{Localizer["Menu.Sounds"]}", (player, opt) => OnSelectSubMenu(player, opt, 1)); - MenuManager.OpenCenterHtmlMenu(DeathmatchCore.Instance, player!, Menu); + Menu.Open(player); } private void OnSelectSwitchPref(CCSPlayerController player, ChatMenuOption option, int preference, bool solo = false) { @@ -47,7 +37,7 @@ public void OpenSubMenu(CCSPlayerController player, int menu, bool solo = false) var title = menu == 1 ? Localizer["Menu.SoundsTitle"] : Localizer["Menu.FunctionsTitle"]; bool IsVIP = AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag); - var Menu = new CenterHtmlMenu($"{title}
"); + var Menu = new CenterHtmlMenu($"{title}
", this); string Value; foreach (var options in PrefsMenu) @@ -62,7 +52,7 @@ public void OpenSubMenu(CCSPlayerController player, int menu, bool solo = false) if (!solo) Menu.AddMenuOption($"{Localizer["Menu.Back"]}", OnSelectBack); - MenuManager.OpenCenterHtmlMenu(DeathmatchCore.Instance, player!, Menu); + Menu.Open(player); } private void SetupDeathmatchMenus() diff --git a/source/Functions/Players.cs b/source/Functions/Players.cs index 2dd5792..3636483 100644 --- a/source/Functions/Players.cs +++ b/source/Functions/Players.cs @@ -1,31 +1,13 @@ using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Timers; -using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Utils; namespace Deathmatch { - public partial class DeathmatchCore + public partial class Deathmatch { - public List blockRandomWeaponsIntegeration = new List(); - public class DeathmatchPlayerData - { - public required string PrimaryWeapon { get; set; } - public required string SecondaryWeapon { get; set; } - public required bool SpawnProtection { get; set; } - public required int KillStreak { get; set; } - public required bool KillSound { get; set; } - public required bool HSKillSound { get; set; } - public required bool KnifeKillSound { get; set; } - public required bool HitSound { get; set; } - public required bool OnlyHS { get; set; } - public required bool HudMessages { get; set; } - public required string LastSpawn { get; set; } - public required int OpenedMenu { get; set; } - } - public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, CommandInfo info) { if (string.IsNullOrEmpty(weaponName)) @@ -38,14 +20,14 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co { if (string.IsNullOrEmpty(primaryWeapons)) { - primaryWeapons = $"{ChatColors.Green} {weapon.Replace("weapon_", "")}"; + primaryWeapons = $"{ChatColors.Green} {Localizer[weapon]}"; } else { - primaryWeapons = $"{primaryWeapons}{ChatColors.Default}, {ChatColors.Green}{weapon.Replace("weapon_", "")}"; + primaryWeapons = $"{primaryWeapons}{ChatColors.Default}, {ChatColors.Green}{Localizer[weapon]}"; } } - info.ReplyToCommand($"{Localizer["Allowed_Primary_Weapons"]}"); + info.ReplyToCommand($"{Localizer["Chat.ListOfAllowedWeapons"]}"); info.ReplyToCommand($"{ChatColors.DarkRed}• {primaryWeapons.ToUpper()}"); } if (AllowedSecondaryWeaponsList.Count != 0) @@ -54,17 +36,17 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co { if (string.IsNullOrEmpty(secondaryWeapons)) { - secondaryWeapons = $"{ChatColors.Green} {weapon.Replace("weapon_", "")}"; + secondaryWeapons = $"{ChatColors.Green} {Localizer[weapon]}"; } else { - secondaryWeapons = $"{secondaryWeapons}{ChatColors.Default}, {ChatColors.Green}{weapon.Replace("weapon_", "")}"; + secondaryWeapons = $"{secondaryWeapons}{ChatColors.Default}, {ChatColors.Green}{Localizer[weapon]}"; } } - info.ReplyToCommand($"{Localizer["Allowed_Secondary_Weapons"]}"); + info.ReplyToCommand($"{Localizer["Chat.ListOfAllowedSecondaryWeapons"]}"); info.ReplyToCommand($"{ChatColors.DarkRed}• {secondaryWeapons.ToUpper()}"); } - info.ReplyToCommand($"{Localizer["Prefix"]} /gun "); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} /gun "); return; } @@ -104,17 +86,17 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co if (matchingCount > 1) { - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["Multiple_Weapon_Select"]} {ChatColors.Default}( {matchingValues} {ChatColors.Default})"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.MultipleWeaponsSelected"]} {ChatColors.Default}( {matchingValues} {ChatColors.Default})"); return; } else if (matchingCount == 0) { if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["Weapon_Name_Not_Found", weaponName]}"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponNotFound", weaponName]}"); return; } - + bool IsVIP = AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag); if (AllowedPrimaryWeaponsList.Contains(weaponName)) { string localizerWeaponName = Localizer[weaponName]; @@ -122,19 +104,20 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co { if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["Weapon_Is_Already_Set", localizerWeaponName]}"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsIsAlreadySet", localizerWeaponName]}"); return; } - if (CheckIsWeaponRestricted(weaponName, AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag), player.TeamNum)) + if (CheckIsWeaponRestricted(weaponName, IsVIP, player.Team)) { if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); - RestrictedWeaponsInfo restrict = RestrictedWeapons[weaponName]; - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["Weapon_Is_Restricted", localizerWeaponName, restrict.nonVIPRestrict, restrict.VIPRestrict]}"); + + var restrictInfo = GetRestrictData(weaponName, IsVIP, player.Team); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsRestricted", localizerWeaponName, restrictInfo.Item1, restrictInfo.Item2]}"); return; } playerData[player].PrimaryWeapon = weaponName; - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["PrimaryWeapon_Set", localizerWeaponName]}"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.PrimaryWeaponSet", localizerWeaponName]}"); if (player.PawnIsAlive && IsHaveWeaponFromSlot(player, 1) != 1) { player.GiveNamedItem(weaponName); @@ -158,19 +141,20 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co { if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["Weapon_Is_Already_Set", localizerWeaponName]}"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponsIsAlreadySet", localizerWeaponName]}"); return; } - if (CheckIsWeaponRestricted(weaponName, AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag), player.TeamNum)) + if (CheckIsWeaponRestricted(weaponName, IsVIP, player.Team)) { if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); - RestrictedWeaponsInfo restrict = RestrictedWeapons[weaponName]; - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["Weapon_Is_Restricted", localizerWeaponName, restrict.nonVIPRestrict, restrict.VIPRestrict]}"); + + var restrictInfo = GetRestrictData(weaponName, IsVIP, player.Team); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsRestricted", localizerWeaponName, restrictInfo.Item1, restrictInfo.Item2]}"); return; } playerData[player].SecondaryWeapon = weaponName; - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["SecondaryWeapon_Set", localizerWeaponName]}"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SecondaryWeaponSet", localizerWeaponName]}"); if (player.PawnIsAlive && IsHaveWeaponFromSlot(player, 2) != 2) { player.GiveNamedItem(weaponName); @@ -192,7 +176,7 @@ public void SetupPlayerWeapons(CCSPlayerController player, string weaponName, Co if (!string.IsNullOrEmpty(Config.SoundSettings.CantEquipSound)) player.ExecuteClientCommand("play " + Config.SoundSettings.CantEquipSound); string localizerWeaponName = Localizer[weaponName]; - info.ReplyToCommand($"{Localizer["Prefix"]} {Localizer["Weapon_Disabled", localizerWeaponName]}"); + info.ReplyToCommand($"{Localizer["Chat.Prefix"]} {Localizer["Chat.WeaponIsDisabled", localizerWeaponName]}"); return; } } @@ -203,9 +187,16 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) player.InGameMoneyServices!.Account = Config.Gameplay.AllowBuyMenu ? 16000 : 0; if (!bNewMode) { - playerData[player].SpawnProtection = true; var timer = AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag) ? Config.PlayersSettings.ProtectionTimeVIP : Config.PlayersSettings.ProtectionTime; - AddTimer(timer, () => playerData[player].SpawnProtection = false, TimerFlags.STOP_ON_MAPCHANGE); + if (timer > 0.1) + { + playerData[player].SpawnProtection = true; + AddTimer(timer, () => + { + playerData[player].SpawnProtection = false; + }, TimerFlags.STOP_ON_MAPCHANGE); + } + if (!IsCasualGamemode && !blockRandomWeaponsIntegeration.Contains(player)) { blockRandomWeaponsIntegeration.Add(player); @@ -214,13 +205,14 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) } int slot = IsHaveWeaponFromSlot(player, 0); - if (slot == 1 || slot == 2) + if (slot == 1 || slot == 2 || ActiveMode == null) return; + bool IsVIP = AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag); if (AllowedPrimaryWeaponsList.Count != 0) { string PrimaryWeapon = playerData[player].PrimaryWeapon; - if (ModeData.RandomWeapons) + if (ActiveMode.RandomWeapons) { PrimaryWeapon = GetRandomWeaponFromList(AllowedPrimaryWeaponsList); } @@ -239,12 +231,12 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) } else { - if (CheckIsWeaponRestricted(PrimaryWeapon, AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag), player.TeamNum)) + if (CheckIsWeaponRestricted(PrimaryWeapon, IsVIP, player.Team)) { playerData[player].PrimaryWeapon = ""; string localizerWeaponName = Localizer[PrimaryWeapon]; - RestrictedWeaponsInfo restrict = RestrictedWeapons[PrimaryWeapon]; - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Weapon_Is_Restricted", localizerWeaponName, restrict.nonVIPRestrict, restrict.VIPRestrict]}"); + 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 { @@ -257,7 +249,7 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) if (string.IsNullOrEmpty(PrimaryWeapon)) { - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Setup_Weapons_By_Command"]}"); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SetupWeaponsCommand"]}"); } else { @@ -268,7 +260,7 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) if (AllowedSecondaryWeaponsList.Count != 0) { string SecondaryWeapon = playerData[player].SecondaryWeapon; - if (ModeData.RandomWeapons) + if (ActiveMode.RandomWeapons) { SecondaryWeapon = GetRandomWeaponFromList(AllowedSecondaryWeaponsList); } @@ -287,12 +279,13 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) } else { - if (CheckIsWeaponRestricted(SecondaryWeapon, AdminManager.PlayerHasPermissions(player, Config.PlayersSettings.VIPFlag), player.TeamNum)) + if (CheckIsWeaponRestricted(SecondaryWeapon, IsVIP, player.Team)) { playerData[player].SecondaryWeapon = ""; string localizerWeaponName = Localizer[SecondaryWeapon]; - RestrictedWeaponsInfo restrict = RestrictedWeapons[SecondaryWeapon]; - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Weapon_Is_Restricted", localizerWeaponName, restrict.nonVIPRestrict, restrict.VIPRestrict]}"); + + 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 { @@ -305,13 +298,18 @@ public void GivePlayerWeapons(CCSPlayerController player, bool bNewMode) if (string.IsNullOrEmpty(SecondaryWeapon)) { - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Setup_Weapons_By_Command"]}"); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Chat.SetupWeaponsCommand"]}"); } else { player.GiveNamedItem(SecondaryWeapon); } } + if (ActiveMode.Utilities != null && ActiveMode.Utilities.Count() > 0) + { + foreach (var item in ActiveMode.Utilities) + player.GiveNamedItem(item); + } return; } @@ -399,7 +397,7 @@ private void SwitchPrefsValue(CCSPlayerController player, int preference) Preference = Localizer["Prefs.HudMessages"]; break; } - player.PrintToChat($"{Localizer["Prefix"]} {Localizer["Prefs.ValueChanged", Preference, changedValue]}"); + player.PrintToChat($"{Localizer["Chat.Prefix"]} {Localizer["Prefs.ValueChanged", Preference, changedValue]}"); } //https://github.com/K4ryuu/K4-System/blob/dev/src/Plugin/PluginCache.cs diff --git a/source/Functions/Spawns.cs b/source/Functions/Spawns.cs index 578f493..b728aeb 100644 --- a/source/Functions/Spawns.cs +++ b/source/Functions/Spawns.cs @@ -1,28 +1,23 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; -using QAngle = CounterStrikeSharp.API.Modules.Utils.QAngle; using System.Drawing; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using System.Numerics; using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Timers; +using System.Globalization; namespace Deathmatch { - public partial class DeathmatchCore + public partial class Deathmatch { - public static Dictionary spawnPositionsCT = new Dictionary(); - public static Dictionary spawnPositionsT = new Dictionary(); - - public void PerformRespawn(CCSPlayerController player, int team, bool IsBot) + public void PerformRespawn(CCSPlayerController player, CsTeam team, bool IsBot) { - if (player == null || !player.IsValid || !player.PlayerPawn.IsValid || player.PawnIsAlive || team == 1 || team == 0) + if (player == null || !player.IsValid || player.PlayerPawn.Value == null || player.PawnIsAlive || team == CsTeam.None || team == CsTeam.Spectator) return; - var spawnsDictionary = team == (byte)CsTeam.Terrorist ? spawnPositionsT : spawnPositionsCT; - + var spawnsDictionary = team == CsTeam.Terrorist ? spawnPositionsT : spawnPositionsCT; var spawnsList = spawnsDictionary.ToList(); if (!IsBot) spawnsList.RemoveAll(x => x.Key == playerData[player].LastSpawn); @@ -34,21 +29,15 @@ public void PerformRespawn(CCSPlayerController player, int team, bool IsBot) return; } - Random random = new Random(); - int selectRadnomSpawn = random.Next(0, spawnsList.Count); - var randomSpawn = spawnsList.ElementAt(selectRadnomSpawn); - Vector position; - QAngle angle; - if (GameRules().WarmupPeriod || !Config.Gameplay.CheckDistance) { + Random random = new Random(); + var randomSpawn = spawnsDictionary.ElementAt(random.Next(spawnsDictionary.Count)); if (!IsBot) playerData[player].LastSpawn = randomSpawn.Key; player.Respawn(); - position = ParseVector(randomSpawn.Key); - angle = ParseQAngle(randomSpawn.Value); - player.PlayerPawn.Value!.Teleport(position, angle, new Vector(0, 0, 0)); + player.PlayerPawn.Value.Teleport(randomSpawn.Key, randomSpawn.Value, new Vector(0, 0, 0)); spawnsDictionary.Remove(randomSpawn.Key); AddTimer(5.0f, () => @@ -59,65 +48,64 @@ public void PerformRespawn(CCSPlayerController player, int team, bool IsBot) return; } - spawnsList = spawnsList.OrderBy(x => random.Next()).ToList(); - var closestDistances = CalculateClosestDistances(player, spawnsList); - - var Spawn = spawnsList.FirstOrDefault(spawn => - { - var spawnKey = spawn.Key; - var closestDistance = closestDistances[spawnKey]; - return closestDistance > Config.Gameplay.DistanceRespawn; - }); - - if (Spawn.Key != null) - { - if (!IsBot) - playerData[player].LastSpawn = Spawn.Key; - - player.Respawn(); - position = ParseVector(Spawn.Key); - angle = ParseQAngle(Spawn.Value); - player.PlayerPawn.Value!.Teleport(position, angle, new Vector(0, 0, 0)); - return; - } - + var Spawn = GetAvailableSpawn(player, spawnsList); if (!IsBot) - playerData[player].LastSpawn = randomSpawn.Key; + playerData[player].LastSpawn = Spawn.Key; player.Respawn(); - position = ParseVector(randomSpawn.Key); - angle = ParseQAngle(randomSpawn.Value); - player.PlayerPawn.Value!.Teleport(position, angle, new Vector(0, 0, 0)); - SendConsoleMessage($"[Deathmatch] Player {player.PlayerName} was respawned, but no available spawn point was found! Therefore, a random spawn was selected.", ConsoleColor.DarkYellow); + player.PlayerPawn.Value.Teleport(Spawn.Key, Spawn.Value, new Vector(0, 0, 0)); + AddTimer(5.0f, () => + { + if (!spawnsDictionary.ContainsKey(Spawn.Key)) + spawnsDictionary.Add(Spawn.Key, Spawn.Value); + }, TimerFlags.STOP_ON_MAPCHANGE); } - private Dictionary CalculateClosestDistances(CCSPlayerController player, List> spawnsList) + private KeyValuePair GetAvailableSpawn(CCSPlayerController player, List> spawnsList) { var allPlayers = Utilities.GetPlayers(); var playerPositions = allPlayers - .Where(p => p != null && p.IsValid && !p.IsHLTV && p.Connected == PlayerConnectedState.PlayerConnected && p.PlayerPawn.IsValid && p.PawnIsAlive && p != player) + .Where(p => !p.IsHLTV && p.Connected == PlayerConnectedState.PlayerConnected && p.PlayerPawn.IsValid && p.PawnIsAlive && p != player) .Select(p => p.PlayerPawn.Value!.AbsOrigin) .ToList(); - var closestDistances = new Dictionary(); - foreach (var spawn in spawnsList) + var availableSpawns = new Dictionary(); + int spawnCount = 0; + foreach (KeyValuePair spawn in spawnsList) { - var spawnKey = spawn.Key; - var spawnAbsOrigin = ParseVector(spawnKey); - double closestDistance = double.MaxValue; + spawnCount++; + double closestDistance = 4000; foreach (var playerPos in playerPositions) { - double distance = GetDistance(playerPos!, spawnAbsOrigin); - if (distance < closestDistance) + if (playerPos != null) { - closestDistance = distance; + double distance = GetDistance(playerPos, spawn.Key); + //Console.WriteLine($"Distance {distance} | {closestDistance}"); + if (distance < closestDistance) + { + //Console.WriteLine($"ClosestDistance Distance {distance}"); + closestDistance = distance; + } } } - closestDistances.Add(spawnKey, closestDistance); + if (closestDistance > Config.Gameplay.DistanceRespawn) + { + //Console.WriteLine($"closestDistance {closestDistance} > DistanceRespawn {Config.Gameplay.DistanceRespawn}"); + availableSpawns.Add(spawn.Key, spawn.Value); + } } - return closestDistances; + 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)); + 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)); + return randomSpawn; } public void AddNewSpawnPoint(string filepath, string posValue, string angleValue, string team) @@ -174,6 +162,7 @@ public bool RemoveSpawnPoint(string filepath, string posValue) File.WriteAllText(filepath, jsonData.ToString()); return true; } + static void RemoveSpawnpointByPos(JArray spawnpointsArray, string posToRemove) { for (int i = spawnpointsArray.Count - 1; i >= 0; i--) @@ -185,16 +174,16 @@ static void RemoveSpawnpointByPos(JArray spawnpointsArray, string posToRemove) } } } - public string GetNearestSpawnPoint(float X, float Y, float Z) + public string GetNearestSpawnPoint(Vector? playerPos) { - float lowestDistance = float.MaxValue; - string nearestSpawn = ""; + if (playerPos == null) + return "Spawn point cannot be deleted!"; + + double lowestDistance = float.MaxValue; + Vector? nearestSpawn = null; foreach (var ctSpawn in spawnPositionsCT.Keys) { - Vector3 playerPos = new Vector3(X, Y, Z); - Vector3 ctSpawnPosition = ParseVector3(ctSpawn); - float distance = Vector3.Distance(playerPos, ctSpawnPosition); - + double distance = GetDistance(playerPos, ctSpawn); if (distance < lowestDistance) { lowestDistance = distance; @@ -203,17 +192,18 @@ public string GetNearestSpawnPoint(float X, float Y, float Z) } foreach (var tSpawn in spawnPositionsT.Keys) { - Vector3 playerPos = new Vector3(X, Y, Z); - Vector3 tSpawnPosition = ParseVector3(tSpawn); - float distance = Vector3.Distance(playerPos, tSpawnPosition); - + double distance = GetDistance(playerPos, tSpawn); if (distance < lowestDistance) { lowestDistance = distance; nearestSpawn = tSpawn; } } - bool isDeleted = RemoveSpawnPoint(ModuleDirectory + $"/spawns/{Server.MapName}.json", nearestSpawn); + + bool isDeleted = false; + if (nearestSpawn != null) + isDeleted = RemoveSpawnPoint(ModuleDirectory + $"/spawns/{Server.MapName}.json", $"{nearestSpawn}"); + if (isDeleted) { LoadMapSpawns(ModuleDirectory + $"/spawns/{Server.MapName}.json", false); @@ -237,7 +227,7 @@ public void ShowAllSpawnPoints() return; } - Vector position = ParseVector(ctTeam); + var position = ctTeam; beam.Render = Color.Blue; beam.Width = 5.5f; position[2] += 50.00f; @@ -257,7 +247,7 @@ public void ShowAllSpawnPoints() SendConsoleMessage($"[Deathmatch] Failed to create beam for T", ConsoleColor.DarkYellow); return; } - Vector position = ParseVector(tTeam); + var position = tTeam; beam.Render = Color.Orange; beam.Width = 5.5f; position[2] += 50.00f; @@ -324,9 +314,6 @@ public static void CreateCustomMapSpawns() foreach (var spawn in spawnPositionsCT) { - var position = ParseVector(spawn.Key); - var angle = ParseQAngle(spawn.Value); - CBaseEntity entity; if (IsCasualGamemode) entity = Utilities.CreateEntityByName(infoPlayerCT)!; @@ -336,15 +323,14 @@ public static void CreateCustomMapSpawns() if (entity == null) { SendConsoleMessage($"[Deathmatch] Failed to create spawn point for CT", ConsoleColor.DarkYellow); - return; + continue; } - entity.Teleport(position, angle, new Vector(0, 0, 0)); + entity.Teleport(spawn.Key, spawn.Value, new Vector(0, 0, 0)); entity.DispatchSpawn(); } + foreach (var spawn in spawnPositionsT) { - var position = ParseVector(spawn.Key); - var angle = ParseQAngle(spawn.Value); CBaseEntity entity; if (IsCasualGamemode) entity = Utilities.CreateEntityByName(infoPlayerT)!; @@ -353,13 +339,14 @@ public static void CreateCustomMapSpawns() if (entity == null) { SendConsoleMessage($"[Deathmatch] Failed to create spawn point for T", ConsoleColor.DarkYellow); - return; + continue; } - entity.Teleport(position, angle, new Vector(0, 0, 0)); + entity.Teleport(spawn.Key, spawn.Value, new Vector(0, 0, 0)); entity.DispatchSpawn(); } } - public void LoadMapSpawns(string filepath, bool mapstart) + + public void LoadMapSpawns(string filePath, bool mapstart) { spawnPositionsCT.Clear(); spawnPositionsT.Clear(); @@ -369,14 +356,15 @@ public void LoadMapSpawns(string filepath, bool mapstart) } else { - if (!File.Exists(filepath)) + if (!File.Exists(filePath)) { SendConsoleMessage($"[Deathmatch] No spawn points found for this map! (Deathmatch/spawns/{Server.MapName}.json)", ConsoleColor.Red); addDefaultSpawnsToList(); } else { - var jsonContent = File.ReadAllText(filepath); + + var jsonContent = File.ReadAllText(filePath); JObject jsonData = JsonConvert.DeserializeObject(jsonContent)!; foreach (var teamData in jsonData["spawnpoints"]!) @@ -387,16 +375,15 @@ public void LoadMapSpawns(string filepath, bool mapstart) if (teamType == "ct") { - spawnPositionsCT.Add(pos, angle); + spawnPositionsCT.Add(ParseVector(pos), ParseQAngle(angle)); } else if (teamType == "t") { - spawnPositionsT.Add(pos, angle); + spawnPositionsT.Add(ParseVector(pos), ParseQAngle(angle)); } } - g_iTotalCTSpawns = spawnPositionsCT.Count; - g_iTotalTSpawns = spawnPositionsT.Count; + SendConsoleMessage($"[Deathmatch] Total Loaded Spawns: CT {spawnPositionsCT.Count} | T {spawnPositionsT.Count}", ConsoleColor.Green); if (mapstart) RemoveMapDefaulSpawns(); } @@ -404,43 +391,33 @@ public void LoadMapSpawns(string filepath, bool mapstart) } private static Vector ParseVector(string pos) { + pos = pos.Replace(",", ""); var values = pos.Split(' '); if (values.Length == 3 && - float.TryParse(values[0], out float x) && - float.TryParse(values[1], out float y) && - float.TryParse(values[2], out float z)) + float.TryParse(values[0], NumberStyles.Float, CultureInfo.InvariantCulture, out float x) && + float.TryParse(values[1], NumberStyles.Float, CultureInfo.InvariantCulture, out float y) && + float.TryParse(values[2], NumberStyles.Float, CultureInfo.InvariantCulture, out float z)) { return new Vector(x, y, z); } - return new Vector(0, 0, 0); } + private static QAngle ParseQAngle(string angle) { + angle = angle.Replace(",", ""); var values = angle.Split(' '); if (values.Length == 3 && - float.TryParse(values[0], out float x) && - float.TryParse(values[1], out float y) && - float.TryParse(values[2], out float z)) + float.TryParse(values[0], NumberStyles.Float, CultureInfo.InvariantCulture, out float x) && + float.TryParse(values[1], NumberStyles.Float, CultureInfo.InvariantCulture, out float y) && + float.TryParse(values[2], NumberStyles.Float, CultureInfo.InvariantCulture, out float z)) { return new QAngle(x, y, z); } return new QAngle(0, 0, 0); } - private static Vector3 ParseVector3(string pos) - { - var values = pos.Split(' '); - if (values.Length == 3 && - float.TryParse(values[0], out float x) && - float.TryParse(values[1], out float y) && - float.TryParse(values[2], out float z)) - { - return new Vector3(x, y, z); - } - return new Vector3(0, 0, 0); - } private static double GetDistance(Vector v1, Vector v2) { double X = v1.X - v2.X; @@ -455,15 +432,15 @@ public void addDefaultSpawnsToList() { foreach (var spawn in Utilities.FindAllEntitiesByDesignerName("info_player_counterterrorist")) { - if (spawn == null) + if (spawn == null || spawn.AbsOrigin == null || spawn.AbsRotation == null) return; - spawnPositionsCT.Add($"{spawn.AbsOrigin}", $"{spawn.AbsRotation}"); + spawnPositionsCT.Add(spawn.AbsOrigin, spawn.AbsRotation); } foreach (var spawn in Utilities.FindAllEntitiesByDesignerName("info_player_terrorist")) { - if (spawn == null) + if (spawn == null || spawn.AbsOrigin == null || spawn.AbsRotation == null) return; - spawnPositionsT.Add($"{spawn.AbsOrigin}", $"{spawn.AbsRotation}"); + spawnPositionsT.Add(spawn.AbsOrigin, spawn.AbsRotation); } } else @@ -474,21 +451,18 @@ public void addDefaultSpawnsToList() randomizer++; if (randomizer % 2 == 0) { - if (spawn == null) + if (spawn == null || spawn.AbsOrigin == null || spawn.AbsRotation == null) return; - spawnPositionsT.Add($"{spawn.AbsOrigin}", $"{spawn.AbsRotation}"); + spawnPositionsT.Add(spawn.AbsOrigin, spawn.AbsRotation); } else { - if (spawn == null) + if (spawn == null || spawn.AbsOrigin == null || spawn.AbsRotation == null) return; - spawnPositionsCT.Add($"{spawn.AbsOrigin}", $"{spawn.AbsRotation}"); + spawnPositionsCT.Add(spawn.AbsOrigin, spawn.AbsRotation); } } } - - g_iTotalCTSpawns = spawnPositionsCT.Count; - g_iTotalTSpawns = spawnPositionsT.Count; } } } \ No newline at end of file diff --git a/source/Functions/Weapons.cs b/source/Functions/Weapons.cs index 89268ab..ed86773 100644 --- a/source/Functions/Weapons.cs +++ b/source/Functions/Weapons.cs @@ -1,53 +1,14 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using Newtonsoft.Json.Linq; +using CounterStrikeSharp.API.Modules.Utils; namespace Deathmatch { - public partial class DeathmatchCore + public partial class Deathmatch { - public class RestrictedWeaponsInfo - { - public int nonVIPRestrict { get; set; } = 0; //T or Global - public int VIPRestrict { get; set; } = 0; //T or Global - public int nonVIPRestrict_Team { get; set; } = 0; //CT - public int VIPRestrict_Team { get; set; } = 0; //CT - } - - readonly HashSet SecondaryWeaponsList = new HashSet - { - "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 - { - "weapon_mag7", "weapon_nova", "weapon_sawedoff", "weapon_xm1014", - "weapon_m249", "weapon_negev", "weapon_mac10", "weapon_mp5sd", - "weapon_mp7", "weapon_mp9", "weapon_p90", "weapon_bizon", - "weapon_ump45", "weapon_ak47", "weapon_aug", "weapon_famas", - "weapon_galilar", "weapon_m4a1_silencer", "weapon_m4a1", "weapon_sg556", - "weapon_awp", "weapon_g3sg1", "weapon_scar20", "weapon_ssg08" - }; - - readonly Dictionary weaponSelectMapping = new Dictionary - { - { "m4a4", "weapon_m4a1" }, - { "weapon_m4a1", "weapon_m4a1" }, - { "m4a1_silencer", "weapon_m4a1_silencer" }, - { "m4a1", "weapon_m4a1_silencer" } - }; - - List AllowedPrimaryWeaponsList = new List(); - List AllowedSecondaryWeaponsList = new List(); - public static Dictionary RestrictedWeapons = new Dictionary(); - public static JObject? weaponsRestrictData { get; private set; } - - public bool CheckIsWeaponRestricted(string weaponName, bool isVIP, int team) + public bool CheckIsWeaponRestricted(string weaponName, bool isVIP, CsTeam team) { bool bPrimary = PrimaryWeaponsList.Contains(weaponName); - int matchingCount = 0; if (bPrimary) { if (AllowedPrimaryWeaponsList.Count == 1) @@ -58,14 +19,13 @@ public bool CheckIsWeaponRestricted(string weaponName, bool isVIP, int team) if (AllowedSecondaryWeaponsList.Count == 1) return false; } - int restrictValue = 0; if (RestrictedWeapons.ContainsKey(weaponName)) { - RestrictedWeaponsInfo restrict = RestrictedWeapons[weaponName]; + int restrictValue = GetWeaponRestrict(weaponName, isVIP, team); + int matchingCount = 0; - if (g_bWeaponRestrictGlobal) + if (Config.WeaponsRestrict.Global) { - restrictValue = isVIP ? restrict.VIPRestrict : restrict.nonVIPRestrict; if (restrictValue == 0) return false; else if (restrictValue < 0) @@ -90,29 +50,12 @@ public bool CheckIsWeaponRestricted(string weaponName, bool isVIP, int team) } else { - switch (team) - { - case 2: - restrictValue = isVIP ? restrict.VIPRestrict_Team : restrict.nonVIPRestrict_Team; - if (restrictValue == 0) - return false; - else if (restrictValue < 0) - return true; - break; - - case 3: - restrictValue = isVIP ? restrict.VIPRestrict : restrict.nonVIPRestrict; - if (restrictValue == 0) - return false; - else if (restrictValue < 0) - return true; - break; - - default: - return true; - } + if (restrictValue == 0) + return false; + else if (restrictValue < 0) + return true; - foreach (var p in Utilities.GetPlayers().Where(p => playerData.ContainsPlayer(p) && p.TeamNum == team)) + foreach (var p in Utilities.GetPlayers().Where(p => playerData.ContainsPlayer(p) && p.Team == team)) { if (bPrimary) { @@ -131,77 +74,6 @@ public bool CheckIsWeaponRestricted(string weaponName, bool isVIP, int team) return false; } - public void CheckIsValidWeaponsInList(List setupedWeaponsList, HashSet weaponsList) - { - foreach (var weapon in setupedWeaponsList) - { - if (!weaponsList.Contains(weapon)) - { - SendConsoleMessage($"[Deathmatch] Invalid weapon name: {weapon} (Mode ID: {g_iActiveMode})", ConsoleColor.Red); - } - else - { - if (weapon != null) - { - string restrictValues = GetWeaponRestrict(weapon.ToString()!, g_iActiveMode.ToString()); - if (!string.IsNullOrEmpty(restrictValues)) - { - if (restrictValues.Contains("ct") && restrictValues.Contains("t")) - { - g_bWeaponRestrictGlobal = false; - string[] teamValues = restrictValues.Split('|'); - foreach (string teamValue in teamValues) - { - string[] parts = teamValue.Split(':'); - - if (parts.Length == 2) - { - string team = parts[0].ToLower(); - string[] values = parts[1].Split(','); - - if (values.Length == 2) - { - if (team == "ct") - { - RestrictedWeapons.Add(weapon.ToString()!, new RestrictedWeaponsInfo { nonVIPRestrict = int.Parse(values[0]), VIPRestrict = int.Parse(values[1]) }); - //SendConsoleMessage($"[Deathmatch] Weapon '{weapon}' is restricted for CT Team ({values[0]} | VIP: {values[1]})", ConsoleColor.Green); - } - else if (team == "t") - { - RestrictedWeapons.Add(weapon.ToString()!, new RestrictedWeaponsInfo { nonVIPRestrict_Team = int.Parse(values[0]), VIPRestrict_Team = int.Parse(values[1]) }); - //SendConsoleMessage($"[Deathmatch] Weapon '{weapon}' is restricted for T Team ({values[0]} | VIP: {values[1]})", ConsoleColor.Green); - } - } - else - { - SendConsoleMessage($"[Deathmatch] Wrong configuration in weapons_restrict.json for '{weapon}'", ConsoleColor.Red); - } - } - } - } - else - { - g_bWeaponRestrictGlobal = true; - string[] globalValues = restrictValues.Split(','); - if (globalValues.Length == 2) - { - RestrictedWeapons.Add(weapon.ToString()!, new RestrictedWeaponsInfo { nonVIPRestrict = int.Parse(globalValues[0]), VIPRestrict = int.Parse(globalValues[1]) }); - //SendConsoleMessage($"[Deathmatch] Weapon '{weapon}' is restricted for All players ({globalValues[0]} | VIP: {globalValues[1]})", ConsoleColor.Green); - } - else - { - SendConsoleMessage($"[Deathmatch] Wrong configuration in weapons_restrict.json for '{weapon}'", ConsoleColor.Red); - } - } - } - /*else - { - Server.PrintToConsole($"{weapon} is not restricted for this mode (ID: {g_iActiveMode})"); - }*/ - } - } - } - } public string GetWeaponFromSlot(CCSPlayerController player, int slot) { if (player.PlayerPawn == null || player.PlayerPawn.Value == null || !player.PlayerPawn.IsValid || player.PlayerPawn.Value.WeaponServices == null) @@ -229,6 +101,7 @@ public string GetWeaponFromSlot(CCSPlayerController player, int slot) } 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) @@ -259,6 +132,7 @@ public int IsHaveWeaponFromSlot(CCSPlayerController player, int slot) } return 3; } + private string GetRandomWeaponFromList(List weaponsList) { Random rand = new Random(); @@ -266,49 +140,33 @@ private string GetRandomWeaponFromList(List weaponsList) return weaponsList[index]; } - public void LoadWeaponsRestrict(string filepath) + public int GetWeaponRestrict(string weaponName, bool isVIP, CsTeam team) { - if (!File.Exists(filepath)) - { - //SendConsoleMessage($"[Deathmatch] No weapons_restrict file found! (Deathmatch/weapons_restrict.json)", ConsoleColor.Red); - JObject weaponData = new JObject - { - ["weapon_ak47"] = new JArray - { - new JObject - { - ["0"] = "7,0", - ["1"] = "8,10" - } - }, - ["weapon_usp_silencer"] = new JArray - { - new JObject - { - ["0"] = "5,10", - ["1"] = "10,0", - ["3"] = "6,8" - } - } - }; + if (!RestrictedWeapons.ContainsKey(weaponName)) + return 0; + if (!RestrictedWeapons[weaponName].ContainsKey(ActiveCustomMode.ToString())) + return 0; - File.WriteAllText(filepath, weaponData.ToString()); - var jsonData = File.ReadAllText(filepath); - weaponsRestrictData = JObject.Parse(jsonData); - } - else - { - var jsonData = File.ReadAllText(filepath); - weaponsRestrictData = JObject.Parse(jsonData); - } + var restrictInfo = RestrictedWeapons[weaponName][ActiveCustomMode.ToString()][isVIP ? RestrictType.VIP : RestrictType.NonVIP]; + return Config.WeaponsRestrict.Global ? restrictInfo.Global : (team == CsTeam.CounterTerrorist ? restrictInfo.CT : restrictInfo.T); } - public string GetWeaponRestrict(string weapon, string modetype) + + public (int, int) GetRestrictData(string weaponName, bool isVIP, CsTeam team) { - if (weaponsRestrictData != null) - { - return weaponsRestrictData[weapon]?[0]?[modetype]?.ToString() ?? ""; - } - return ""; + if (!RestrictedWeapons.ContainsKey(weaponName)) + return (0, 0); + if (!RestrictedWeapons[weaponName].ContainsKey(ActiveCustomMode.ToString())) + return (0, 0); + + var restrictDataVIP = RestrictedWeapons[weaponName][ActiveCustomMode.ToString()][RestrictType.VIP]; + var restrictDataNonVIP = RestrictedWeapons[weaponName][ActiveCustomMode.ToString()][RestrictType.NonVIP]; + + if (Config.WeaponsRestrict.Global) + return (restrictDataNonVIP.Global, restrictDataVIP.Global); + + return team == CsTeam.CounterTerrorist + ? (restrictDataNonVIP.CT, restrictDataVIP.CT) + : (restrictDataNonVIP.T, restrictDataVIP.T); } } } \ No newline at end of file