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