From a45ce5e04e7f4d7a24c241f55f5eae827c0ce050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:44:42 +0300 Subject: [PATCH 01/13] AWP Permission Option, more weapons, changed some default values - Allow only vip players and admins to get AWP - added more weapons pistols/rifles - chnaged pistol rounds to ( 4 ) - changed "AddSkipOption" to false --- Modules/Config/RetakesAllocatorConfig.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/Config/RetakesAllocatorConfig.cs b/Modules/Config/RetakesAllocatorConfig.cs index 0ccc1df..72f4d4a 100644 --- a/Modules/Config/RetakesAllocatorConfig.cs +++ b/Modules/Config/RetakesAllocatorConfig.cs @@ -27,7 +27,10 @@ public class RetakesAllocatorConfig : BasePluginConfig public string[] TriggerWords { get; set; } = { "guns", "gun", "weapon", "weapons" }; [JsonPropertyName("AddSkipOption")] - public bool AddSkipOption { get; set; } = true; + public bool AddSkipOption { get; set; } = false; + + [JsonPropertyName("AwpPermission")] + public string AwpPermission { get; set; } = string.Empty; [JsonPropertyName("Weapons")] public WeaponsSection Weapons { get; set; } = new(); @@ -123,7 +126,7 @@ public class PrefixConfig public class PistolRoundConfig { - public int RoundAmount { get; init; } = 2; + public int RoundAmount { get; init; } = 4; public string WeaponT { get; init; } = "weapon_glock"; public string WeaponCt { get; init; } = "weapon_usp_silencer"; } From f7f703928504ea9730bcb5081e7333cd416fd572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:45:11 +0300 Subject: [PATCH 02/13] Add pistol round columns to MySqlProvider table --- Modules/Db/MySqlProvider.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/Db/MySqlProvider.cs b/Modules/Db/MySqlProvider.cs index e1263d5..093ecf9 100644 --- a/Modules/Db/MySqlProvider.cs +++ b/Modules/Db/MySqlProvider.cs @@ -24,6 +24,8 @@ public MySqlProvider(string connectionString) `ct_primary` INT NOT NULL DEFAULT 0, `t_secondary` INT NOT NULL DEFAULT 0, `ct_secondary` INT NOT NULL DEFAULT 0, + `t_pistol_round` INT NOT NULL DEFAULT 0, + `ct_pistol_round` INT NOT NULL DEFAULT 0, `give_awp` INT NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE (`auth`) From bcdc4fcdfad0e08c739afcb5b9164c9050231ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:45:28 +0300 Subject: [PATCH 03/13] Add pistol round fields to SqliteProvider table --- Modules/Db/SqliteProvider.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/Db/SqliteProvider.cs b/Modules/Db/SqliteProvider.cs index 6ded8b4..5843759 100644 --- a/Modules/Db/SqliteProvider.cs +++ b/Modules/Db/SqliteProvider.cs @@ -24,6 +24,8 @@ name VARCHAR(128) NOT NULL, ct_primary INTEGER NOT NULL DEFAULT 0, t_secondary INTEGER NOT NULL DEFAULT 0, ct_secondary INTEGER NOT NULL DEFAULT 0, + t_pistol_round INTEGER NOT NULL DEFAULT 0, + ct_pistol_round INTEGER NOT NULL DEFAULT 0, give_awp INTEGER NOT NULL DEFAULT 0 ); """; From 284d2ba243856a0155d8f6d51fe9dd6c5df4be5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:45:47 +0300 Subject: [PATCH 04/13] Add properties for pistol round preferences --- Modules/Db/WeaponPreference.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/Db/WeaponPreference.cs b/Modules/Db/WeaponPreference.cs index 869f5d6..7980faa 100644 --- a/Modules/Db/WeaponPreference.cs +++ b/Modules/Db/WeaponPreference.cs @@ -12,5 +12,7 @@ public class WeaponPreference public int CtPrimary { get; set; } public int TSecondary { get; set; } public int CtSecondary { get; set; } + public int TPistolRound { get; set; } + public int CtPistolRound { get; set; } public int GiveAwp { get; set; } } From 5bd8ac9c8ed80cf2587791c968f250ed5dde42f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:46:04 +0300 Subject: [PATCH 05/13] Add pistol round columns to WeaponStore database --- Modules/Db/WeaponStore.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Modules/Db/WeaponStore.cs b/Modules/Db/WeaponStore.cs index 2c16711..e9ea605 100644 --- a/Modules/Db/WeaponStore.cs +++ b/Modules/Db/WeaponStore.cs @@ -27,6 +27,20 @@ public async Task InitializeAsync() await using var conn = _provider.CreateConnection(); await conn.OpenAsync(); await conn.ExecuteAsync(_provider.CreateTableSql); + await AddColumnIfMissing(conn, "t_pistol_round"); + await AddColumnIfMissing(conn, "ct_pistol_round"); + } + + private static async Task AddColumnIfMissing(System.Data.Common.DbConnection conn, string column) + { + try + { + await conn.ExecuteAsync($"ALTER TABLE weapons ADD COLUMN {column} INTEGER NOT NULL DEFAULT 0"); + } + catch + { + // Column already exists. CREATE TABLE handles fresh installs; this keeps old DBs working. + } } /// Returns the stored preferences for a SteamID, or null if none exist. @@ -36,7 +50,7 @@ public async Task InitializeAsync() await conn.OpenAsync(); return await conn.QuerySingleOrDefaultAsync( """ - SELECT auth, name, t_primary, ct_primary, t_secondary, ct_secondary, give_awp + SELECT auth, name, t_primary, ct_primary, t_secondary, ct_secondary, t_pistol_round, ct_pistol_round, give_awp FROM weapons WHERE auth = @auth """, @@ -68,6 +82,8 @@ UPDATE weapons ct_primary = @CtPrimary, t_secondary = @TSecondary, ct_secondary = @CtSecondary, + t_pistol_round = @TPistolRound, + ct_pistol_round = @CtPistolRound, give_awp = @GiveAwp WHERE auth = @Auth """, From d28fff4020d3270a2e941aa51eee2384b08e1415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:46:50 +0300 Subject: [PATCH 06/13] Replace OpenTPrimaryMenu with OpenPistolRoundTMenu --- Modules/Handlers/Commands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Handlers/Commands.cs b/Modules/Handlers/Commands.cs index 1304bb6..4e90ebe 100644 --- a/Modules/Handlers/Commands.cs +++ b/Modules/Handlers/Commands.cs @@ -61,7 +61,7 @@ private static void GunsCommand(CCSPlayerController? player, CommandInfo command return; } - OpenTPrimaryMenu(player); + OpenPistolRoundTMenu(player); } private static void CTGunsCommand(CCSPlayerController? player, CommandInfo commandInfo) From 74de7bf9b3c6550a91427c197a9fc78d706022ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:47:07 +0300 Subject: [PATCH 07/13] Replace OpenTPrimaryMenu with OpenPistolRoundTMenu --- Modules/Handlers/Listeners.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Handlers/Listeners.cs b/Modules/Handlers/Listeners.cs index 80e33c9..b9a8485 100644 --- a/Modules/Handlers/Listeners.cs +++ b/Modules/Handlers/Listeners.cs @@ -65,7 +65,7 @@ private static HookResult OnSay(CCSPlayerController? player, CommandInfo command return HookResult.Continue; } - OpenTPrimaryMenu(player); + OpenPistolRoundTMenu(player); return HookResult.Continue; } From 4975cdcea1fbc23468750aeef14363f0c16f134c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:47:37 +0300 Subject: [PATCH 08/13] Add pistol round weapons and refactor weapon selection --- Modules/Weapons/Allocator.cs | 68 ++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/Modules/Weapons/Allocator.cs b/Modules/Weapons/Allocator.cs index efe48c2..395ff52 100644 --- a/Modules/Weapons/Allocator.cs +++ b/Modules/Weapons/Allocator.cs @@ -5,6 +5,7 @@ using RetakesAllocator.Modules.Votes; using static RetakesAllocator.Modules.Weapons.Menu; +using static RetakesAllocator.Modules.Utils; using static RetakesAllocator.Modules.Votes.Votes; namespace RetakesAllocator.Modules.Weapons; @@ -23,32 +24,46 @@ public enum WeaponType PrimaryT, PrimaryCt, SecondaryT, - SecondaryCt + SecondaryCt, + PistolRoundT, + PistolRoundCt }; public static List PrimaryT = new() { new Weapon("weapon_ak47", "AK-47"), + new Weapon("weapon_galilar", "Galil"), new Weapon("weapon_sg556", "SG 553") }; public static List PrimaryCt = new() { - new Weapon("weapon_m4a1", "M4A4"), new Weapon("weapon_m4a1_silencer", "M4A1-S"), + new Weapon("weapon_m4a1", "M4A4"), + new Weapon("weapon_famas", "FAMAS"), new Weapon("weapon_aug", "AUG") }; public static List PistolsT = new() { new Weapon("weapon_glock", "Glock-18"), + new Weapon("weapon_deagle", "Desert Eagle"), new Weapon("weapon_p250", "P250"), + new Weapon("weapon_tec9", "Tec-9"), + new Weapon("weapon_elite", "Dual Berettas"), + new Weapon("weapon_cz75a", "CZ75"), + new Weapon("weapon_revolver", "Revolver") }; public static List PistolsCT = new() { new Weapon("weapon_usp_silencer", "USP-S"), + new Weapon("weapon_deagle", "Desert Eagle"), new Weapon("weapon_p250", "P250"), + new Weapon("weapon_fiveseven", "Five-SeveN"), + new Weapon("weapon_elite", "Dual Berettas"), + new Weapon("weapon_cz75a", "CZ75"), + new Weapon("weapon_revolver", "Revolver"), new Weapon("weapon_hkp2000", "P2000") }; @@ -61,6 +76,8 @@ public enum WeaponType public int PrimaryWeaponCt = 0; public int SecondaryWeaponT = 0; public int SecondaryWeaponCt = 0; + public int PistolRoundWeaponT = GetWeaponIndex(Core.Config?.PistolRound.WeaponT ?? "weapon_glock", PistolsT); + public int PistolRoundWeaponCt = GetWeaponIndex(Core.Config?.PistolRound.WeaponCt ?? "weapon_usp_silencer", PistolsCT); public GiveAwp GiveAwp = GiveAwp.Never; public bool ShouldGiveAwp = false; @@ -71,6 +88,12 @@ public static void ResetNades() _nades = new Nades(Core.NadesConfig.TNades); } + private static int GetWeaponIndex(string item, List weapons) + { + var index = weapons.FindIndex(w => w.Item == item); + return index < 0 ? 0 : index; + } + public static int GetWeaponIndex(string weapon, WeaponType type) { switch(type) @@ -83,6 +106,10 @@ public static int GetWeaponIndex(string weapon, WeaponType type) return PistolsT.FindIndex(w => w.DisplayName == weapon); case WeaponType.SecondaryCt: return PistolsCT.FindIndex(w => w.DisplayName == weapon); + case WeaponType.PistolRoundT: + return PistolsT.FindIndex(w => w.DisplayName == weapon); + case WeaponType.PistolRoundCt: + return PistolsCT.FindIndex(w => w.DisplayName == weapon); } return -1; @@ -90,6 +117,11 @@ public static int GetWeaponIndex(string weapon, WeaponType type) public bool SetupGiveAwp() { + if (!HasAwpAccess(CCsPlayerController)) + { + return false; + } + var giveAwp = GiveAwp switch { GiveAwp.Always => true, @@ -205,7 +237,7 @@ public void Allocate() } else { - primary = CCsPlayerController.Team == CsTeam.Terrorist ? PrimaryT[PrimaryWeaponT].Item : PrimaryCt[PrimaryWeaponCt].Item; + primary = GetPrimaryWeapon(); } string secondary; @@ -229,6 +261,21 @@ public void Allocate() } } + private string GetPrimaryWeapon() + { + var weapons = CCsPlayerController.Team == CsTeam.Terrorist ? PrimaryT : PrimaryCt; + var selectedIndex = CCsPlayerController.Team == CsTeam.Terrorist ? PrimaryWeaponT : PrimaryWeaponCt; + var primary = weapons[selectedIndex].Item; + + if (HasAwpAccess(CCsPlayerController) || !primary.Equals("weapon_awp", StringComparison.OrdinalIgnoreCase)) + { + return primary; + } + + return weapons.FirstOrDefault(w => !w.Item.Equals("weapon_awp", StringComparison.OrdinalIgnoreCase))?.Item + ?? (CCsPlayerController.Team == CsTeam.Terrorist ? "weapon_ak47" : "weapon_m4a1"); + } + public void AllocatePistolRound() { if (!player.Controller.IsValid) @@ -246,7 +293,9 @@ public void AllocatePistolRound() return; } - var secondary = (CCsPlayerController.Team == CsTeam.Terrorist) ? Core.Config.PistolRound.WeaponT : Core.Config.PistolRound.WeaponCt; + var secondary = CCsPlayerController.Team == CsTeam.Terrorist + ? PistolsT[PistolRoundWeaponT].Item + : PistolsCT[PistolRoundWeaponCt].Item; CCsPlayerController.GiveNamedItem(secondary); CCsPlayerController.GiveNamedItem(CsItem.Knife); @@ -276,10 +325,17 @@ public void AllocateVote(Vote vote) var weapons = CCsPlayerController.Team == CsTeam.Terrorist ? vote.WeaponsT : vote.WeaponsCt; + if (!HasAwpAccess(CCsPlayerController)) + { + weapons = weapons.Where(w => !w.Equals("awp", StringComparison.OrdinalIgnoreCase)).ToList(); + } + if(weapons.Count > 1) { ShowWeaponSelectionMenu(CCsPlayerController, weapons, WeaponSelectionTime); - } else { + } + else if(weapons.Count == 1) + { CCsPlayerController.GiveNamedItem("weapon_" + weapons.First()); } @@ -324,4 +380,4 @@ private void GiveCtEquipment() }; } } -} \ No newline at end of file +} From 3df496c3f58976eadc15ffe53b784c7fc3bbc4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:47:55 +0300 Subject: [PATCH 09/13] Refactor weapon menu display names and options --- Modules/Weapons/Menu.cs | 118 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 7 deletions(-) diff --git a/Modules/Weapons/Menu.cs b/Modules/Weapons/Menu.cs index e11df3f..0bc2e88 100644 --- a/Modules/Weapons/Menu.cs +++ b/Modules/Weapons/Menu.cs @@ -52,9 +52,85 @@ public class Menu {"ssg08", "SSG 08"} }; + public static void OpenPistolRoundTMenu(CCSPlayerController player) + { + var centerHtmlMenu = new CenterHtmlMenu("[ T ] Pistol Round", Plugin); + + if(Core.Config.AddSkipOption) + { + centerHtmlMenu.AddMenuOption("SKIP", (p, _) => OpenPistolRoundCTMenu(p)); + } + + foreach (var weapon in PistolsT) + { + centerHtmlMenu.AddMenuOption(weapon.DisplayName, (CCSPlayerController player, ChatMenuOption option) => OnPistolRoundTSelect(player, option)); + } + + MenuManager.OpenCenterHtmlMenu(Plugin, player, centerHtmlMenu); + } + + private static void OnPistolRoundTSelect(CCSPlayerController player, ChatMenuOption? option) + { + if (option == null) + { + PrintToChat(player, $"{Prefix} You did not select a weapon!"); + return; + } + + var playerObj = FindPlayer(player); + + if (playerObj == null!) + { + return; + } + + PrintToChat(player, $"{Prefix} You selected {option.Text} as T Pistol Round!"); + playerObj.WeaponsAllocator.PistolRoundWeaponT = GetWeaponIndex(option.Text, WeaponType.PistolRoundT); + + OpenPistolRoundCTMenu(player); + } + + public static void OpenPistolRoundCTMenu(CCSPlayerController player) + { + var centerHtmlMenu = new CenterHtmlMenu("[ CT ] Pistol Round", Plugin); + + if(Core.Config.AddSkipOption) + { + centerHtmlMenu.AddMenuOption("SKIP", (p, _) => OpenTPrimaryMenu(p)); + } + + foreach (var weapon in PistolsCT) + { + centerHtmlMenu.AddMenuOption(weapon.DisplayName, (CCSPlayerController player, ChatMenuOption option) => OnPistolRoundCTSelect(player, option)); + } + + MenuManager.OpenCenterHtmlMenu(Plugin, player, centerHtmlMenu); + } + + private static void OnPistolRoundCTSelect(CCSPlayerController player, ChatMenuOption? option) + { + if (option == null) + { + PrintToChat(player, $"{Prefix} You did not select a weapon!"); + return; + } + + var playerObj = FindPlayer(player); + + if (playerObj == null!) + { + return; + } + + PrintToChat(player, $"{Prefix} You selected {option.Text} as CT Pistol Round!"); + playerObj.WeaponsAllocator.PistolRoundWeaponCt = GetWeaponIndex(option.Text, WeaponType.PistolRoundCt); + + OpenTPrimaryMenu(player); + } + public static void OpenTPrimaryMenu(CCSPlayerController player, bool showNext = true) { - var centerHtmlMenu = new CenterHtmlMenu($"{Prefix} Select a T Primary Weapon", Plugin); + var centerHtmlMenu = new CenterHtmlMenu("[ T ] Primary Weapon", Plugin); if(Core.Config.AddSkipOption && showNext) { @@ -63,6 +139,11 @@ public static void OpenTPrimaryMenu(CCSPlayerController player, bool showNext = foreach (var weapon in PrimaryT) { + if (!HasAwpAccess(player) && weapon.Item.Equals("weapon_awp", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + centerHtmlMenu.AddMenuOption(weapon.DisplayName, (CCSPlayerController player, ChatMenuOption option) => OnTPrimarySelect(player, option, showNext)); } @@ -99,7 +180,7 @@ private static void OnTPrimarySelect(CCSPlayerController player, ChatMenuOption? public static void OpenCTPrimaryMenu(CCSPlayerController player, bool showNext = true) { - var centerHtmlMenu = new CenterHtmlMenu($"{Prefix} Select a CT Primary Weapon", Plugin); + var centerHtmlMenu = new CenterHtmlMenu("[ CT ] Primary Weapon", Plugin); if(Core.Config.AddSkipOption && showNext) { @@ -108,6 +189,11 @@ public static void OpenCTPrimaryMenu(CCSPlayerController player, bool showNext = foreach (var weapon in PrimaryCt) { + if (!HasAwpAccess(player) && weapon.Item.Equals("weapon_awp", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + centerHtmlMenu.AddMenuOption(weapon.DisplayName, (CCSPlayerController player, ChatMenuOption option) => OnCTPrimarySelect(player, option, showNext)); } @@ -144,7 +230,7 @@ private static void OnCTPrimarySelect(CCSPlayerController player, ChatMenuOption public static void OpenSecondaryTMenu(CCSPlayerController player, bool showNext = true) { - var centerHtmlMenu = new CenterHtmlMenu($"{Prefix} Select a T Secondary Weapon", Plugin); + var centerHtmlMenu = new CenterHtmlMenu("[ T ] Secondary Weapon", Plugin); if(Core.Config.AddSkipOption && showNext) { @@ -189,11 +275,11 @@ private static void OnSecondaryTSelect(CCSPlayerController player, ChatMenuOptio public static void OpenSecondaryCTMenu(CCSPlayerController player, bool showNext = true) { - var centerHtmlMenu = new CenterHtmlMenu($"{Prefix} Select a CT Secondary Weapon", Plugin); + var centerHtmlMenu = new CenterHtmlMenu("[ CT ] Secondary Weapon", Plugin); if(Core.Config.AddSkipOption && showNext) { - centerHtmlMenu.AddMenuOption("SKIP", (p, _) => OpenGiveAWPMenu(p)); + centerHtmlMenu.AddMenuOption("SKIP", (p, _) => OpenAwpMenuIfAllowed(p)); } foreach (var weapon in PistolsCT) @@ -224,6 +310,17 @@ private static void OnSecondaryCTSelect(CCSPlayerController player, ChatMenuOpti playerObj.WeaponsAllocator.SecondaryWeaponCt = GetWeaponIndex(option.Text, WeaponType.SecondaryCt); if(showNext) + { + OpenAwpMenuIfAllowed(player); + return; + } + + MenuManager.CloseActiveMenu(player); + } + + private static void OpenAwpMenuIfAllowed(CCSPlayerController player) + { + if (HasAwpAccess(player)) { OpenGiveAWPMenu(player); return; @@ -234,7 +331,14 @@ private static void OnSecondaryCTSelect(CCSPlayerController player, ChatMenuOpti public static void OpenGiveAWPMenu(CCSPlayerController player) { - var centerHtmlMenu = new CenterHtmlMenu($"{Prefix} Select when to give the AWP", Plugin); + if (!HasAwpAccess(player)) + { + PrintToChat(player, $"{Prefix} The AWP menu is for VIP players only."); + MenuManager.CloseActiveMenu(player); + return; + } + + var centerHtmlMenu = new CenterHtmlMenu("When To Get AWP", Plugin); centerHtmlMenu.AddMenuOption("Never", OnGiveAWPSelect); centerHtmlMenu.AddMenuOption("Sometimes", OnGiveAWPSelect); @@ -344,4 +448,4 @@ private static string WeaponToDisplayName(string weapon) { return Weapons.TryGetValue(weapon, out var name) ? name : weapon; } -} \ No newline at end of file +} From d50f8bd6a630aba7c30c87bd57bb47b434fc674d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:48:33 +0300 Subject: [PATCH 10/13] AWP permission check and safe weapon index method --- Modules/Utils.cs | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 738a15f..dd7a03e 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -1,6 +1,7 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Admin; using Microsoft.Extensions.Logging; using static RetakesAllocator.Modules.Core; using RetakesAllocator.Modules.Weapons; @@ -34,6 +35,24 @@ public static Player FindPlayer(CCSPlayerController controller) return Players.Find(player => player.PlayerIndex == controller.Index)!; } + public static bool HasAwpAccess(CCSPlayerController player) + { + var permission = Core.Config.AwpPermission.Trim(); + + if (permission.Length == 0) + { + return true; + } + + if (!permission.StartsWith('@')) + { + permission = $"@{permission}"; + } + + return AdminManager.PlayerHasPermissions(player, permission) + || AdminManager.GetPlayerAdminData(player.AuthorizedSteamID) != null; + } + public static void ServerCommand(string command, params object[] args) { Server.ExecuteCommand(string.Format(command, args)); @@ -102,13 +121,20 @@ private static void ApplyPreferences(Player playerObj, WeaponPreference pref) { var allocator = playerObj.WeaponsAllocator; - allocator.PrimaryWeaponT = pref.TPrimary > Allocator.PrimaryT.Count ? 0 : pref.TPrimary; - allocator.PrimaryWeaponCt = pref.CtPrimary > Allocator.PrimaryCt.Count ? 0 : pref.CtPrimary; - allocator.SecondaryWeaponT = pref.TSecondary > Allocator.PistolsT.Count ? 0 : pref.TSecondary; - allocator.SecondaryWeaponCt = pref.CtSecondary > Allocator.PistolsCT.Count ? 0 : pref.CtSecondary; + allocator.PrimaryWeaponT = SafeWeaponIndex(pref.TPrimary, Allocator.PrimaryT.Count); + allocator.PrimaryWeaponCt = SafeWeaponIndex(pref.CtPrimary, Allocator.PrimaryCt.Count); + allocator.SecondaryWeaponT = SafeWeaponIndex(pref.TSecondary, Allocator.PistolsT.Count); + allocator.SecondaryWeaponCt = SafeWeaponIndex(pref.CtSecondary, Allocator.PistolsCT.Count); + allocator.PistolRoundWeaponT = SafeWeaponIndex(pref.TPistolRound, Allocator.PistolsT.Count); + allocator.PistolRoundWeaponCt = SafeWeaponIndex(pref.CtPistolRound, Allocator.PistolsCT.Count); allocator.GiveAwp = (GiveAwp)pref.GiveAwp; } + private static int SafeWeaponIndex(int index, int count) + { + return index < 0 || index >= count ? 0 : index; + } + public static void RemovePlayerFromList(CCSPlayerController player, bool flush = false) { if (player == null || !player.IsValid || player.IsBot) @@ -131,6 +157,8 @@ public static void RemovePlayerFromList(CCSPlayerController player, bool flush = CtPrimary = playerObj.WeaponsAllocator.PrimaryWeaponCt, TSecondary = playerObj.WeaponsAllocator.SecondaryWeaponT, CtSecondary = playerObj.WeaponsAllocator.SecondaryWeaponCt, + TPistolRound = playerObj.WeaponsAllocator.PistolRoundWeaponT, + CtPistolRound = playerObj.WeaponsAllocator.PistolRoundWeaponCt, GiveAwp = (int)playerObj.WeaponsAllocator.GiveAwp, }; From bcf9ee139094e3c7991f6cc032160eeb02737592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:49:10 +0300 Subject: [PATCH 11/13] Update ConfigModelTests to reflect new config values --- tests/RetakesAllocator.Tests/ConfigModelTests.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/RetakesAllocator.Tests/ConfigModelTests.cs b/tests/RetakesAllocator.Tests/ConfigModelTests.cs index e7100ae..d652bec 100644 --- a/tests/RetakesAllocator.Tests/ConfigModelTests.cs +++ b/tests/RetakesAllocator.Tests/ConfigModelTests.cs @@ -14,15 +14,16 @@ public void Defaults_MatchExistingCanonicalValues() var config = new RetakesAllocatorConfig(); Assert.Equal("sqlite", config.DbConnection.Provider); - Assert.True(config.AddSkipOption); + Assert.False(config.AddSkipOption); + Assert.Equal(string.Empty, config.AwpPermission); Assert.Equal(new[] { "guns", "gun", "weapon", "weapons" }, config.TriggerWords); // Weapon lists copied from the Allocator canonical defaults. - Assert.Equal(2, config.Weapons.PrimaryT.Count); + Assert.Equal(3, config.Weapons.PrimaryT.Count); Assert.Equal("weapon_ak47", config.Weapons.PrimaryT[0].Item); - Assert.Equal(3, config.Weapons.PrimaryCt.Count); - Assert.Equal(2, config.Weapons.PistolsT.Count); - Assert.Equal(3, config.Weapons.PistolsCt.Count); + Assert.Equal(4, config.Weapons.PrimaryCt.Count); + Assert.Equal(7, config.Weapons.PistolsT.Count); + Assert.Equal(8, config.Weapons.PistolsCt.Count); // Nades defaults. Assert.Equal(2, config.Nades.CtNades.Flashbangs); @@ -54,7 +55,7 @@ public void Json_UsesLabeledSectionNames_AndRoundTrips() foreach (var section in new[] { "\"ConfigVersion\"", "\"DbConnection\"", "\"Prefix\"", "\"PistolRound\"", - "\"TriggerWords\"", "\"AddSkipOption\"", + "\"TriggerWords\"", "\"AddSkipOption\"", "\"AwpPermission\"", "\"Weapons\"", "\"Nades\"", "\"Votes\"", }) { From c2ef974fe6bb21f91a7d05489ae997c9ed99b868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 01:49:41 +0300 Subject: [PATCH 12/13] Add tests for pistol round properties in WeaponStore --- tests/RetakesAllocator.Tests/WeaponStoreTests.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/RetakesAllocator.Tests/WeaponStoreTests.cs b/tests/RetakesAllocator.Tests/WeaponStoreTests.cs index e49ce01..f8d5d86 100644 --- a/tests/RetakesAllocator.Tests/WeaponStoreTests.cs +++ b/tests/RetakesAllocator.Tests/WeaponStoreTests.cs @@ -30,6 +30,8 @@ public async Task CreateUserAsync_ThenGetUserAsync_ReturnsDefaultsRow() Assert.Equal(0, result.CtPrimary); Assert.Equal(0, result.TSecondary); Assert.Equal(0, result.CtSecondary); + Assert.Equal(0, result.TPistolRound); + Assert.Equal(0, result.CtPistolRound); Assert.Equal(0, result.GiveAwp); } @@ -46,6 +48,8 @@ public async Task SaveUserAsync_PersistsAllPreferenceColumns() CtPrimary = 2, TSecondary = 1, CtSecondary = 2, + TPistolRound = 1, + CtPistolRound = 2, GiveAwp = 2, }; await db.Store.SaveUserAsync(pref); @@ -56,6 +60,8 @@ public async Task SaveUserAsync_PersistsAllPreferenceColumns() Assert.Equal(2, result.CtPrimary); Assert.Equal(1, result.TSecondary); Assert.Equal(2, result.CtSecondary); + Assert.Equal(1, result.TPistolRound); + Assert.Equal(2, result.CtPistolRound); Assert.Equal(2, result.GiveAwp); } From 105edb408c77b218c659c2179367f54028146fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=AA=20St=CE=B1r?= <45707960+Staaar0@users.noreply.github.com> Date: Tue, 9 Jun 2026 02:06:59 +0300 Subject: [PATCH 13/13] Update some default settings and added new one - Updated PistolRound to ( 4 ) - changed "AddSkipOption" to false - "AwpPermission" for VIP Players --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7f449e3..69fbf78 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,13 @@ This is the full default config, generated on first load: "PrefixCon": "[RetakesAllocator]" }, "PistolRound": { - "RoundAmount": 2, + "RoundAmount": 4, "WeaponT": "weapon_glock", "WeaponCt": "weapon_usp_silencer" }, "TriggerWords": [ "guns", "gun", "weapon", "weapons" ], - "AddSkipOption": true, + "AddSkipOption": false, + "AwpPermission": "", "Weapons": { "PrimaryT": [ { "Item": "weapon_ak47", "DisplayName": "AK-47" }, @@ -130,9 +131,12 @@ For **MySQL**, set `"Provider": "mysql"` and fill in the connection fields; for Selectable weapons, grenade kits, and weapon-vote definitions all live in the single config file above: -- **`Weapons`** — the four selectable lists (`PrimaryT`, `PrimaryCt`, `PistolsT`, - `PistolsCt`). Each entry is an `Item` (the `weapon_*` class name) and the +- **`Weapons`** — the six selectable lists (`PistolsT`, `PistolsCT`, `PrimaryT`, `PrimaryCT`, +`SecondaryT`, `SecondaryCT`,). Each entry is an `Item` (the `weapon_*` class name) and the `DisplayName` shown in the in-game menu. +- **`AwpPermission`** — permission needed to see/select AWP options and receive an + AWP. The default is `empty`; set the permission `@VIP` for VIP Players, or + leave it empty to allow everyone. - **`Nades`** — per-team grenade kits (`CtNades` / `TNades`): how many of each grenade a player is given. - **`Votes`** — each vote defines a chat command (`css_`), the weapons it