├── Dapper.dll ├── TagsApi.dll ├── Tomlyn.dll ├── MySqlConnector.dll ├── .gitignore ├── StoreApi ├── StoreApi.csproj ├── IStoreApi.cs └── Store.cs ├── Store ├── src │ ├── item │ │ ├── items │ │ │ ├── link.cs │ │ │ ├── respawn.cs │ │ │ ├── sound.cs │ │ │ ├── weapon.cs │ │ │ ├── gravity.cs │ │ │ ├── armor.cs │ │ │ ├── open.cs │ │ │ ├── bunnyhop.cs │ │ │ ├── godmode.cs │ │ │ ├── speed.cs │ │ │ ├── health.cs │ │ │ ├── coloredskin.cs │ │ │ ├── smoke.cs │ │ │ ├── tracer.cs │ │ │ ├── grenadetrail.cs │ │ │ ├── wings.cs │ │ │ ├── equipment.cs │ │ │ ├── tags.cs │ │ │ ├── trail.cs │ │ │ └── playerskin.cs │ │ ├── ItemModuleManager.cs │ │ └── item.cs │ ├── Extension │ │ ├── TomlExtensions.cs │ │ ├── VectorExtensions.cs │ │ ├── JsonExtensions.cs │ │ └── PlayerExtensions.cs │ ├── gamerules │ │ └── gamerules.cs │ ├── credits │ │ └── credits.cs │ ├── log │ │ └── log.cs │ ├── cs2-store.cs │ ├── menu │ │ ├── menubase.cs │ │ └── menu.cs │ ├── api │ │ └── api.cs │ ├── findtarget │ │ └── findtarget.cs │ ├── config │ │ └── config.cs │ ├── command │ │ └── command.cs │ └── event │ │ └── event.cs ├── cs2-store.csproj └── lang │ ├── zh-Hans.json │ ├── en.json │ ├── tr.json │ ├── pl.json │ ├── pt-BR.json │ ├── sl.json │ ├── ua.json │ ├── ru.json │ ├── ro.json │ └── fr.json ├── cs2-store.sln ├── .github └── workflows │ └── build.yml ├── config-example.toml ├── README.md └── cs2-store-example.json /Dapper.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schwarper/cs2-store/HEAD/Dapper.dll -------------------------------------------------------------------------------- /TagsApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schwarper/cs2-store/HEAD/TagsApi.dll -------------------------------------------------------------------------------- /Tomlyn.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schwarper/cs2-store/HEAD/Tomlyn.dll -------------------------------------------------------------------------------- /MySqlConnector.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schwarper/cs2-store/HEAD/MySqlConnector.dll -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | **/obj 3 | **/bin 4 | 5 | # Ignore everything in BuildOutput directory 6 | BuildOutput/ -------------------------------------------------------------------------------- /StoreApi/StoreApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | $(ProjectDir)..\BuildOutput\shared\StoreApi\ 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Store/src/item/items/link.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using static StoreApi.Store; 4 | 5 | namespace Store; 6 | 7 | [StoreItemType("link")] 8 | public class Item_Link : IItemModule 9 | { 10 | public bool Equipable => false; 11 | public bool? RequiresAlive => null; 12 | 13 | public void OnPluginStart() { } 14 | 15 | public void OnMapStart() { } 16 | 17 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 18 | 19 | public bool OnEquip(CCSPlayerController player, Dictionary item) 20 | { 21 | player.ExecuteClientCommandFromServer(item["link"]); 22 | return true; 23 | } 24 | 25 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 26 | { 27 | return true; 28 | } 29 | } -------------------------------------------------------------------------------- /Store/src/item/items/respawn.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using static StoreApi.Store; 4 | 5 | namespace Store; 6 | 7 | [StoreItemType("respawn")] 8 | public class Item_Respawn : IItemModule 9 | { 10 | public bool Equipable => false; 11 | public bool? RequiresAlive => false; 12 | 13 | public void OnPluginStart() { } 14 | 15 | public void OnMapStart() { } 16 | 17 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 18 | 19 | public bool OnEquip(CCSPlayerController player, Dictionary item) 20 | { 21 | if (player.Team is not (CsTeam.Terrorist or CsTeam.CounterTerrorist)) 22 | return false; 23 | 24 | player.Respawn(); 25 | return true; 26 | } 27 | 28 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 29 | { 30 | return true; 31 | } 32 | } -------------------------------------------------------------------------------- /Store/src/item/items/sound.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | using static StoreApi.Store; 5 | 6 | namespace Store; 7 | 8 | [StoreItemType("sound")] 9 | public class Item_Sound : IItemModule 10 | { 11 | public bool Equipable => false; 12 | public bool? RequiresAlive => null; 13 | 14 | public void OnPluginStart() { } 15 | 16 | public void OnMapStart() { } 17 | 18 | public void OnServerPrecacheResources(ResourceManifest manifest) 19 | { 20 | Item.GetItemsByType("sound").ForEach(item => manifest.AddResource(item.Value["sound"])); 21 | } 22 | 23 | public bool OnEquip(CCSPlayerController player, Dictionary item) 24 | { 25 | Utilities.GetPlayers() 26 | .Where(target => target != null && target.IsValid) 27 | .ToList() 28 | .ForEach(target => target.ExecuteClientCommand($"play {item["sound"]}")); 29 | 30 | return true; 31 | } 32 | 33 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 34 | { 35 | return true; 36 | } 37 | } -------------------------------------------------------------------------------- /Store/src/item/items/weapon.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using Store.Extension; 4 | using static StoreApi.Store; 5 | 6 | namespace Store; 7 | 8 | [StoreItemType("weapon")] 9 | public class Item_Weapon : IItemModule 10 | { 11 | public bool Equipable => false; 12 | public bool? RequiresAlive => true; 13 | 14 | public void OnPluginStart() { } 15 | 16 | public void OnMapStart() { } 17 | 18 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 19 | 20 | public bool OnEquip(CCSPlayerController player, Dictionary item) 21 | { 22 | if (item.TryGetValue("no_pistol_round", out string? nopistolround) && nopistolround == "true" && GameRules.IsPistolRound()) 23 | { 24 | player.PrintToChatMessage("No in pistol round", Item.GetItemName(player, item)); 25 | return false; 26 | } 27 | 28 | player.GiveNamedItem(item["weapon"]); 29 | return true; 30 | } 31 | 32 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 33 | { 34 | return true; 35 | } 36 | } -------------------------------------------------------------------------------- /Store/src/item/items/gravity.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using System.Globalization; 4 | using static StoreApi.Store; 5 | 6 | namespace Store; 7 | 8 | [StoreItemType("gravity")] 9 | public class Item_Gravity : IItemModule 10 | { 11 | public bool Equipable => false; 12 | public bool? RequiresAlive => true; 13 | 14 | public void OnPluginStart() { } 15 | 16 | public void OnMapStart() { } 17 | 18 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 19 | 20 | public bool OnEquip(CCSPlayerController player, Dictionary item) 21 | { 22 | if (!float.TryParse(item["gravityValue"], CultureInfo.InvariantCulture, out float gravityValue)) 23 | { 24 | return false; 25 | } 26 | 27 | if (player.PlayerPawn?.Value is not { } playerPawn) return false; 28 | 29 | playerPawn.GravityScale = gravityValue; 30 | return true; 31 | } 32 | 33 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 34 | { 35 | if (player.PlayerPawn?.Value is { } playerPawn) 36 | { 37 | playerPawn.GravityScale = 1.0f; 38 | } 39 | return true; 40 | } 41 | } -------------------------------------------------------------------------------- /Store/src/item/items/armor.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using Store.Extension; 4 | using static Store.Config_Config; 5 | using static StoreApi.Store; 6 | 7 | namespace Store; 8 | 9 | [StoreItemType("armor")] 10 | public class Item_Armor : IItemModule 11 | { 12 | public bool Equipable => false; 13 | public bool? RequiresAlive => true; 14 | 15 | public void OnPluginStart() { } 16 | 17 | public void OnMapStart() { } 18 | 19 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 20 | 21 | public bool OnEquip(CCSPlayerController player, Dictionary item) 22 | { 23 | if (!int.TryParse(item["armorValue"], out int armor)) 24 | return false; 25 | 26 | if (player.PlayerPawn?.Value is not { } playerPawn) 27 | return false; 28 | 29 | int maxArmor = Config.Settings.MaxArmor; 30 | if (maxArmor > 0 && playerPawn.ArmorValue >= maxArmor) 31 | return false; 32 | 33 | playerPawn.GiveArmor(Math.Min(armor, maxArmor - playerPawn.ArmorValue)); 34 | return true; 35 | } 36 | 37 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 38 | { 39 | return true; 40 | } 41 | } -------------------------------------------------------------------------------- /Store/src/Extension/TomlExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Tomlyn.Model; 3 | 4 | namespace Store.Extension; 5 | 6 | public static class TomlExtensions 7 | { 8 | public static T? GetSection(this TomlTable model, string sectionName) where T : new() 9 | { 10 | if (!model.TryGetValue(sectionName, out object? sectionObj) || sectionObj is not TomlTable section) 11 | return default; 12 | 13 | return MapTomlTableToObject(section); 14 | } 15 | 16 | public static T MapTomlTableToObject(this TomlTable table) where T : new() 17 | { 18 | T obj = new(); 19 | PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); 20 | 21 | foreach (PropertyInfo prop in props) 22 | { 23 | if (!prop.CanWrite || !table.TryGetValue(prop.Name, out object? value)) 24 | continue; 25 | 26 | try 27 | { 28 | if (prop.PropertyType == typeof(List) && value is TomlArray array) 29 | prop.SetValue(obj, array.OfType().ToList()); 30 | else 31 | prop.SetValue(obj, Convert.ChangeType(value, prop.PropertyType)); 32 | } 33 | catch 34 | { } 35 | } 36 | 37 | return obj; 38 | } 39 | } -------------------------------------------------------------------------------- /Store/src/Extension/VectorExtensions.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | 4 | namespace Store.Extension; 5 | 6 | public static class VectorExtensions 7 | { 8 | public static Vector GetEyePosition(CCSPlayerController player) 9 | { 10 | if (player.PlayerPawn?.Value is not { } pawn || pawn.CameraServices == null) 11 | { 12 | throw new ArgumentException("Player pawn or camera services are not valid."); 13 | } 14 | 15 | Vector absOrigin = pawn.AbsOrigin!; 16 | float viewOffsetZ = pawn.CameraServices.OldPlayerViewOffsetZ; 17 | 18 | return new Vector(absOrigin.X, absOrigin.Y, absOrigin.Z + viewOffsetZ); 19 | } 20 | 21 | public static float CalculateDistance(Vector vector1, Vector vector2) 22 | { 23 | float dx = vector2.X - vector1.X; 24 | float dy = vector2.Y - vector1.Y; 25 | float dz = vector2.Z - vector1.Z; 26 | 27 | return MathF.Sqrt((dx * dx) + (dy * dy) + (dz * dz)); 28 | } 29 | 30 | public static void Copy(Vector source, Vector destination) 31 | { 32 | destination.X = source.X; 33 | destination.Y = source.Y; 34 | destination.Z = source.Z; 35 | } 36 | 37 | public static bool IsZero(Vector vector) 38 | { 39 | return vector.LengthSqr() == 0; 40 | } 41 | } -------------------------------------------------------------------------------- /Store/src/item/ItemModuleManager.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using static StoreApi.Store; 3 | 4 | namespace Store; 5 | 6 | public static class ItemModuleManager 7 | { 8 | public static readonly Dictionary Modules = []; 9 | 10 | public static void RegisterModules(Assembly assembly) 11 | { 12 | foreach (Type type in assembly.GetTypes().Where(t => t is { IsClass: true, IsAbstract: false } && typeof(IItemModule).IsAssignableFrom(t))) 13 | { 14 | if (Activator.CreateInstance(type) is not IItemModule module) 15 | continue; 16 | 17 | if (type.GetCustomAttribute() is { } attr) 18 | { 19 | LoadModule(attr.Name, module); 20 | } 21 | else if (type.GetCustomAttribute()?.Names is { } attrs) 22 | { 23 | foreach (string attrName in attrs) 24 | { 25 | LoadModule(attrName, module); 26 | } 27 | } 28 | } 29 | } 30 | 31 | private static void LoadModule(string name, IItemModule module) 32 | { 33 | Modules[name] = module; 34 | Console.WriteLine($"[CS2-Store] Module '{name}' has been added."); 35 | module.OnPluginStart(); 36 | } 37 | } -------------------------------------------------------------------------------- /Store/src/item/items/open.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | using static StoreApi.Store; 5 | 6 | namespace Store; 7 | 8 | [StoreItemType("open")] 9 | public class Item_Open : IItemModule 10 | { 11 | private static readonly string[] DoorNames = 12 | [ 13 | "func_door", 14 | "func_movelinear", 15 | "func_door_rotating", 16 | "prop_door_rotating" 17 | ]; 18 | 19 | public bool Equipable => false; 20 | public bool? RequiresAlive => null; 21 | 22 | public void OnPluginStart() { } 23 | 24 | public void OnMapStart() { } 25 | 26 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 27 | 28 | public bool OnEquip(CCSPlayerController player, Dictionary item) 29 | { 30 | foreach (string doorName in DoorNames) 31 | { 32 | IEnumerable doors = Utilities.FindAllEntitiesByDesignerName(doorName); 33 | foreach (CBaseEntity door in doors) 34 | { 35 | door.AcceptInput("Open"); 36 | } 37 | } 38 | 39 | return true; 40 | } 41 | 42 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 43 | { 44 | return true; 45 | } 46 | } -------------------------------------------------------------------------------- /Store/src/item/items/bunnyhop.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using Store.Extension; 4 | using static Store.Store; 5 | using static StoreApi.Store; 6 | 7 | namespace Store; 8 | 9 | [StoreItemType("bunnyhop")] 10 | public class Item_Bunnyhop : IItemModule 11 | { 12 | public bool Equipable => true; 13 | public bool? RequiresAlive => null; 14 | 15 | private static bool _bunnyhopExists = false; 16 | 17 | public void OnPluginStart() 18 | { 19 | _bunnyhopExists = Item.IsAnyItemExistInType("bunnyhop"); 20 | } 21 | 22 | public void OnMapStart() { } 23 | 24 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 25 | 26 | public bool OnEquip(CCSPlayerController player, Dictionary item) 27 | { 28 | return true; 29 | } 30 | 31 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 32 | { 33 | return true; 34 | } 35 | 36 | public static void OnTick(CCSPlayerController player) 37 | { 38 | if (!_bunnyhopExists) return; 39 | 40 | Store_Equipment? playerBunnyhop = Instance.GlobalStorePlayerEquipments.FirstOrDefault(p => p.SteamID == player.SteamID && p.Type == "bunnyhop"); 41 | if (playerBunnyhop == null) return; 42 | 43 | if (player.PlayerPawn?.Value is not { } playerPawn) return; 44 | 45 | playerPawn.BunnyHop(player); 46 | } 47 | } -------------------------------------------------------------------------------- /Store/src/item/items/godmode.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using Store.Extension; 4 | using System.Globalization; 5 | using static Store.Store; 6 | using static StoreApi.Store; 7 | 8 | namespace Store; 9 | 10 | [StoreItemType("godmode")] 11 | public class Item_Godmode : IItemModule 12 | { 13 | public bool Equipable => false; 14 | public bool? RequiresAlive => true; 15 | 16 | public void OnPluginStart() { } 17 | 18 | public void OnMapStart() { } 19 | 20 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 21 | 22 | public bool OnEquip(CCSPlayerController player, Dictionary item) 23 | { 24 | if (!float.TryParse(item["godmodeTimerValue"], CultureInfo.InvariantCulture, out float godmodeTimerValue)) 25 | { 26 | return false; 27 | } 28 | 29 | if (player.PlayerPawn?.Value is not { } playerPawn) return false; 30 | 31 | if (godmodeTimerValue > 0.0f) 32 | { 33 | Instance.AddTimer(godmodeTimerValue, () => 34 | { 35 | playerPawn.TakesDamage = true; 36 | player.PrintToChatMessage("Godmode expired"); 37 | }); 38 | } 39 | 40 | playerPawn.TakesDamage = false; 41 | return true; 42 | } 43 | 44 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 45 | { 46 | return true; 47 | } 48 | } -------------------------------------------------------------------------------- /Store/src/gamerules/gamerules.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Cvars; 4 | using static Store.Config_Config; 5 | 6 | namespace Store; 7 | 8 | public static class GameRules 9 | { 10 | private static CCSGameRulesProxy? _gameRulesProxy; 11 | private static readonly ConVar _mpHalftime = ConVar.Find("mp_halftime")!; 12 | private static readonly ConVar _mpMaxrounds = ConVar.Find("mp_maxrounds")!; 13 | 14 | public static bool IgnoreWarmUp() 15 | { 16 | if (_gameRulesProxy?.IsValid != true) 17 | { 18 | _gameRulesProxy = Utilities.FindAllEntitiesByDesignerName("cs_gamerules").FirstOrDefault(); 19 | } 20 | 21 | return Config.Credits["default"].IgnoreWarmup && (_gameRulesProxy?.GameRules?.WarmupPeriod ?? false); 22 | } 23 | 24 | public static bool IsPistolRound() 25 | { 26 | if (_gameRulesProxy?.IsValid != true) 27 | { 28 | _gameRulesProxy = Utilities.FindAllEntitiesByDesignerName("cs_gamerules").FirstOrDefault(); 29 | } 30 | 31 | bool isHalftime = _mpHalftime.GetPrimitiveValue(); 32 | int maxRounds = _mpMaxrounds.GetPrimitiveValue(); 33 | 34 | return _gameRulesProxy?.GameRules?.TotalRoundsPlayed == 0 || 35 | (isHalftime && maxRounds / 2 == _gameRulesProxy?.GameRules?.TotalRoundsPlayed) || 36 | (_gameRulesProxy?.GameRules?.GameRestart ?? false); 37 | } 38 | } -------------------------------------------------------------------------------- /Store/src/item/items/speed.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using Store.Extension; 4 | using System.Globalization; 5 | using static Store.Store; 6 | using static StoreApi.Store; 7 | 8 | namespace Store; 9 | 10 | [StoreItemType("speed")] 11 | public class Item_Speed : IItemModule 12 | { 13 | public bool Equipable => false; 14 | public bool? RequiresAlive => true; 15 | 16 | public void OnPluginStart() { } 17 | 18 | public void OnMapStart() { } 19 | 20 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 21 | 22 | public bool OnEquip(CCSPlayerController player, Dictionary item) 23 | { 24 | if (!float.TryParse(item["speedValue"], CultureInfo.InvariantCulture, out float speed) || 25 | !float.TryParse(item["speedTimerValue"], CultureInfo.InvariantCulture, out float speedtimer)) 26 | return false; 27 | 28 | CCSPlayerPawn? playerPawn = player.PlayerPawn.Value; 29 | if (playerPawn == null) 30 | return false; 31 | 32 | playerPawn.VelocityModifier = speed; 33 | 34 | if (speedtimer > 0.0) 35 | { 36 | Instance.AddTimer(speedtimer, () => 37 | { 38 | playerPawn.VelocityModifier = 1.0f; 39 | player.PrintToChatMessage("Speed expired"); 40 | }); 41 | } 42 | 43 | return true; 44 | } 45 | 46 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 47 | { 48 | return true; 49 | } 50 | } -------------------------------------------------------------------------------- /Store/src/credits/credits.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using static Store.Store; 3 | using static StoreApi.Store; 4 | 5 | namespace Store; 6 | 7 | public static class Credits 8 | { 9 | public static Store_Player? GetStorePlayer(CCSPlayerController player) 10 | { 11 | return Instance.GlobalStorePlayers.FirstOrDefault(p => p.SteamID == player.SteamID); 12 | } 13 | 14 | public static int Get(CCSPlayerController player) 15 | { 16 | return GetStorePlayer(player)?.Credits ?? -1; 17 | } 18 | 19 | public static int GetOriginal(CCSPlayerController player) 20 | { 21 | return GetStorePlayer(player)?.OriginalCredits ?? -1; 22 | } 23 | 24 | public static int SetOriginal(CCSPlayerController player, int credits) 25 | { 26 | Store_Player? storePlayer = GetStorePlayer(player); 27 | if (storePlayer == null) return -1; 28 | 29 | storePlayer.OriginalCredits = credits; 30 | return storePlayer.OriginalCredits; 31 | } 32 | 33 | public static int Set(CCSPlayerController player, int credits) 34 | { 35 | Store_Player? storePlayer = GetStorePlayer(player); 36 | if (storePlayer == null) return -1; 37 | 38 | storePlayer.Credits = credits; 39 | return storePlayer.Credits; 40 | } 41 | 42 | public static int Give(CCSPlayerController player, int credits) 43 | { 44 | Store_Player? storePlayer = GetStorePlayer(player); 45 | if (storePlayer == null) return -1; 46 | 47 | storePlayer.Credits = Math.Max(storePlayer.Credits + credits, 0); 48 | return storePlayer.Credits; 49 | } 50 | } -------------------------------------------------------------------------------- /cs2-store.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.35013.160 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cs2-store", "Store\cs2-store.csproj", "{6E4C86F8-8E8E-4E22-9815-339EED9BCC7E}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StoreApi", "StoreApi\StoreApi.csproj", "{3FB0AFB3-316A-4D08-9CB3-63CFD720AC3D}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {6E4C86F8-8E8E-4E22-9815-339EED9BCC7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {6E4C86F8-8E8E-4E22-9815-339EED9BCC7E}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {6E4C86F8-8E8E-4E22-9815-339EED9BCC7E}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {6E4C86F8-8E8E-4E22-9815-339EED9BCC7E}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {3FB0AFB3-316A-4D08-9CB3-63CFD720AC3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {3FB0AFB3-316A-4D08-9CB3-63CFD720AC3D}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {3FB0AFB3-316A-4D08-9CB3-63CFD720AC3D}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {3FB0AFB3-316A-4D08-9CB3-63CFD720AC3D}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A9FC1EA6-0A7A-4B04-B5A3-0FB63C74290A} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Store/src/item/items/health.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using Store.Extension; 4 | using static Store.Config_Config; 5 | using static StoreApi.Store; 6 | 7 | namespace Store; 8 | 9 | [StoreItemType("health")] 10 | public class Item_Health : IItemModule 11 | { 12 | public bool Equipable => false; 13 | public bool? RequiresAlive => true; 14 | 15 | public void OnPluginStart() { } 16 | 17 | public void OnMapStart() { } 18 | 19 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 20 | 21 | public bool OnEquip(CCSPlayerController player, Dictionary item) 22 | { 23 | if (!int.TryParse(item["healthValue"], out int healthValue)) 24 | return false; 25 | 26 | if (player.PlayerPawn?.Value is not { } playerPawn) 27 | return false; 28 | 29 | int currentHealth = playerPawn.GetHealth(); 30 | int maxHealth = Config.Settings.MaxHealth; 31 | int pawnMaxHealth = playerPawn.MaxHealth; 32 | 33 | if (maxHealth > 0 && currentHealth >= maxHealth) 34 | return false; 35 | else if (maxHealth == -1 && currentHealth >= pawnMaxHealth) 36 | return false; 37 | 38 | int newHealth = currentHealth + healthValue; 39 | 40 | if (maxHealth > 0) 41 | { 42 | newHealth = Math.Min(newHealth, maxHealth); 43 | } 44 | else if (maxHealth == -1) 45 | { 46 | newHealth = Math.Min(newHealth, pawnMaxHealth); 47 | } 48 | 49 | player.SetHealth(newHealth); 50 | return true; 51 | } 52 | 53 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 54 | { 55 | return true; 56 | } 57 | } -------------------------------------------------------------------------------- /Store/src/Extension/JsonExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | namespace Store.Extension; 4 | 5 | public static class JsonExtensions 6 | { 7 | public static bool IsValueKindObject(this JsonValueKind valueKind) 8 | { 9 | return valueKind == JsonValueKind.Object; 10 | } 11 | 12 | public static List GetElementJsonProperty(this JsonElement element, List ignorePropNameList) 13 | { 14 | return [.. element.EnumerateObject().Where(prop => !ignorePropNameList.Contains(prop.Name))]; 15 | } 16 | 17 | public static Dictionary> ExtractItems(this JsonElement category) 18 | { 19 | Dictionary> itemsDictionary = []; 20 | 21 | foreach (JsonProperty subItem in category.EnumerateObject()) 22 | { 23 | if (subItem.Value.ValueKind == JsonValueKind.Object) 24 | { 25 | if (subItem.Value.TryGetProperty("uniqueid", out JsonElement uniqueIdElement)) 26 | { 27 | string uniqueId = uniqueIdElement.GetString() ?? $"unknown_{subItem.Name}"; 28 | Dictionary itemData = subItem.Value.EnumerateObject() 29 | .ToDictionary(prop => prop.Name, prop => prop.Value.ToString()); 30 | 31 | itemData["name"] = subItem.Name; 32 | itemsDictionary[uniqueId] = itemData; 33 | } 34 | else 35 | { 36 | Dictionary> nestedItems = ExtractItems(subItem.Value); 37 | foreach (KeyValuePair> nestedItem in nestedItems) 38 | { 39 | itemsDictionary[nestedItem.Key] = nestedItem.Value; 40 | } 41 | } 42 | } 43 | } 44 | 45 | return itemsDictionary; 46 | } 47 | } -------------------------------------------------------------------------------- /Store/cs2-store.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | $(ProjectDir)..\BuildOutput\plugins\cs2-store\ 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ..\TagsApi.dll 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /StoreApi/IStoreApi.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Core.Capabilities; 3 | using System.Reflection; 4 | using static StoreApi.Store; 5 | 6 | namespace StoreApi; 7 | 8 | public interface IStoreApi 9 | { 10 | static readonly PluginCapability Capability = new("cs2-store:api"); 11 | 12 | event Action>? OnPlayerPurchaseItem; 13 | event Action>? OnPlayerEquipItem; 14 | event Action>? OnPlayerUnequipItem; 15 | event Action>? OnPlayerSellItem; 16 | 17 | string GetDatabaseString(); 18 | int GetPlayerCredits(CCSPlayerController player); 19 | int SetPlayerCredits(CCSPlayerController player, int credits); 20 | int GetPlayerOriginalCredits(CCSPlayerController player); 21 | int SetPlayerOriginalCredits(CCSPlayerController player, int credits); 22 | int GivePlayerCredits(CCSPlayerController player, int credits); 23 | bool Item_Give(CCSPlayerController player, Dictionary item); 24 | bool Item_Purchase(CCSPlayerController player, Dictionary item); 25 | bool Item_Equip(CCSPlayerController player, Dictionary item); 26 | bool Item_Unequip(CCSPlayerController player, Dictionary item, bool update); 27 | bool Item_Sell(CCSPlayerController player, Dictionary item); 28 | bool Item_PlayerHas(CCSPlayerController player, string type, string uniqueId, bool ignoreVip); 29 | bool Item_PlayerUsing(CCSPlayerController player, string type, string uniqueId); 30 | bool Item_IsInJson(string uniqueId); 31 | bool IsPlayerVip(CCSPlayerController player); 32 | Dictionary? GetItem(string uniqueId); 33 | List>> GetItemsByType(string type); 34 | List GetPlayerItems(CCSPlayerController player, string? type); 35 | List GetPlayerEquipments(CCSPlayerController player, string? type); 36 | void RegisterModules(Assembly assembly); 37 | } -------------------------------------------------------------------------------- /Store/src/item/items/coloredskin.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using Store.Extension; 4 | using System.Drawing; 5 | using static Store.Store; 6 | using static StoreApi.Store; 7 | 8 | namespace Store; 9 | 10 | [StoreItemType("coloredskin")] 11 | public class Item_ColoredSkin : IItemModule 12 | { 13 | public bool Equipable => true; 14 | public bool? RequiresAlive => null; 15 | 16 | private static bool _coloredSkinExists = false; 17 | 18 | public void OnPluginStart() 19 | { 20 | _coloredSkinExists = Item.IsAnyItemExistInType("coloredskin"); 21 | } 22 | 23 | public void OnMapStart() { } 24 | 25 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 26 | 27 | public bool OnEquip(CCSPlayerController player, Dictionary item) 28 | { 29 | return true; 30 | } 31 | 32 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 33 | { 34 | player.PlayerPawn.Value?.ColorSkin(Color.White); 35 | return true; 36 | } 37 | 38 | public static void OnTick(CCSPlayerController player) 39 | { 40 | if (!_coloredSkinExists) return; 41 | 42 | Store_Equipment? playerColoredSkin = Instance.GlobalStorePlayerEquipments.FirstOrDefault(p => p.SteamID == player.SteamID && p.Type == "coloredskin"); 43 | if (playerColoredSkin == null) return; 44 | 45 | Dictionary? itemData = Item.GetItem(playerColoredSkin.UniqueId); 46 | if (itemData == null) return; 47 | 48 | Color color; 49 | 50 | if (itemData.TryGetValue("color", out string? scolor) && !string.IsNullOrEmpty(scolor)) 51 | { 52 | string[] colorValues = scolor.Split(' '); 53 | color = Color.FromArgb(int.Parse(colorValues[0]), int.Parse(colorValues[1]), int.Parse(colorValues[2])); 54 | } 55 | else 56 | { 57 | Array knownColors = Enum.GetValues(typeof(KnownColor)); 58 | KnownColor? randomColorName = (KnownColor?)knownColors.GetValue(Instance.Random.Next(knownColors.Length)); 59 | 60 | if (!randomColorName.HasValue) return; 61 | 62 | color = Color.FromKnownColor(randomColorName.Value); 63 | } 64 | 65 | player.PlayerPawn.Value?.ColorSkin(color); 66 | } 67 | } -------------------------------------------------------------------------------- /Store/src/item/items/smoke.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | using System.Globalization; 5 | using static Store.Store; 6 | using static StoreApi.Store; 7 | 8 | namespace Store; 9 | 10 | [StoreItemType("smoke")] 11 | public class Item_Smoke : IItemModule 12 | { 13 | private static bool smokeExists = false; 14 | 15 | public bool Equipable => true; 16 | public bool? RequiresAlive => null; 17 | 18 | public void OnPluginStart() 19 | { 20 | smokeExists = Item.IsAnyItemExistInType("smoke"); 21 | } 22 | 23 | public void OnMapStart() { } 24 | 25 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 26 | 27 | public bool OnEquip(CCSPlayerController player, Dictionary item) 28 | { 29 | return true; 30 | } 31 | 32 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 33 | { 34 | return true; 35 | } 36 | 37 | public static void OnEntityCreated(CEntityInstance entity) 38 | { 39 | if (!smokeExists || entity.DesignerName != "smokegrenade_projectile") 40 | return; 41 | 42 | CSmokeGrenadeProjectile grenade = new(entity.Handle); 43 | if (grenade.Handle == IntPtr.Zero) 44 | return; 45 | 46 | Server.NextFrame(() => 47 | { 48 | CBasePlayerController? player = grenade.Thrower.Value?.Controller.Value; 49 | if (player == null) 50 | return; 51 | 52 | Store_Equipment? item = Instance.GlobalStorePlayerEquipments.FirstOrDefault(p => p.SteamID == player.SteamID && p.Type == "smoke"); 53 | if (item == null) 54 | return; 55 | 56 | if (item.UniqueId == "colorsmoke") 57 | { 58 | grenade.SmokeColor.X = Instance.Random.NextSingle() * 255.0f; 59 | grenade.SmokeColor.Y = Instance.Random.NextSingle() * 255.0f; 60 | grenade.SmokeColor.Z = Instance.Random.NextSingle() * 255.0f; 61 | } 62 | else 63 | { 64 | Dictionary? itemdata = Item.GetItem(item.UniqueId); 65 | if (itemdata == null) 66 | return; 67 | 68 | string[] colorValues = itemdata["color"].Split(' '); 69 | grenade.SmokeColor.X = float.Parse(colorValues[0], CultureInfo.InvariantCulture); 70 | grenade.SmokeColor.Y = float.Parse(colorValues[1], CultureInfo.InvariantCulture); 71 | grenade.SmokeColor.Z = float.Parse(colorValues[2], CultureInfo.InvariantCulture); 72 | } 73 | }); 74 | } 75 | } -------------------------------------------------------------------------------- /StoreApi/Store.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Modules.Utils; 3 | using Timer = CounterStrikeSharp.API.Modules.Timers.Timer; 4 | 5 | namespace StoreApi; 6 | 7 | public abstract class Store 8 | { 9 | public class Store_Player 10 | { 11 | public required ulong SteamID { get; set; } 12 | public required string PlayerName { get; set; } 13 | public int Credits { get; set; } 14 | public int OriginalCredits { get; set; } 15 | public DateTime DateOfJoin { get; set; } 16 | public DateTime DateOfLastJoin { get; set; } 17 | public bool? bPlayerIsLoaded; 18 | } 19 | 20 | public class Store_Item 21 | { 22 | public required ulong SteamID { get; set; } 23 | public int Price { get; set; } 24 | public required string Type { get; set; } 25 | public required string UniqueId { get; set; } 26 | public DateTime DateOfPurchase { get; set; } 27 | public DateTime DateOfExpiration { get; set; } 28 | } 29 | 30 | public class Store_Equipment 31 | { 32 | public required ulong SteamID { get; set; } 33 | public required string Type { get; set; } 34 | public required string UniqueId { get; set; } 35 | public int Slot { get; set; } 36 | } 37 | 38 | public class Store_Item_Types 39 | { 40 | public required string Type; 41 | public required Action MapStart; 42 | public required Action ServerPrecacheResources; 43 | public required Func, bool> Equip; 44 | public required Func, bool, bool> Unequip; 45 | public required bool Equipable; 46 | public bool? Alive; 47 | } 48 | public class PlayerTimer 49 | { 50 | public Timer? CreditIntervalTimer { get; set; } 51 | } 52 | 53 | public interface IItemModule 54 | { 55 | void OnPluginStart(); 56 | void OnMapStart(); 57 | void OnServerPrecacheResources(ResourceManifest manifest); 58 | bool OnEquip(CCSPlayerController player, Dictionary item); 59 | bool OnUnequip(CCSPlayerController player, Dictionary item, bool update); 60 | bool Equipable { get; } 61 | bool? RequiresAlive { get; } 62 | } 63 | 64 | [AttributeUsage(AttributeTargets.Class)] 65 | public class StoreItemTypeAttribute(string name) : Attribute 66 | { 67 | public string Name { get; } = name; 68 | } 69 | 70 | [AttributeUsage(AttributeTargets.Class)] 71 | public class StoreItemTypesAttribute(string[] name) : Attribute 72 | { 73 | public string[] Names { get; } = name; 74 | } 75 | } -------------------------------------------------------------------------------- /Store/src/log/log.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using CounterStrikeSharp.API; 3 | 4 | namespace Store; 5 | 6 | public static class Log 7 | { 8 | public enum LogType 9 | { 10 | GiveCredit, 11 | GiftCredit 12 | } 13 | 14 | public class LogEntry 15 | { 16 | public string Date { get; set; } = string.Empty; 17 | public string From { get; set; } = string.Empty; 18 | public string FromId { get; set; } = string.Empty; 19 | public string To { get; set; } = string.Empty; 20 | public string ToId { get; set; } = string.Empty; 21 | public int CreditsGiven { get; set; } 22 | } 23 | 24 | private static readonly JsonSerializerOptions JsonOptions = new() 25 | { 26 | WriteIndented = true, 27 | Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping 28 | }; 29 | 30 | public static void SaveLog( 31 | string fromName, 32 | string fromSteamId, 33 | string toName, 34 | string toSteamId, 35 | int creditsAmount, 36 | LogType logType) 37 | { 38 | try 39 | { 40 | string logFolder = Path.Combine( 41 | Server.GameDirectory, 42 | "csgo", 43 | "addons", 44 | "counterstrikesharp", 45 | "logs", 46 | "Store" 47 | ); 48 | 49 | Directory.CreateDirectory(logFolder); 50 | 51 | string logFile = Path.Combine( 52 | logFolder, 53 | $"{DateTime.Now:dd.MM.yyyy}-{logType.ToString().ToLower()}-log.json" 54 | ); 55 | 56 | List logs = LoadLogs(logFile); 57 | 58 | LogEntry logEntry = new() 59 | { 60 | Date = DateTime.Now.ToString("HH:mm:ss"), 61 | From = fromName, 62 | FromId = fromSteamId, 63 | To = toName, 64 | ToId = toSteamId, 65 | CreditsGiven = creditsAmount 66 | }; 67 | 68 | logs.Add(logEntry); 69 | 70 | File.WriteAllText(logFile, JsonSerializer.Serialize(logs, JsonOptions)); 71 | } 72 | catch (Exception ex) 73 | { 74 | Server.PrintToConsole($"credit log error: {ex.Message}"); 75 | } 76 | } 77 | 78 | private static List LoadLogs(string logFile) 79 | { 80 | if (!File.Exists(logFile)) 81 | return []; 82 | 83 | try 84 | { 85 | string existing = File.ReadAllText(logFile); 86 | return string.IsNullOrWhiteSpace(existing) 87 | ? [] 88 | : JsonSerializer.Deserialize>(existing) ?? []; 89 | } 90 | catch 91 | { 92 | return []; 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /Store/src/item/items/tracer.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | using Store.Extension; 5 | using System.Globalization; 6 | using static Store.Store; 7 | using static StoreApi.Store; 8 | 9 | namespace Store; 10 | 11 | [StoreItemType("tracer")] 12 | public class Item_Tracer : IItemModule 13 | { 14 | public bool Equipable => true; 15 | public bool? RequiresAlive => null; 16 | 17 | public void OnPluginStart() 18 | { 19 | if (Item.IsAnyItemExistInType("tracer")) 20 | Instance.RegisterEventHandler(OnBulletImpact); 21 | } 22 | 23 | public void OnMapStart() { } 24 | 25 | public void OnServerPrecacheResources(ResourceManifest manifest) 26 | { 27 | Item.GetItemsByType("tracer").ForEach(item => manifest.AddResource(item.Value["model"])); 28 | } 29 | 30 | public bool OnEquip(CCSPlayerController player, Dictionary item) 31 | { 32 | return true; 33 | } 34 | 35 | public bool OnUnequip(CCSPlayerController player, Dictionary item, bool update) 36 | { 37 | return true; 38 | } 39 | 40 | private static HookResult OnBulletImpact(EventBulletImpact @event, GameEventInfo info) 41 | { 42 | CCSPlayerController? player = @event.Userid; 43 | if (player == null || !player.IsValid) 44 | return HookResult.Continue; 45 | 46 | Store_Equipment? playertracer = Instance.GlobalStorePlayerEquipments.FirstOrDefault(p => p.SteamID == player.SteamID && p.Type == "tracer"); 47 | if (playertracer == null) 48 | return HookResult.Continue; 49 | 50 | Dictionary? itemdata = Item.GetItem(playertracer.UniqueId); 51 | if (itemdata == null) 52 | return HookResult.Continue; 53 | 54 | CBeam? entity = Utilities.CreateEntityByName("beam"); 55 | if (entity == null || !entity.IsValid) 56 | return HookResult.Continue; 57 | 58 | string acceptinputvalue = itemdata.GetValueOrDefault("acceptInputValue", "Start"); 59 | entity.SetModel(itemdata["model"]); 60 | entity.DispatchSpawn(); 61 | entity.AcceptInput(acceptinputvalue); 62 | 63 | Vector position = VectorExtensions.GetEyePosition(player); 64 | entity.Teleport(position, new QAngle(), new Vector()); 65 | 66 | entity.EndPos.X = @event.X; 67 | entity.EndPos.Y = @event.Y; 68 | entity.EndPos.Z = @event.Z; 69 | Utilities.SetStateChanged(entity, "CBeam", "m_vecEndPos"); 70 | 71 | float lifetime = itemdata.TryGetValue("lifetime", out string? value) && float.TryParse(value, CultureInfo.InvariantCulture, out float lt) ? lt : 0.3f; 72 | 73 | Instance.AddTimer(lifetime, () => 74 | { 75 | if (entity.IsValid) 76 | entity.Remove(); 77 | }); 78 | 79 | return HookResult.Continue; 80 | } 81 | } -------------------------------------------------------------------------------- /Store/src/cs2-store.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Core.Capabilities; 4 | using CS2MenuManager.API.Class; 5 | using Store.Extension; 6 | using StoreApi; 7 | using System.Reflection; 8 | using System.Text.Json; 9 | using static StoreApi.Store; 10 | 11 | namespace Store; 12 | 13 | public class Store : BasePlugin, IPluginConfig 14 | { 15 | public override string ModuleName => "Store"; 16 | public override string ModuleVersion => "v24"; 17 | public override string ModuleAuthor => "schwarper"; 18 | 19 | public Item_Config Config { get; set; } = new(); 20 | public List GlobalStorePlayers { get; set; } = []; 21 | public List GlobalStorePlayerItems { get; set; } = []; 22 | public List GlobalStorePlayerEquipments { get; set; } = []; 23 | public Dictionary GlobalDictionaryPlayer { get; set; } = []; 24 | public int GlobalTickrate { get; set; } = 0; 25 | public static Store Instance { get; set; } = new(); 26 | public Random Random { get; set; } = new(); 27 | public Dictionary GlobalGiftTimeout { get; set; } = []; 28 | public static StoreAPI Api { get; set; } = new(); 29 | public Dictionary> Items { get; set; } = []; 30 | public Dictionary InspectList { get; set; } = []; 31 | 32 | public override void Load(bool hotReload) 33 | { 34 | Capabilities.RegisterPluginCapability(IStoreApi.Capability, () => Api); 35 | Instance = this; 36 | 37 | Event.Load(); 38 | Command.Load(); 39 | 40 | if (hotReload) 41 | { 42 | List players = Utilities.GetPlayers(); 43 | foreach (CCSPlayerController player in players) 44 | { 45 | if (player.IsBot) 46 | continue; 47 | 48 | Database.LoadPlayer(player); 49 | MenuManager.CloseActiveMenu(player); 50 | } 51 | } 52 | } 53 | 54 | public override void Unload(bool hotReload) 55 | { 56 | Event.Unload(); 57 | Item_Tags.OnPluginEnd(); 58 | 59 | List players = Utilities.GetPlayers(); 60 | foreach (CCSPlayerController player in players) 61 | { 62 | if (player.IsBot) 63 | continue; 64 | 65 | MenuManager.CloseActiveMenu(player); 66 | } 67 | } 68 | 69 | public override void OnAllPluginsLoaded(bool hotReload) 70 | { 71 | ItemModuleManager.RegisterModules(Assembly.GetExecutingAssembly()); 72 | } 73 | 74 | public void OnConfigParsed(Item_Config config) 75 | { 76 | Config_Config.Load(); 77 | 78 | if (!config.Items.ValueKind.IsValueKindObject()) 79 | throw new JsonException(); 80 | 81 | Items = config.Items.ExtractItems(); 82 | Config = config; 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /Store/lang/zh-Hans.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}用户不匹配", 3 | "More than one client matched": "{white}没有匹配的用户", 4 | "Must be an integer": "{white}数量必须为整数", 5 | "Must be higher than zero": "{white}数量不能为0", 6 | "Must be a steamid": "{white}请输入有效的steamid", 7 | "No credits enough": "{white}积分余额不足", 8 | "You are not alive": "{white}死亡状态无法购买", 9 | "You are alive": "{white}只有死亡后才可购买", 10 | "No in pistol round": "{white}手枪局无法购买{green}{0}{white}", 11 | "No gift yourself": "{white}无法给自己赠送积分", 12 | "No type found": "{white}没有找到这个类型,请重新输入. {red}{0}", 13 | "Gift timeout": "{white}你需要等待{green}{0}秒{white}后才能赠送", 14 | "No purchase because team": "{white}您需要加入{red}{0}{white}阵营才能购买此皮肤!", 15 | "No equip because team": "{white}您需要加入{red}{0}{white}阵营才能装备此皮肤!", 16 | "You need correct weapon": "{white}你需要拿着{red}{0}{white}才能检视!", 17 | "Players' credits are refreshed": "{white}玩家积分已刷新!", 18 | 19 | "t team players": "{green}T阵营{white}玩家", 20 | "ct team players": "{green}CT阵营{white}玩家", 21 | "alive players": "{green}存活{white}玩家", 22 | "all players": "{green}所有{white}玩家", 23 | "dead players": "{green}死亡{white}玩家", 24 | "Console": "{white}控制台", 25 | 26 | "Purchase Succeeded": "{white}你购买了{green}{0}{white}", 27 | "Purchase Equip": "{white}你装备了{green}{0}{white}", 28 | "Purchase Unequip": "{white}你取消装备了{green}{0}{white}", 29 | "Item Sell": "{white}你{white}卖掉了{green}{0}{white}", 30 | "Godmode expired": "{white}你的无敌模式已到期", 31 | "Speed expired": "{white}你的加速模式已到期", 32 | "Hidetrails off": "{white}轨迹显示{green}已开启{white}!", 33 | "Hidetrails on": "{white}轨迹显示{red}已关闭{white}!", 34 | 35 | "menu_store": "商店【 积分余额: {0} 】", 36 | 37 | "menu_store<all_title>": "通用模型", 38 | "menu_store<t_title>": "T阵营模型", 39 | "menu_store<ct_title>": "CT阵营模型", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "装备", 43 | "menu_store<unequip>": "取消装备", 44 | "menu_store<sell>": "出售 [{0}]", 45 | "menu_store<confirm_title>": "确认购买吗?", 46 | "menu_store<yes>": "是", 47 | "menu_store<no>": "否", 48 | "menu_store<confirm_item>": "{0} - {1} 积分", 49 | "menu_store<inspect>": "检视", 50 | 51 | "css_credits": "{white}积分余额: {green}{0} {white}", 52 | "css_givecredits<player>": "{blue}{0}{white}给了{green}{2}积分{white}到{green}{1}{white}的账户里", 53 | "css_givecredits<steamid>": "{blue}{0}{white}给了{green}{2}积分{white}到{green}{1}{white}的账户里", 54 | "css_givecredits<multiple>": "{blue}{0}{white}给了{green}{2}积分{white}到{green}{1}{white}的账户里", 55 | 56 | "css_gift<player>": "{white}你赠送了{green}{1}{white}积分给{blue}{0}{white}", 57 | "css_gift<target>": "{blue}{0}{white}赠送了{green}{1}{white}积分给你", 58 | 59 | "css_reset": "{blue}{0}{white}重置了{green}{1}{white}的商店数据", 60 | 61 | "credits_earned<active>": "{white}活跃奖励,{gold}积分{white}+{green}{0}{white}", 62 | "credits_earned<inactive>": "{white}非活跃奖励,{gold}积分{white}+{green}{0}{white}", 63 | "credits_earned<kill>": "{white}击杀玩家,{gold}积分{white}+{green}{0}{white}", 64 | 65 | "css_model0": "{blue}{0}{white}开启了强制默认模型", 66 | "css_model1": "{blue}{0}{white}关闭了强制默认模型", 67 | 68 | "FreePlayerSkin": "免费玩家皮肤", 69 | "CT": "反恐精英", 70 | "Fernandez Frogman [CT]": "费尔南德斯蛙人 [CT]" 71 | } -------------------------------------------------------------------------------- /Store/src/item/items/grenadetrail.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | using static Store.Store; 5 | using static StoreApi.Store; 6 | 7 | namespace Store; 8 | 9 | [StoreItemType("grenadetrail")] 10 | public class Item_GrenadeTrail : IItemModule 11 | { 12 | public bool Equipable => true; 13 | public bool? RequiresAlive => null; 14 | 15 | public static Dictionary<CBaseCSGrenadeProjectile, CParticleSystem> GlobalGrenadeTrail { get; set; } = []; 16 | private static bool _grenadeTrailExists = false; 17 | 18 | public void OnPluginStart() 19 | { 20 | _grenadeTrailExists = Item.IsAnyItemExistInType("grenadetrail"); 21 | } 22 | 23 | public void OnMapStart() 24 | { 25 | GlobalGrenadeTrail.Clear(); 26 | } 27 | 28 | public void OnServerPrecacheResources(ResourceManifest manifest) 29 | { 30 | List<KeyValuePair<string, Dictionary<string, string>>> items = Item.GetItemsByType("grenadetrail"); 31 | 32 | foreach (KeyValuePair<string, Dictionary<string, string>> item in items) 33 | { 34 | manifest.AddResource(item.Value["model"]); 35 | } 36 | } 37 | 38 | public bool OnEquip(CCSPlayerController player, Dictionary<string, string> item) 39 | { 40 | return true; 41 | } 42 | 43 | public bool OnUnequip(CCSPlayerController player, Dictionary<string, string> item, bool update) 44 | { 45 | return true; 46 | } 47 | 48 | public static void OnEntityCreated(CEntityInstance entity) 49 | { 50 | if (!_grenadeTrailExists || !entity.DesignerName.EndsWith("_projectile")) return; 51 | 52 | CBaseCSGrenadeProjectile grenade = new(entity.Handle); 53 | if (grenade.Handle == IntPtr.Zero) return; 54 | 55 | Server.NextFrame(() => 56 | { 57 | CBasePlayerController? player = grenade.Thrower.Value?.Controller.Value; 58 | if (player == null) return; 59 | 60 | Store_Equipment? item = Instance.GlobalStorePlayerEquipments.FirstOrDefault(p => p.SteamID == player.SteamID && p.Type == "grenadetrail"); 61 | if (item == null) return; 62 | 63 | CParticleSystem? particle = Utilities.CreateEntityByName<CParticleSystem>("info_particle_system"); 64 | if (particle == null || !particle.IsValid) return; 65 | 66 | Dictionary<string, string>? itemData = Item.GetItem(item.UniqueId); 67 | if (itemData == null) return; 68 | 69 | string acceptInputValue = itemData.TryGetValue("acceptInputValue", out string? value) && !string.IsNullOrEmpty(value) ? value : "Start"; 70 | 71 | particle.EffectName = itemData["model"]; 72 | particle.StartActive = true; 73 | particle.Teleport(grenade.AbsOrigin); 74 | particle.DispatchSpawn(); 75 | particle.AcceptInput("FollowEntity", grenade, particle, "!activator"); 76 | particle.AcceptInput(acceptInputValue); 77 | 78 | GlobalGrenadeTrail[grenade] = particle; 79 | }); 80 | } 81 | } -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build & Publish cs2-store 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - 'README.md' 9 | - '.github/workflows/**' 10 | - 'config-example.toml' 11 | - 'cs2-store-example.json' 12 | 13 | jobs: 14 | setup: 15 | permissions: 16 | contents: write 17 | runs-on: ubuntu-latest 18 | outputs: 19 | buildnumber: ${{ steps.buildnumber.outputs.build_number }} 20 | steps: 21 | - name: Generate build number 22 | id: buildnumber 23 | uses: onyxmueller/build-tag-number@v1 24 | with: 25 | token: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | build: 28 | needs: setup 29 | runs-on: ubuntu-latest 30 | permissions: 31 | contents: write 32 | steps: 33 | - name: Prepare Environment Variables 34 | shell: bash 35 | run: | 36 | echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV 37 | echo "BUILD_NUMBER=${{ needs.setup.outputs.buildnumber }}" >> $GITHUB_ENV 38 | 39 | - name: Checkout Repository 40 | uses: actions/checkout@v3 41 | 42 | - name: Setup .NET 43 | uses: actions/setup-dotnet@v3 44 | with: 45 | dotnet-version: '8.0.x' 46 | 47 | - name: Restore Dependencies 48 | run: dotnet restore 49 | 50 | - name: Build 51 | run: | 52 | dotnet build cs2-store.sln -c Release --no-restore /p:Version=${{ env.BUILD_NUMBER }} 53 | 54 | - name: Create Release Artifact (ZIP) from BuildOutput 55 | run: | 56 | mkdir -p release 57 | cd BuildOutput 58 | zip -r ../cs2-store-v${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip * --exclude '*.nupkg' '*.xml' 59 | 60 | - name: Create GitHub Release 61 | id: create_release 62 | uses: actions/create-release@v1 63 | env: 64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 65 | with: 66 | tag_name: v${{ env.BUILD_NUMBER }} 67 | release_name: v${{ env.BUILD_NUMBER }} 68 | draft: false 69 | prerelease: false 70 | body: | 71 | ## Release Notes for v${{ env.BUILD_NUMBER }} 72 | 73 | --- 74 | ### Changes: 75 | - ${{ github.event.pull_request.title || github.event.head_commit.message }} 76 | 77 | --- 78 | ### Feedback: 79 | If you encounter any issues, please report them [here](https://github.com/${{ github.repository }}/issues). 80 | 81 | --- 82 | ### Support: 83 | If you'd like to support the continued development of this project, you can do so by [buying me a coffee](https://buymeacoffee.com/schwarper). Your support is genuinely appreciated. 84 | 85 | - name: Upload Release Asset 86 | uses: actions/upload-release-asset@v1 87 | env: 88 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 89 | with: 90 | upload_url: ${{ steps.create_release.outputs.upload_url }} 91 | asset_path: ./cs2-store-v${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip 92 | asset_name: cs2-store-v${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip 93 | asset_content_type: application/zip 94 | -------------------------------------------------------------------------------- /Store/src/menu/menubase.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Core.Translations; 3 | using CounterStrikeSharp.API.Modules.Admin; 4 | using CS2MenuManager.API.Class; 5 | using CS2MenuManager.API.Enum; 6 | using CS2MenuManager.API.Interface; 7 | using System.Text.Json; 8 | using static Store.Config_Config; 9 | using static Store.Store; 10 | using static StoreApi.Store; 11 | 12 | namespace Store; 13 | 14 | public static class MenuBase 15 | { 16 | public static void DisplayStoreMenu(CCSPlayerController? player, bool inventory) 17 | { 18 | if (player == null) 19 | return; 20 | 21 | Menu.DisplayStore(player, inventory); 22 | } 23 | 24 | public static int GetSellingPrice(Dictionary<string, string> item, Store_Item playerItem) 25 | { 26 | float sellRatio = Config.Settings.SellRatio; 27 | bool usePurchaseCredit = Config.Settings.SellUsePurchaseCredit; 28 | 29 | int purchasePrice = usePurchaseCredit && playerItem != null ? playerItem.Price : int.Parse(item["price"]); 30 | return (int)(purchasePrice * sellRatio); 31 | } 32 | 33 | public static bool CheckFlag(CCSPlayerController player, Dictionary<string, string> item, bool sell = false) 34 | { 35 | item.TryGetValue("flag", out string? flag); 36 | return CheckFlag(player, flag, !sell); 37 | } 38 | 39 | public static bool CheckFlag(CCSPlayerController player, string? flagAll, bool trueIfNull) 40 | { 41 | return string.IsNullOrEmpty(flagAll) 42 | ? trueIfNull 43 | : flagAll.Split(',') 44 | .Any(flag => (flag.StartsWith('@') && AdminManager.PlayerHasPermissions(player, flag)) || 45 | (flag.StartsWith('#') && AdminManager.PlayerInGroup(player, flag)) || 46 | (flag == player.SteamID.ToString())); 47 | } 48 | 49 | public static string GetCategoryName(CCSPlayerController player, JsonProperty category) 50 | { 51 | return Instance.Localizer.ForPlayer(player, category.Name); 52 | } 53 | 54 | public static void InspectAction(CCSPlayerController player, Dictionary<string, string> item, string type) 55 | { 56 | switch (type) 57 | { 58 | case "playerskin": 59 | item.TryGetValue("skin", out string? skn); 60 | Item_PlayerSkin.Inspect(player, item["model"], skn); 61 | break; 62 | /* 63 | case "customweapon": 64 | Item_CustomWeapon.Inspect(player, item["viewmodel"], item["weapon"]); 65 | break; 66 | */ 67 | } 68 | } 69 | 70 | public static void AddMenuOption(this IMenu menu, CCSPlayerController player, DisableOption disableOption, string display, params object[] args) 71 | { 72 | menu.AddItem(Instance.Localizer.ForPlayer(player, display, args), disableOption); 73 | } 74 | 75 | public static void AddMenuOption(this IMenu menu, CCSPlayerController player, Action<CCSPlayerController, ItemOption> callback, string display, params object[] args) 76 | { 77 | menu.AddItem(Instance.Localizer.ForPlayer(player, display, args), callback); 78 | } 79 | 80 | public static void AddMenuOption(this IMenu menu, CCSPlayerController player, Action<CCSPlayerController, ItemOption> callback, DisableOption disableOption, string display, params object[] args) 81 | { 82 | menu.AddItem(Instance.Localizer.ForPlayer(player, display, args), callback, disableOption); 83 | } 84 | 85 | public static BaseMenu CreateMenuByType(string title) 86 | { 87 | return MenuManager.MenuByType(Config.Menu.MenuType, title, Instance); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Store/lang/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}There is no matching client", 3 | "More than one client matched": "{white}There are more than one client matched", 4 | "Must be an integer": "{white}The value you entered must be an integer", 5 | "Must be higher than zero": "{white}The value you entered must be higher than zero.", 6 | "Must be a steamid": "{white}The value you entered must be a valid steamid", 7 | "No credits enough": "{white}You do not have enough credits.", 8 | "You are not alive": "{white}You can buy it only when you are alive.", 9 | "You are alive": "{white}You can buy it only when you are dead.", 10 | "No in pistol round": "{white}You cannot buy this item {green}{0} {white} in pistol round.", 11 | "No gift yourself": "{white}You cannot gift credits to yourself.", 12 | "No type found": "{white}No type found. {red}{0}", 13 | "Gift timeout": "{white}You need to wait {green}{0} seconds {white}to gift.", 14 | "No purchase because team": "{white}You cannot purchase this item. You need to be in {red}{0} {white}team.", 15 | "No equip because team": "{white}You cannot equip this item. You need to be in {red}{0} {white}team.", 16 | "You need correct weapon": "{white}You need {red}{0} {white}to inspect.", 17 | "Players' credits are refreshed": "Players' credits are refreshed.", 18 | 19 | "t team players": "{green}t team {white}players", 20 | "ct team players": "{green}ct team {white}players", 21 | "alive players": "{green}alive {white}players", 22 | "all players": "{green}all {white}players", 23 | "dead players": "{green}dead {white}players", 24 | "Console": "Console", 25 | 26 | "Purchase Succeeded": "{white}You {white}bought {green}{0}{white}.", 27 | "Purchase Equip": "{white}You {white}equipped {green}{0}{white}.", 28 | "Purchase Unequip": "{white}You {white}unequipped {green}{0}{white}.", 29 | "Item Sell": "{white}You {white}sold {green}{0}{white}.", 30 | "Godmode expired": "{white}Your godmode time is expired.", 31 | "Speed expired": "{white}Your speed time is expired.", 32 | "Hidetrails off": "{white}You can see trails now.", 33 | "Hidetrails on": "{white}You cannot see trails now.", 34 | 35 | "menu_store<title>": "Store [Your credits: {0}]", 36 | 37 | "menu_store<all_title>": "Models in common", 38 | "menu_store<t_title>": "T Models", 39 | "menu_store<ct_title>": "CT Models", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "EQUIP", 43 | "menu_store<unequip>": "UNEQUIP", 44 | "menu_store<sell>": "SELL [{0}]", 45 | "menu_store<confirm_title>": "Buying?", 46 | "menu_store<yes>": "Yes", 47 | "menu_store<no>": "No", 48 | "menu_store<confirm_item>": "{0} - {1} credits", 49 | "menu_store<inspect>": "Inspect", 50 | 51 | "css_credits": "{white}You have {green}{0} {white}credits.", 52 | "css_givecredits<player>": "{blue}{0} {white}gave {green}{2} credits {white}to {green}{1}{white}.", 53 | "css_givecredits<steamid>": "{blue}{0} {white}gave {green}{2} credits {white}to {green}{1}{white}.", 54 | "css_givecredits<multiple>": "{blue}{0} {white}gave {green}{2} credits {white}to {green}{1}{white}.", 55 | 56 | "css_gift<player>": "{white}You have sent {green}{1}{white}credits to {blue}{0}{white}.", 57 | "css_gift<target>": "{blue}{0} {white}sent you {green}{1} {white}credits.", 58 | 59 | "css_reset": "{blue}{0}{white} resetted {green}{1}{white}'s store datas.", 60 | 61 | "credits_earned<active>": "{white}You earned {green}{0} credits {white}for being active on the server.", 62 | "credits_earned<inactive>": "{white}You earned {green}{0} credits {white}for being inactive on the server.", 63 | "credits_earned<kill>": "{white}You earned {green}{0} credits {white}for killing a player.", 64 | 65 | "css_model0": "{blue}{0}{white} turned on the default forcing of player models.", 66 | "css_model1": "{blue}{0}{white} turned off the default forcing of player models.", 67 | 68 | "FreePlayerSkin": "Free Player Skin", 69 | "CT": "CT Skins", 70 | "Fernandez Frogman [CT]": "*Fernandez Frogman [CT]*" 71 | } -------------------------------------------------------------------------------- /Store/lang/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}Eşleşen alıcı bulunamadı.", 3 | "More than one client matched": "{white}Verilen biçim düzeniyle birden fazla alıcı eşleşti.", 4 | "Must be an integer": "{white}Girdiğiniz değer bir sayı olmalıdır.", 5 | "Must be higher than zero": "{white}Girdiğiniz değer sıfırdan büyük olmalıdır.", 6 | "Must be a steamid": "{white}Girdiğiniz değer steamid olmalıdır.", 7 | "No credits enough": "{white}Yeterli krediniz bulunmamaktadır.", 8 | "You are not alive": "{white}Sadece yaşarken alabilirsiniz.", 9 | "You are alive": "{white}Sadece ölüyken alabilirsiniz.", 10 | "No in pistol round": "{white}Bu ürünü {green}{0} {white}tabanca turunda alamazsınız.", 11 | "No gift yourself": "{white}Kendine kredi hediye edemezsin.", 12 | "No type found": "{white}Böyle bir type bulunamadı. {red}{0}", 13 | "Gift timeout": "{white}Kredi hediye etmek için {green}{0} saniye {white}beklemelisin.", 14 | "No purchase because team": "{white}Bu ürünü satın alamazsınız. {red}{0} {white}takımında olmanız gerekiyor.", 15 | "No equip because team": "{white}Bu ürünü kuşanamazsınız. {red}{0} {white}takımında olmanız gerekiyor.", 16 | "You need correct weapon": "{white}İncelemek için {red}{0} {white}gerekli.", 17 | "Players' credits are refreshed": "Oyuncuların kredileri yenilendi.", 18 | 19 | "t team players": "{green}t takımı {white}oyuncularını", 20 | "ct team players": "{green}ct takımı {white}oyuncularını", 21 | "alive players": "{green}yaşayan {white}oyuncuları", 22 | "all players": "{green}bütün {white}oyuncuları", 23 | "dead players": "{green}ölü {white}oyuncuları", 24 | "Console": "PANEL", 25 | 26 | "Purchase Succeeded": "{green}{0} {white}satın aldın.", 27 | "Purchase Equip": "{green}{0} {white}kuşandın.", 28 | "Purchase Unequip": "{green}{0} {white}bıraktın.", 29 | "Item Sell": "{green}{0} {white}sattın.", 30 | "Godmode expired": "{white}Godmode süreniz bitti.", 31 | "Speed expired": "{white}Hızlı koşma süreniz bitti.", 32 | "Hidetrails off": "{white}Artık izleri görebilirsiniz.", 33 | "Hidetrails on": "{white}Artık izleri göremezsiniz.", 34 | 35 | "menu_store<title>": "Market [Krediniz: {0}]", 36 | 37 | "menu_store<all_title>": "Ortak Modeller", 38 | "menu_store<t_title>": "T Modelleri", 39 | "menu_store<ct_title>": "CT Modelleri", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "KUŞAN", 43 | "menu_store<unequip>": "BIRAK", 44 | "menu_store<sell>": "SAT [{0}]", 45 | "menu_store<confirm_title>": "Satın alıyor musun?", 46 | "menu_store<yes>": "Evet", 47 | "menu_store<no>": "Hayır", 48 | "menu_store<confirm_item>": "{0} - {1} kredi", 49 | "menu_store<inspect>": "İncele", 50 | 51 | "css_credits": "{green}{0} {white}kredin bulunmaktadır.", 52 | "css_givecredits<player>": "{blue}{0}{white}, {green}{1} {white}adlı oyuncuya {green}{2} kredi {white}verdi.", 53 | "css_givecredits<steamid>": "{blue}{0}{white}, {green}{1} {white}steamidye {green}{2} kredi {white}verdi.", 54 | "css_givecredits<multiple>": "{blue}{0}{white}, {green}{1} {green}{2} kredi {white}verdi.", 55 | 56 | "css_gift<player>": "{blue}{0}{white} adlı kişiye {green}{1} {white}kredi yolladınız.", 57 | "css_gift<target>": "{blue}{0}{white}, size {green}{1} {white}kredi yolladı.", 58 | 59 | "css_reset": "{blue}{0}{white}, {green}{1} {white}adlı oyuncunun marketini sıfırladı", 60 | 61 | "credits_earned<active>": "{white}Sunucuda aktif vakit geçirdiğiniz için {green}{0} kredi {white}kazandınız.", 62 | "credits_earned<inactive>": "{white}Sunucuda pasif vakit geçirdiğiniz için {green}{0} kredi {white}kazandınız.", 63 | "credits_earned<kill>": "{white}Oyuncu öldürdüğünüz için {green}{0} {white}kredi kazandınız.", 64 | 65 | "css_model0": "{blue}{0}{white}, oyuncu modellerinin varsayılan zorunluluğunu açtı.", 66 | "css_model1": "{blue}{0}{white}, oyuncu modellerinin varsayılan zorunluluğunu kapattı.", 67 | 68 | "FreePlayerSkin": "Ücretsiz Oyuncu Modeli", 69 | "CT": "CT Modelleri", 70 | "Fernandez Frogman [CT]": "Fernandez Frogman [CT]" 71 | } -------------------------------------------------------------------------------- /Store/lang/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}Nie znaleziono pasującego klienta", 3 | "More than one client matched": "{white}Znaleziono więcej niż jeden pasujący klient", 4 | "Must be an integer": "{white}Wartość, którą wpisałeś, musi być liczbą całkowitą", 5 | "Must be higher than zero": "{white}Wartość, którą wpisałeś, musi być większa od zera.", 6 | "Must be a steamid": "{white}Wartość, którą wpisałeś, musi być prawidłowym steamid", 7 | "No credits enough": "{white}Nie masz wystarczającej liczby kredytów.", 8 | "You are not alive": "{white}Możesz to kupić tylko, gdy jesteś żywy.", 9 | "You are alive": "{white}Możesz to kupić tylko, gdy jesteś martwy.", 10 | "No in pistol round": "{white}Nie możesz kupić tego przedmiotu {green}{0} {white}w rundzie pistoletowej.", 11 | "No gift yourself": "{white}Nie możesz podarować kredytów sobie.", 12 | "No type found": "{white}Nie znaleziono typu. {red}{0}", 13 | "Gift timeout": "{white}Musisz poczekać {green}{0} sekund {white}na możliwość podarowania.", 14 | "No purchase because team": "{white}Nie możesz kupić tego przedmiotu. Musisz być w drużynie {red}{0} {white}.", 15 | "No equip because team": "{white}Nie możesz wyposażyć się w ten przedmiot. Musisz być w drużynie {red}{0} {white}.", 16 | "You need correct weapon": "{white}Potrzebujesz {red}{0} {white}, aby sprawdzić.", 17 | "Players' credits are refreshed": "Kredyty graczy zostały odświeżone.", 18 | 19 | "t team players": "{green}gracze drużyny t {white}", 20 | "ct team players": "{green}gracze drużyny ct {white}", 21 | "alive players": "{green}żywi gracze {white}", 22 | "all players": "{green}wszyscy gracze {white}", 23 | "dead players": "{green}martwi gracze {white}", 24 | "Console": "Konsola", 25 | 26 | "Purchase Succeeded": "{white}Zakupiłeś {green}{0}{white}.", 27 | "Purchase Equip": "{white}Wyposażyłeś {green}{0}{white}.", 28 | "Purchase Unequip": "{white}Zdjąłeś {green}{0}{white}.", 29 | "Item Sell": "{white}Sprzedałeś {green}{0}{white}.", 30 | "Godmode expired": "{white}Twój czas trybu boga wygasł.", 31 | "Speed expired": "{white}Twój czas szybkości wygasł.", 32 | "Hidetrails off": "{white}Teraz możesz widzieć ślady.", 33 | "Hidetrails on": "{white}Teraz nie możesz widzieć śladów.", 34 | 35 | "menu_store<title>": "Sklep [Twoje kredyty: {0}]", 36 | 37 | "menu_store<all_title>": "Modele ogólne", 38 | "menu_store<t_title>": "Modele T", 39 | "menu_store<ct_title>": "Modele CT", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "Wyposaż", 43 | "menu_store<unequip>": "Zdejmij", 44 | "menu_store<sell>": "Sprzedaj [{0}]", 45 | "menu_store<confirm_title>": "Kupujesz?", 46 | "menu_store<yes>": "Tak", 47 | "menu_store<no>": "Nie", 48 | "menu_store<confirm_item>": "{0} - {1} kredytów", 49 | "menu_store<inspect>": "Zbadaj", 50 | 51 | "css_credits": "{white}Masz {green}{0} {white}kredytów.", 52 | "css_givecredits<player>": "{blue}{0} {white}dał {green}{2} kredytów {white}graczowi {green}{1}{white}.", 53 | "css_givecredits<steamid>": "{blue}{0} {white}dał {green}{2} kredytów {white}graczowi {green}{1}{white}.", 54 | "css_givecredits<multiple>": "{blue}{0} {white}dał {green}{2} kredytów {white}graczom {green}{1}{white}.", 55 | 56 | "css_gift<player>": "{white}Wysłałeś {green}{1}{white} kredytów do {blue}{0}{white}.", 57 | "css_gift<target>": "{blue}{0} {white}wysłał Ci {green}{1} {white}kredytów.", 58 | 59 | "css_reset": "{blue}{0}{white} zresetował dane sklepu gracza {green}{1}{white}.", 60 | 61 | "credits_earned<active>": "{white}Zarobiłeś {green}{0} kredytów {white}za bycie aktywnym na serwerze.", 62 | "credits_earned<inactive>": "{white}Zarobiłeś {green}{0} kredytów {white}za bycie nieaktywnym na serwerze.", 63 | "credits_earned<kill>": "{white}Zarobiłeś {green}{0} kredytów {white}za zabicie gracza.", 64 | 65 | "css_model0": "{blue}{0}{white} włączył wymuszanie domyślnych modeli graczy.", 66 | "css_model1": "{blue}{0}{white} wyłączył wymuszanie domyślnych modeli graczy.", 67 | 68 | "FreePlayerSkin": "Darmowa skórka gracza", 69 | "CT": "Skórki CT", 70 | "Fernandez Frogman [CT]": "Fernandez Frogman [CT]" 71 | } 72 | -------------------------------------------------------------------------------- /Store/lang/pt-BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}Não há nenhum cliente correspondente", 3 | "More than one client matched": "{white>Há mais de um cliente correspondente", 4 | "Must be an integer": "{white}O valor inserido deve ser um número inteiro", 5 | "Must be higher than zero": "{white}O valor inserido deve ser maior que zero.", 6 | "Must be a steamid": "{white}O valor inserido deve ser um steamid válido", 7 | "No credits enough": "{white}Você não possui créditos suficientes.", 8 | "You are not alive": "{white}Você só pode comprar quando estiver vivo.", 9 | "You are alive": "{white}Você só pode comprar quando estiver morto.", 10 | "No in pistol round": "{white}Você não pode comprar este item {green}{0} {white} na rodada de pistola.", 11 | "No gift yourself": "{white}Você não pode presentear a si mesmo.", 12 | "No type found": "{white}Nenhum tipo encontrado. {red}{0}", 13 | "Gift timeout": "{white}Você precisa esperar {green}{0} segundos {white}para enviar o presente.", 14 | "No purchase because team": "{white}Você não pode comprar este item. Você precisa estar no time {red}{0} {white}.", 15 | "No equip because team": "{white}Você não pode equipar este item. Você precisa estar no time {red}{0} {white}.", 16 | "You need correct weapon": "{white}Você precisa de {red}{0} {white}para inspecionar.", 17 | "Players' credits are refreshed": "Os créditos dos jogadores foram atualizados.", 18 | 19 | "t team players": "{green}Jogadores de team t{white}", 20 | "ct team players": "{green}Jogadores de team ct{white}", 21 | "alive players": "{green}jogadores vivos{white}", 22 | "all players": "{green}todos os jogadores{white}", 23 | "dead players": "{green}jogadores mortos{white}", 24 | "Console": "Console", 25 | 26 | "Purchase Succeeded": "{white}Você comprou {green}{0}{white}.", 27 | "Purchase Equip": "{white}Você equipou {green}{0}{white}.", 28 | "Purchase Unequip": "{white}Você desequipou {green}{0}{white}.", 29 | "Item Sell": "{white}Você vendeu {green}{0}{white}.", 30 | "Godmode expired": "{white}Seu tempo de godmode expirou.", 31 | "Speed expired": "{white}Seu tempo de velocidade expirou.", 32 | "Hidetrails off": "{white}Agora você pode ver os rastros.", 33 | "Hidetrails on": "{white}Agora você não pode ver os rastros.", 34 | 35 | "menu_store<title>": "Loja [Seus créditos: {0}]", 36 | 37 | "menu_store<all_title>": "Modelos em comum", 38 | "menu_store<t_title>": "Modelos T", 39 | "menu_store<ct_title>": "Modelos CT", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "EQUIPAR", 43 | "menu_store<unequip>": "DESEQUIPAR", 44 | "menu_store<sell>": "VENDER [{0}]", 45 | "menu_store<confirm_title>": "Comprando?", 46 | "menu_store<yes>": "Sim", 47 | "menu_store<no>": "Não", 48 | "menu_store<confirm_item>": "{0} - {1} créditos", 49 | "menu_store<inspect>": "Inspecionar", 50 | 51 | "css_credits": "{white}Você possui {green}{0} {white}créditos.", 52 | "css_givecredits<player>": "{blue}{0} {white}deu {green}{2} créditos {white}para {green}{1}{white}.", 53 | "css_givecredits<steamid>": "{blue}{0} {white}deu {green}{2} créditos {white}para {green}{1}{white}.", 54 | "css_givecredits<multiple>": "{blue}{0} {white}deu {green}{2} créditos {white}para {green}{1}{white}.", 55 | 56 | "css_gift<player>": "{white}Você enviou {green}{1} {white}créditos para {blue}{0}{white}.", 57 | "css_gift<target>": "{blue}{0} {white}enviou {green}{1} {white}créditos para você.", 58 | 59 | "css_reset": "{blue}{0}{white} redefiniu os dados da loja de {green}{1}{white}.", 60 | 61 | "credits_earned<active>": "{white}Você ganhou {green}{0} créditos {white}por estar ativo no servidor.", 62 | "credits_earned<inactive>": "{white}Você ganhou {green}{0} créditos {white}por estar inativo no servidor.", 63 | "credits_earned<kill>": "{white}Você ganhou {green}{0} créditos {white}por matar um jogador.", 64 | 65 | "css_model0": "{blue}{0}{white} ativou o forçamento padrão dos modelos de jogadores", 66 | "css_model1": "{blue}{0}{white} desativou o forçamento padrão dos modelos de jogadores.", 67 | 68 | "FreePlayerSkin": "Skin de jogador grátis", 69 | "CT": "Skins CT", 70 | "Fernandez Frogman [CT]": "Fernandez Frogman [CT]" 71 | } -------------------------------------------------------------------------------- /Store/lang/sl.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}Trenutno ni ustrezne stranke.", 3 | "More than one client matched": "{white}Ujema se več kot ena stranka.", 4 | "Must be an integer": "{white}Vrednost, ki ste jo vnesli, mora biti celo število.", 5 | "Must be higher than zero": "{white}Vrednost, ki ste jo vnesli, mora biti večja od nič.", 6 | "Must be a steamid": "{white}Vrednost, ki ste jo vnesli, mora biti veljavni steamid.", 7 | "No credits enough": "{white}Nimate dovolj kreditov za nakup.", 8 | "You are not alive": "{white}Ta predmet lahko kupiš le, ko si živ.", 9 | "You are alive": "{white}Ta predmet lahko kupiš le, ko si mrtev.", 10 | "No in pistol round": "{white}Tento predmet nemôžete použiť {green}{0} {white}v pištoľnom kole.", 11 | "No gift yourself": "{white}Ne morete darovati kreditov samemu sebi.", 12 | "No type found": "{white}Samemu sebi ne morete podariti kreditov. {red}{0}", 13 | "Gift timeout": "{white}Počakati moraš {green}{0} sekund {white}preden lahko podariš darilo.", 14 | "No purchase because team": "{white}Te predmete ne morete kupiti. Morate biti v ekipi {red}{0} {white}.", 15 | "No equip because team": "{white}Te predmete ne morete opremiti. Morate biti v ekipi {red}{0} {white}.", 16 | "You need correct weapon": "{white}Potrebujete {red}{0} {white}za pregled.", 17 | "Players' credits are refreshed": "Krediti igralcev so bili osveženi.", 18 | 19 | "t team players": "{green}Zaporniki", 20 | "ct team players": "{green}Pazniki", 21 | "alive players": "{green}Živi {white}igralci", 22 | "all players": "{green}Vsi {white}igralci", 23 | "dead players": "{green}Mrtvi {white}igralci", 24 | "Console": "Konzola", 25 | 26 | "Purchase Succeeded": "{white}Kupil {white}si {green}{0}{white}.", 27 | "Purchase Equip": "{white}Opremljeni {white}ste z {green}{0}{white}.", 28 | "Purchase Unequip": "{white}Odstranil {white}si {green}{0}{white}.", 29 | "Item Sell": "{white}Prodal {white}si {green}{0}{white}.", 30 | "Godmode expired": "{white}Vaš čas boga načina je potekel.", 31 | "Speed expired": "{white}Vaš hitrostni čas je potekel.", 32 | "Hidetrails off": "{white}Zdaj lahko vidite sledi.", 33 | "Hidetrails on": "{white}Zdaj ne morete videti sledi.", 34 | 35 | "menu_store<title>": "Trgovina [Vaši krediti: {0}]", 36 | 37 | "menu_store<all_title>": "Skupni Modeli", 38 | "menu_store<t_title>": "T Modeli", 39 | "menu_store<ct_title>": "CT Modeli", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "AKTIVIRAJ", 43 | "menu_store<unequip>": "DEAKTIVIRAJ", 44 | "menu_store<sell>": "PRODAJ [{0}]", 45 | "menu_store<confirm_title>": "Nakup?", 46 | "menu_store<yes>": "Da", 47 | "menu_store<no>": "Ne", 48 | "menu_store<confirm_item>": "{0} - {1} krediti", 49 | "menu_store<inspect>": "Pregledati", 50 | 51 | "css_credits": "{white}Trenutno imaš {green}{0} {white}kreditov.", 52 | "css_givecredits<player>": "{blue}{0} {white}je dal {lightblue}{2} kredite {white}igralcu {green}{1}{white}.", 53 | "css_givecredits<steamid>": "{blue}{0} {white}je dal {lightblue}{2} kredite {white}igralcu {green}{1}{white}.", 54 | "css_givecredits<multiple>": "{blue}{0} {white}je dal {lightblue}{2} kredite {white} {green}{1}{white}.", 55 | 56 | "css_gift<player>": "{white}Poslal/a si {green}{1}{white}kredite igralcu {blue}{0}{white}.", 57 | "css_gift<target>": "{blue}{0} {white}Poslal/a je {green}{1} {white} stevilo kreditov.", 58 | 59 | "css_reset": "{blue}{0}{white} restartal bazo {green}{1}{white}'s trgovine.", 60 | 61 | "credits_earned<active>": "{white}Prislužil si {green}{0} kreditov {white}, zaradi igranja na strežniku.", 62 | "credits_earned<inactive>": "{white}Prislužil si {green}{0} kreditov {white}, zaradi neaktivnosti na strežniku.", 63 | "credits_earned<kill>": "{white}Dobil si {green}{0} kreditov {white}za uboj igralca.", 64 | 65 | "css_model0": "{blue}{0}{white} vklopil privzeto vsiljevanje modelov igralcev.", 66 | "css_model1": "{blue}{0}{white} izklopil privzeto vsiljevanje modelov igralcev.", 67 | 68 | "FreePlayerSkin": "Brezplačna skin igralca", 69 | "CT": "CT Skini", 70 | "Fernandez Frogman [CT]": "Fernandez Frogman [CT]" 71 | } -------------------------------------------------------------------------------- /Store/lang/ua.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}Не знайдено відповідного клієнта", 3 | "More than one client matched": "{white}Знайдено більше одного відповідного клієнта", 4 | "Must be an integer": "{white}Введене значення повинно бути цілим числом", 5 | "Must be higher than zero": "{white}Значення, яке ви ввели, має бути більше нуля.", 6 | "Must be a steamid": "{white}Значення, яке ви ввели, має бути дійсним паролем", 7 | "No credits enough": "{white}У вас недостатньо кредитів.", 8 | "You are not alive": "{white}Ви можете купити це лише тоді, коли ви живі.", 9 | "You are alive": "{white}Ви можете купити це лише тоді, коли ви мертві.", 10 | "No in pistol round": "{white}Ви не зможете купити цей предмет {green}{0} {white} у пістолетному раунді.", 11 | "No gift yourself": "{white}Ви не можете подарувати кредити самому собі.", 12 | "No type found": "{white}Тип не знайдено. {red}{0}", 13 | "Gift timeout": "{white}Вам потрібно зачекати {green}{0} секунд {white}щоб зробити подарунок.", 14 | "No purchase because team": "{white}Ви не можете придбати цей предмет. Ви повинні бути в команді {red}{0} {white}.", 15 | "No equip because team": "{white}Ви не можете екіпірувати цей предмет. Ви повинні бути в команді {red}{0} {white}.", 16 | "You need correct weapon": "{white}Вам потрібен {red}{0} {white}для огляду.", 17 | "Players' credits are refreshed": "Кредити гравців оновлено.", 18 | 19 | "t team players": "{green}Гравці {white}у команді t team", 20 | "ct team players": "{green}Гравці {white}у команді ct team", 21 | "alive players": "{green}Живі {white}гравці", 22 | "all players": "{green}Всі {white}гравці", 23 | "dead players": "{green}Мертві {white}гравці", 24 | "Console": "Консоль", 25 | 26 | "Purchase Succeeded": "{white}Ви {white}купили {green}{0}{white}.", 27 | "Purchase Equip": "{white}Ви {white}екіпіровали {green}{0}{white}.", 28 | "Purchase Unequip": "{white}Ви {white}зняли екіпіровку з {green}{0}{white}.", 29 | "Item Sell": "{white}Ви {white}продали {green}{0}{white}.", 30 | "Godmode expired": "{white}Час вашого богомоду закінчився.", 31 | "Speed expired": "{white}Час вашої швидкості закінчився.", 32 | "Hidetrails off": "{white}Тепер ви можете бачити сліди.", 33 | "Hidetrails on": "{white}Тепер ви не можете бачити сліди.", 34 | 35 | "menu_store<title>": "Магазин [Ваші кредити: {0}]", 36 | 37 | "menu_store<all_title>": "Загальні моделі", 38 | "menu_store<t_title>": "Моделі t", 39 | "menu_store<ct_title>": "Моделі ct", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "ЕКІПІРОВАТИ", 43 | "menu_store<unequip>": "ЗНЯТИ", 44 | "menu_store<sell>": "ПРОДАТИ [{0}]", 45 | "menu_store<confirm_title>": "Купуєш?", 46 | "menu_store<yes>": "Так", 47 | "menu_store<no>": "Ні", 48 | "menu_store<confirm_item>": "{0} - {1} креді", 49 | "menu_store<inspect>": "Перевірити", 50 | 51 | "css_credits": "{white}У вас {green}{0} {white}кредитів.", 52 | "css_givecredits<player>": "{blue}{0} {white}передав {green}{2} кредитів {white}{green}{1}{white}.", 53 | "css_givecredits<steamid>": "{blue}{0} {white}передав {green}{2} кредитів {white}{green}{1}{white}.", 54 | "css_givecredits<multiple>": "{blue}{0} {white}передали {green}{2} кредитів {white}гравцям: {green}{1}{white}.", 55 | 56 | "css_gift<player>": "{white}Ви відправили {green}{1} кредитів {white}гравцю {blue}{0}{white}.", 57 | "css_gift<target>": "{blue}{0} {white}передав вам {green}{1} кредитів{white}.", 58 | 59 | "css_reset": "{blue}{0}{white} скинув дані магазину для {green}{1}{white}.", 60 | 61 | "credits_earned<active>": "{white}Ви заробили {green}{0} кредитів {white}за активну присутність на сервері.", 62 | "credits_earned<inactive>": "{white}Ви заробили {green}{0} кредитів {white}за неактивну присутність на сервері.", 63 | "credits_earned<kill>": "{white}Ви заробили {green}{0} кредитів {white}за вбивство гравця.", 64 | 65 | "css_model0": "{blue}{0}{white} увімкнено форсування моделей гравців за замовчуванням.", 66 | "css_model1": "{blue}{0}{white} вимкнено вирівнювання моделей гравців за замовчуванням.", 67 | 68 | "FreePlayerSkin": "Безкоштовний скін гравця", 69 | "CT": "Скіни CT", 70 | "Fernandez Frogman [CT]": "Фернандес Frogman [CT]" 71 | } -------------------------------------------------------------------------------- /Store/lang/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}Не найдено совпадений с клиентом", 3 | "More than one client matched": "{white}Найдено более одного совпадения с клиентом", 4 | "Must be an integer": "{white}Введенное значение должно быть целым числом", 5 | "Must be higher than zero": "{white}Введенное вами значение должно быть больше нуля.", 6 | "Must be a steamid": "{white}Введенное вами значение должно быть действительным steamid", 7 | "No credits enough": "{white}У вас недостаточно кредитов.", 8 | "You are not alive": "{white}Вы можете купить это только когда вы живы.", 9 | "You are alive": "{white}Вы можете купить это только когда вы мертвы.", 10 | "No in pistol round": "{white}Вы не сможете купить этот предмет {green}{0} {white} в пистолетном раунде.", 11 | "No gift yourself": "{white}Вы не можете подарить кредиты сами себе.", 12 | "No type found": "{white}Тип не найден. {red}{0}", 13 | "Gift timeout": "{white}Вам нужно подождать {green}{0} секунд {white}перед тем, как отправить подарок.", 14 | "No purchase because team": "{white}Вы не можете купить этот предмет. Вы должны быть в команде {red}{0} {white}.", 15 | "No equip because team": "{white}Вы не можете экипировать этот предмет. Вы должны быть в команде {red}{0} {white}.", 16 | "You need correct weapon": "{white}Вам нужно {red}{0} {white}для осмотра.", 17 | "Players' credits are refreshed": "Кредиты игроков обновлены.", 18 | 19 | "t team players": "{green}Игроки {white}в команде t team", 20 | "ct team players": "{green}Игроки {white}в команде ct team", 21 | "alive players": "{green}Живые {white}игроки", 22 | "all players": "{green}Все {white}игроки", 23 | "dead players": "{green}Мертвые {white}игроки", 24 | "Console": "Консоль", 25 | 26 | "Purchase Succeeded": "{white}Вы {white}купили {green}{0}{white}.", 27 | "Purchase Equip": "{white}Вы {white}экипировали {green}{0}{white}.", 28 | "Purchase Unequip": "{white}Вы {white}сняли снаряжение с {green}{0}{white}.", 29 | "Item Sell": "{white}Вы {white}продали {green}{0}{white}.", 30 | "Godmode expired": "{white}Время вашего бессмертия истекло.", 31 | "Speed expired": "{white}Время вашей скорости истекло.", 32 | "Hidetrails off": "{white}Теперь вы можете видеть следы.", 33 | "Hidetrails on": "{white}Теперь вы не можете видеть следы.", 34 | 35 | "menu_store<title>": "Магазин [Ваши кредиты: {0}]", 36 | 37 | "menu_store<all_title>": "Общие модели", 38 | "menu_store<t_title>": "Модели t", 39 | "menu_store<ct_title>": "Модели ct", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "ЭКИПИРОВАТЬ", 43 | "menu_store<unequip>": "СНЯТЬ", 44 | "menu_store<sell>": "ПРОДАТЬ [{0}]", 45 | "menu_store<confirm_title>": "Покупка?", 46 | "menu_store<yes>": "Да", 47 | "menu_store<no>": "Нет", 48 | "menu_store<confirm_item>": "{0} - {1} креди", 49 | "menu_store<inspect>": "Проверить", 50 | 51 | "css_credits": "{white}У вас {green}{0} {white}кредитов.", 52 | "css_givecredits<player>": "{blue}{0} {white}передал {green}{2} кредитов {white}{green}{1}{white}.", 53 | "css_givecredits<steamid>": "{blue}{0} {white}передал {green}{2} кредитов {white}{green}{1}{white}.", 54 | "css_givecredits<multiple>": "{blue}{0} {white}передали {green}{2} кредитов {white}игрокам: {green}{1}{white}.", 55 | 56 | "css_gift<player>": "{white}Вы отправили {green}{1} кредитов {white}игроку {blue}{0}{white}.", 57 | "css_gift<target>": "{blue}{0} {white}передал вам {green}{1} кредитов{white}.", 58 | 59 | "css_reset": "{blue}{0}{white} сбросил данные магазина для {green}{1}{white}.", 60 | 61 | "credits_earned<active>": "{white}Вы заработали {green}{0} кредитов {white}за активное присутствие на сервере.", 62 | "credits_earned<inactive>": "{white}Вы заработали {green}{0} кредитов {white}за неактивное присутствие на сервере.", 63 | "credits_earned<kill>": "{white}Вы заработали {green}{0} кредитов {white}за убийство игрока.", 64 | 65 | "css_model0": "{blue}{0}{white} включена форсировка моделей игроков по умолчанию.", 66 | "css_model1": "{blue}{0}{white} выключил принудительное форсирование моделей игроков по умолчанию.", 67 | 68 | "FreePlayerSkin": "Бесплатный скин игрока", 69 | "CT": "Скины CT", 70 | "Fernandez Frogman [CT]": "Фернандес Лягушка [CT]" 71 | } -------------------------------------------------------------------------------- /Store/lang/ro.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}Nu există niciun client potrivit", 3 | "More than one client matched": "{white}Există mai mulți clienți care se potrivesc", 4 | "Must be an integer": "{white}Valoarea introdusă trebuie să fie un număr întreg", 5 | "Must be higher than zero": "{white}Valoarea introdusă trebuie să fie mai mare decât zero.", 6 | "Must be a steamid": "{white}Valoarea introdusă trebuie să fie un steamid valid", 7 | "No credits enough": "{white}Nu ai suficiente credite.", 8 | "You are not alive": "{white}Poți cumpăra acest lucru doar când ești în viață.", 9 | "You are alive": "{white}Poți cumpăra acest lucru doar când ești mort.", 10 | "No in pistol round": "{white}Nu poți cumpăra acest obiect {green}{0} {white}în runda de pistol.", 11 | "No gift yourself": "{white}Nu poți trimite credite către tine însuți.", 12 | "No type found": "{white}Nu a fost găsit niciun tip. {red}{0}", 13 | "Gift timeout": "{white}Trebuie să aștepți {green}{0} secunde {white}pentru a oferi cadoul.", 14 | "No purchase because team": "{white}Nu poți achiziționa acest articol. Trebuie să fii în echipa {red}{0} {white}.", 15 | "No equip because team": "{white}Nu poți echipa acest articol. Trebuie să fii în echipa {red}{0} {white}.", 16 | "You need correct weapon": "{white}Ai nevoie de {red}{0} {white}pentru a inspecta.", 17 | "Players' credits are refreshed": "Creditele jucătorilor au fost reîmprospătate.", 18 | 19 | "t team players": "{green}jucători echipa T {white}", 20 | "ct team players": "{green}jucători echipa CT {white}", 21 | "alive players": "{green}jucători în viață {white}", 22 | "all players": "{green}toți jucătorii {white}", 23 | "dead players": "{green}jucători morți {white}", 24 | "Console": "Consolă", 25 | 26 | "Purchase Succeeded": "{white}Ai {white}cumpărat {green}{0}{white}.", 27 | "Purchase Equip": "{white}Ai {white}echipat {green}{0}{white}.", 28 | "Purchase Unequip": "{white}Ai {white}dezechipat {green}{0}{white}.", 29 | "Item Sell": "{white}Ai {white}vândut {green}{0}{white}.", 30 | "Godmode expired": "{white}Timpul tău de godmode a expirat.", 31 | "Speed expired": "{white}Timpul tău de viteză a expirat.", 32 | "Hidetrails off": "{white}Acum poți vedea urmele.", 33 | "Hidetrails on": "{white}Acum nu mai poți vedea urmele.", 34 | 35 | "menu_store<title>": "Magazin [Creditele tale: {0}]", 36 | 37 | "menu_store<all_title>": "Modele în comun", 38 | "menu_store<t_title>": "Modele T", 39 | "menu_store<ct_title>": "Modele CT", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "ECHIPEAZĂ", 43 | "menu_store<unequip>": "DEZ-ECHIPEAZĂ", 44 | "menu_store<sell>": "VINDE [{0}]", 45 | "menu_store<confirm_title>": "Cumperi?", 46 | "menu_store<yes>": "Da", 47 | "menu_store<no>": "Nu", 48 | "menu_store<confirm_item>": "{0} - {1} credite", 49 | "menu_store<inspect>": "Inspecta", 50 | 51 | "css_credits": "{white}Ai {green}{0} {white}credite.", 52 | "css_givecredits<player>": "{blue}{0} {white}a dat {green}{2} credite {white}către {green}{1}{white}.", 53 | "css_givecredits<steamid>": "{blue}{0} {white}a dat {green}{2} credite {white}către {green}{1}{white}.", 54 | "css_givecredits<multiple>": "{blue}{0} {white}a dat {green}{2} credite {white}către {green}{1}{white}.", 55 | 56 | "css_gift<player>": "{white}Ai trimis {green}{1}{white}credite către {blue}{0}{white}.", 57 | "css_gift<target>": "{blue}{0} {white}ți-a trimis {green}{1} {white}credite.", 58 | 59 | "css_reset": "{blue}{0}{white} a resetat datele magazinului pentru {green}{1}{white}.", 60 | 61 | "credits_earned<active>": "{white}Ai câștigat {green}{0} credite {white}pentru că ai fost activ pe server.", 62 | "credits_earned<inactive>": "{white}Ai câștigat {green}{0} credite {white}pentru că ai fost inactiv pe server.", 63 | "credits_earned<kill>": "{white}Ai câștigat {green}{0} credite {white}pentru că ai omorât un jucător.", 64 | 65 | "css_model0": "{blue}{0}{white} a activat forțarea implicită a modelelor jucătorilor.", 66 | "css_model1": "{blue}{0}{white} a dezactivat forțarea implicită a modelelor jucătorilor.", 67 | 68 | "FreePlayerSkin": "Skin gratuit pentru jucător", 69 | "CT": "Skin-uri CT", 70 | "Fernandez Frogman [CT]": "Fernandez Frogman [CT]" 71 | } -------------------------------------------------------------------------------- /Store/src/Extension/PlayerExtensions.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Core.Translations; 4 | using CounterStrikeSharp.API.Modules.Timers; 5 | using CounterStrikeSharp.API.Modules.Utils; 6 | using System.Drawing; 7 | using static Store.Config_Config; 8 | using static Store.Store; 9 | 10 | namespace Store.Extension; 11 | 12 | public static class PlayerExtensions 13 | { 14 | public static void PrintToChatMessage(this CCSPlayerController player, string message, params object[] args) 15 | { 16 | player.PrintToChat($"{Config.Settings.Tag}{Instance.Localizer.ForPlayer(player, message, args)}"); 17 | } 18 | 19 | public static void ChangeModelDelay(this CCSPlayerController player, string model, bool disableLeg, int slotNumber, string? skin) 20 | { 21 | float applyDelay = Math.Max(Config.Settings.ApplyPlayerskinDelay, 0.1f); 22 | 23 | Instance.AddTimer(applyDelay, () => 24 | { 25 | if (!player.IsValid || !player.PawnIsAlive || (slotNumber != 1 && player.TeamNum != slotNumber)) 26 | { 27 | return; 28 | } 29 | 30 | if (Config.Settings.EnableCs2Fixes && player.TeamNum == (int)CsTeam.Terrorist) 31 | { 32 | return; 33 | } 34 | 35 | player.PlayerPawn.Value?.ChangeModel(model, disableLeg, skin); 36 | }, TimerFlags.STOP_ON_MAPCHANGE); 37 | } 38 | 39 | public static void ChangeModel(this CCSPlayerPawn pawn, string model, bool disableLeg, string? skin) 40 | { 41 | if (string.IsNullOrEmpty(model)) return; 42 | 43 | if (Config.Settings.EnableCs2Fixes && pawn.TeamNum == (int)CsTeam.Terrorist) 44 | { 45 | return; 46 | } 47 | 48 | Server.NextFrame(() => 49 | { 50 | pawn.SetModel(model); 51 | 52 | Color originalRender = pawn.Render; 53 | 54 | pawn.Render = disableLeg 55 | ? Color.FromArgb(254, originalRender.R, originalRender.G, originalRender.B) 56 | : Color.FromArgb(255, originalRender.R, originalRender.G, originalRender.B); 57 | 58 | if (!string.IsNullOrEmpty(skin)) 59 | { 60 | pawn.AcceptInput("Skin", null, pawn, skin); 61 | } 62 | }); 63 | } 64 | 65 | public static void ColorSkin(this CCSPlayerPawn pawn, Color color) 66 | { 67 | Color originalRender = pawn.Render; 68 | 69 | pawn.Render = Color.FromArgb(originalRender.A, color.R, color.G, color.B); 70 | pawn.RenderMode = RenderMode_t.kRenderTransColor; 71 | Utilities.SetStateChanged(pawn, "CBaseModelEntity", "m_clrRender"); 72 | } 73 | 74 | public static int GetHealth(this CCSPlayerPawn pawn) 75 | { 76 | return pawn.Health; 77 | } 78 | 79 | public static void SetHealth(this CCSPlayerController player, int health) 80 | { 81 | if (player.PlayerPawn?.Value is not { } pawn) return; 82 | 83 | player.Health = health; 84 | pawn.Health = health; 85 | 86 | if (health > 100) 87 | { 88 | player.MaxHealth = health; 89 | pawn.MaxHealth = health; 90 | } 91 | 92 | Utilities.SetStateChanged(pawn, "CBaseEntity", "m_iHealth"); 93 | } 94 | 95 | public static void GiveArmor(this CCSPlayerPawn playerPawn, int armor) 96 | { 97 | if (playerPawn.ItemServices != null) 98 | { 99 | new CCSPlayer_ItemServices(playerPawn.ItemServices.Handle).HasHelmet = true; 100 | } 101 | 102 | playerPawn.ArmorValue += armor; 103 | Utilities.SetStateChanged(playerPawn, "CCSPlayerPawn", "m_ArmorValue"); 104 | } 105 | 106 | public static void BunnyHop(this CCSPlayerPawn playerPawn, CCSPlayerController player) 107 | { 108 | PlayerFlags flags = (PlayerFlags)playerPawn.Flags; 109 | PlayerButtons buttons = player.Buttons; 110 | 111 | if (!buttons.HasFlag(PlayerButtons.Jump) || !flags.HasFlag(PlayerFlags.FL_ONGROUND) || playerPawn.MoveType.HasFlag(MoveType_t.MOVETYPE_LADDER)) 112 | { 113 | return; 114 | } 115 | 116 | playerPawn.AbsVelocity.Z = 267.0f; 117 | } 118 | } -------------------------------------------------------------------------------- /Store/lang/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "No matching client": "{white}Il n'y a pas de client correspondant", 3 | "More than one client matched": "{white}Il y a plus d'un client correspondant", 4 | "Must be an integer": "{white}La valeur que vous avez saisie doit être un entier", 5 | "Must be higher than zero": "{white}La valeur que vous avez saisie doit être supérieure à zéro.", 6 | "Must be a steamid": "{white}La valeur que vous avez saisie doit être un SteamID valide", 7 | "No credits enough": "{white}Vous n'avez pas assez de crédits.", 8 | "You are not alive": "{white}Vous ne pouvez l'acheter que lorsque vous êtes en vie.", 9 | "You are alive": "{white}Vous ne pouvez l'acheter que lorsque vous êtes mort.", 10 | "No in pistol round": "{white}Vous ne pouvez pas acheter cet article {green}{0} {white} au round pistolet.", 11 | "No gift yourself": "{white}ous ne pouvez pas vous offrir des crédits à vous-même.", 12 | "No type found": "{white}Aucun type trouvé. {red}{0}", 13 | "Gift timeout": "{white}Vous devez attendre {green}{0} secondes {white}pour faire un don.", 14 | "No purchase because team": "{white}Vous ne pouvez pas acheter cet objet. Vous devez être dans l'équipe {red}{0}.", 15 | "No equip because team": "{white}Vous ne pouvez pas équiper cet objet. Vous devez être dans l'équipe {red}{0}.", 16 | "You need correct weapon": "{white}Vous avez besoin de {red}{0} {white}pour inspecter.", 17 | "Players' credits are refreshed": "Les crédits des joueurs sont réinitialisés.", 18 | 19 | "t team players": "{green}Joueurs de l'équipe {white}T", 20 | "ct team players": "{green}Joueurs de l'équipe {white}CT", 21 | "alive players": "{green}Joueurs en {white}vie", 22 | "all players": "{green}Tous les {white}joueurs", 23 | "dead players": "{green}Joueurs {white}morts", 24 | "Console": "Console", 25 | 26 | "Purchase Succeeded": "{white}Vous avez {white}acheté {green}{0}{white}.", 27 | "Purchase Equip": "{white}Vous avez {white}équipé {green}{0}{white}.", 28 | "Purchase Unequip": "{white}Vous avez {white} retiré {green}{0}{white}.", 29 | "Item Sell": "{white}Vous avez {white}vendu {green}{0}{white}.", 30 | "Godmode expired": "{white}Votre temps d'invincibilité est expiré.", 31 | "Speed expired": "{white}Votre temps de vitesse est expiré.", 32 | "Hidetrails off": "{white}Vous pouvez voir les trails maintenant.", 33 | "Hidetrails on": "{white}Vous ne pouvez plus voir les trails maintenant.", 34 | 35 | "menu_store<title>": "Store [Vos crédits: {0}]", 36 | 37 | "menu_store<all_title>": "Modèles en commun", 38 | "menu_store<t_title>": "Modèles T", 39 | "menu_store<ct_title>": "Modèles CT", 40 | "menu_store<purchase>": "{0} - [{1}]", 41 | "menu_store<purchase1>": "{0}", 42 | "menu_store<equip>": "ÉQUIPER", 43 | "menu_store<unequip>": "RETIRER", 44 | "menu_store<sell>": "VENDRE [{0}]", 45 | "menu_store<confirm_title>": "Acheter ?", 46 | "menu_store<yes>": "Oui", 47 | "menu_store<no>": "Non,", 48 | "menu_store<confirm_item>": "{0} - {1} crédits", 49 | "menu_store<inspect>": "Inspecter", 50 | 51 | "css_credits": "{white}Vous avez {green}{0} {white}crédits.", 52 | "css_givecredits<player>": "{blue}{0} {white}a donné {green}{2} crédits {white}à {green}{1}{white}.", 53 | "css_givecredits<steamid>": "{blue}{0} {white}a donné {green}{2} crédits {white}à {green}{1}{white}.", 54 | "css_givecredits<multiple>": "{blue}{0} {white}a donné {green}{2} crédits {white}à {green}{1}{white}.", 55 | 56 | "css_gift<player>": "{white}Vous avez envoyé {green}{1}{white}crédits à {blue}{0}{white}.", 57 | "css_gift<target>": "{blue}{0} {white}vous a envoyé {green}{1} {white}crédits.", 58 | 59 | "css_reset": "{blue}{0}{white} à réinitialisé les données du store de {green}{1}{white}", 60 | 61 | "credits_earned<active>": "{white}Vous avez gagné {green}{0} crédits {white}pour avoir été actif sur le serveur.", 62 | "credits_earned<inactive>": "{white}Vous avez gagné {green}{0} crédits {white}pour avoir été inactif sur le serveur.", 63 | "credits_earned<kill>": "{white}Vous avez gagné {green}{0} crédits {white}pour avoir tué un joueur.", 64 | 65 | "css_model0": "{blue}{0}{white} a activé les modèles par default pour les joueurs.", 66 | "css_model1": "{blue}{0}{white} a désactivé les modèles par default pour les joueurs.", 67 | 68 | "FreePlayerSkin": "Skin de joueur gratuit", 69 | "CT": "Skins CT", 70 | "Fernandez Frogman [CT]": "Fernandez Frogman [CT]" 71 | } -------------------------------------------------------------------------------- /Store/src/api/api.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using StoreApi; 3 | using System.Reflection; 4 | using static StoreApi.Store; 5 | 6 | namespace Store; 7 | 8 | public class StoreAPI : IStoreApi 9 | { 10 | public event Action<CCSPlayerController, Dictionary<string, string>>? OnPlayerPurchaseItem; 11 | public event Action<CCSPlayerController, Dictionary<string, string>>? OnPlayerEquipItem; 12 | public event Action<CCSPlayerController, Dictionary<string, string>>? OnPlayerUnequipItem; 13 | public event Action<CCSPlayerController, Dictionary<string, string>>? OnPlayerSellItem; 14 | 15 | public void PlayerPurchaseItem(CCSPlayerController player, Dictionary<string, string> item) 16 | { 17 | OnPlayerPurchaseItem?.Invoke(player, item); 18 | } 19 | 20 | public void PlayerEquipItem(CCSPlayerController player, Dictionary<string, string> item) 21 | { 22 | OnPlayerEquipItem?.Invoke(player, item); 23 | } 24 | 25 | public void PlayerUnequipItem(CCSPlayerController player, Dictionary<string, string> item) 26 | { 27 | OnPlayerUnequipItem?.Invoke(player, item); 28 | } 29 | 30 | public void PlayerSellItem(CCSPlayerController player, Dictionary<string, string> item) 31 | { 32 | OnPlayerSellItem?.Invoke(player, item); 33 | } 34 | 35 | public string GetDatabaseString() 36 | { 37 | return Database.GlobalDatabaseConnectionString; 38 | } 39 | 40 | public int GetPlayerCredits(CCSPlayerController player) 41 | { 42 | return Credits.Get(player); 43 | } 44 | 45 | public int SetPlayerCredits(CCSPlayerController player, int credits) 46 | { 47 | return Credits.Set(player, credits); 48 | } 49 | 50 | public int GetPlayerOriginalCredits(CCSPlayerController player) 51 | { 52 | return Credits.GetOriginal(player); 53 | } 54 | 55 | public int SetPlayerOriginalCredits(CCSPlayerController player, int credits) 56 | { 57 | return Credits.SetOriginal(player, credits); 58 | } 59 | 60 | public int GivePlayerCredits(CCSPlayerController player, int credits) 61 | { 62 | return Credits.Give(player, credits); 63 | } 64 | 65 | public bool Item_Give(CCSPlayerController player, Dictionary<string, string> item) 66 | { 67 | return Item.Give(player, item); 68 | } 69 | 70 | public bool Item_Purchase(CCSPlayerController player, Dictionary<string, string> item) 71 | { 72 | return Item.Purchase(player, item); 73 | } 74 | 75 | public bool Item_Equip(CCSPlayerController player, Dictionary<string, string> item) 76 | { 77 | return Item.Equip(player, item); 78 | } 79 | 80 | public bool Item_Unequip(CCSPlayerController player, Dictionary<string, string> item, bool update) 81 | { 82 | return Item.Unequip(player, item, update); 83 | } 84 | 85 | public bool Item_Sell(CCSPlayerController player, Dictionary<string, string> item) 86 | { 87 | return Item.Sell(player, item); 88 | } 89 | 90 | public bool Item_PlayerHas(CCSPlayerController player, string type, string uniqueId, bool ignoreVip) 91 | { 92 | return Item.PlayerHas(player, type, uniqueId, ignoreVip); 93 | } 94 | 95 | public bool Item_PlayerUsing(CCSPlayerController player, string type, string uniqueId) 96 | { 97 | return Item.PlayerUsing(player, type, uniqueId); 98 | } 99 | 100 | public bool Item_IsInJson(string uniqueId) 101 | { 102 | return Item.IsInJson(uniqueId); 103 | } 104 | 105 | public bool IsPlayerVip(CCSPlayerController player) 106 | { 107 | return Item.IsPlayerVip(player); 108 | } 109 | 110 | public Dictionary<string, string>? GetItem(string uniqueId) 111 | { 112 | return Item.GetItem(uniqueId); 113 | } 114 | 115 | public List<KeyValuePair<string, Dictionary<string, string>>> GetItemsByType(string type) 116 | { 117 | return Item.GetItemsByType(type); 118 | } 119 | 120 | public List<Store_Item> GetPlayerItems(CCSPlayerController player, string? type) 121 | { 122 | return Item.GetPlayerItems(player, type); 123 | } 124 | 125 | public List<Store_Equipment> GetPlayerEquipments(CCSPlayerController player, string? type) 126 | { 127 | return Item.GetPlayerEquipments(player, type); 128 | } 129 | 130 | public void RegisterModules(Assembly assembly) 131 | { 132 | ItemModuleManager.RegisterModules(assembly); 133 | } 134 | } -------------------------------------------------------------------------------- /config-example.toml: -------------------------------------------------------------------------------- 1 | # ───────────────────────────── 2 | # Store Plugin Configuration 3 | # ───────────────────────────── 4 | 5 | [DatabaseConnection] 6 | # Hostname or IP address of the MySQL server 7 | Host = "" 8 | 9 | # MySQL server port (usually 3306) 10 | Port = 3306 11 | 12 | # Username for database authentication 13 | User = "" 14 | 15 | # Password for database authentication 16 | Pass = "" 17 | 18 | # Name of the database to be used 19 | Name = "" 20 | 21 | # Table used to store player data (credits etc.) 22 | StorePlayersName = "store_players" 23 | 24 | # Table used to store the store item data 25 | StoreItemsName = "store_items" 26 | 27 | # Table used to store which items players have equipped 28 | StoreEquipments = "store_equipments" 29 | 30 | # ───────────────────────────── 31 | 32 | [Commands] 33 | # Command aliases that can be used by players. You may add more aliases as needed. 34 | Credits = [ "credits", "tl" ] 35 | Store = [ "store", "shop", "market" ] 36 | Inventory = [ "inv", "inventory" ] 37 | GiveCredits = [ "givecredits" ] 38 | Gift = [ "gift" ] 39 | ResetPlayer = [ "resetplayer" ] 40 | ResetDatabase = [ "resetdatabase" ] 41 | RefreshPlayersCredits = [ "refreshcredits" ] 42 | HideTrails = [ "hidetrails" ] 43 | PlayerSkinsOff = [ "model0", "modeloff" ] 44 | PlayerSkinsOn = [ "model1", "modelon" ] 45 | 46 | # ───────────────────────────── 47 | 48 | [DefaultModels] 49 | # Default player models for each team. Leave empty if not used. 50 | Terrorist = [ "characters/models/tm_leet/tm_leet_variantj.vmdl" ] 51 | CounterTerrorist = [ "characters/models/ctm_fbi/ctm_fbi_variantb.vmdl" ] 52 | 53 | # If true, disables the legs of default models. 54 | DefaultModelDisableLeg = false 55 | 56 | # ───────────────────────────── 57 | 58 | # Credit earning rules for specific permission groups. 59 | # High-priority permission entries should be placed above lower ones. 60 | # Do NOT include 'Start', 'IgnoreWarmup', or 'IntervalActiveInActive' in any group other than "default". 61 | 62 | [Credits."@css/root"] 63 | AmountActive = 30 # Credits earned when active 64 | AmountInActive = 3 # Credits earned when inactive 65 | AmountKill = 3 # Credits earned per kill 66 | 67 | [Credits."@css/vip"] 68 | AmountActive = 20 # Credits earned when active 69 | AmountInActive = 2 # Credits earned when inactive 70 | AmountKill = 2 # Credits earned per kill 71 | 72 | [Credits."default"] 73 | # These fields are ONLY allowed in the "default" group 74 | Start = 0 # Starting credit balance for new players 75 | IgnoreWarmup = true # If true, disables credit earning during warmup 76 | IntervalActiveInActive = 60 # The interval (in seconds) at which players earn credits. 77 | AmountActive = 10 # Credits earned when active 78 | AmountInActive = 1 # Credits earned when inactive 79 | AmountKill = 1 # Credits earned per kill 80 | 81 | # ───────────────────────────── 82 | 83 | [Menu] 84 | # Enables the confirmation menu before finalizing a purchase 85 | EnableConfirmMenu = true 86 | 87 | # Type of menu interface to use 88 | # Supported values: ConsoleMenu, ChatMenu, CenterHtmlMenu, WasdMenu 89 | MenuType = "WasdMenu" 90 | 91 | # Users with this flag can equip items without paying 92 | # Leave empty to disable VIP privileges 93 | VipFlag = "@css/root" 94 | 95 | # Sound to play for positive 96 | MenuPressSoundYes = "" 97 | 98 | # Sound to play for negative 99 | MenuPressSoundNo = "" 100 | 101 | # If false, the menu will remain open until you close it. 102 | CloseMenuAfterSelect = false 103 | 104 | # ───────────────────────────── 105 | 106 | [Settings] 107 | # Message prefix for store plugin messages (supports color codes like {red}, {green}) 108 | Tag = "{red}[Store]" 109 | 110 | # Maximum health allowed via store items (0 = infinity) 111 | MaxHealth = 0 112 | 113 | # Maximum armor allowed via store items (0 = infinity) 114 | MaxArmor = 0 115 | 116 | # Ratio of credit received when selling an item (e.g., 0.6 = 60% of value) 117 | SellRatio = 0.6 118 | 119 | # Delay in seconds before a player skin is applied after selection 120 | ApplyPlayerskinDelay = 0.1 121 | 122 | # If true, selling returns credit based on the price the player paid 123 | # If false, selling returns credit based on the current store price 124 | SellUsePurchaseCredit = false 125 | 126 | # Enables compatibility adjustments for CS2 fixes 127 | EnableCs2Fixes = false 128 | 129 | # If true, all credit transactions will be logged into daily log files 130 | # If false, no logs will be saved 131 | EnableLog = false 132 | 133 | # ───────────────────────────── 134 | 135 | [Permissions] 136 | # Required flag to toggle player model (model0/model1) features 137 | Model0Model1Flag = "@css/root" 138 | 139 | # Required flag to access /givecredits command 140 | GiveCredits = "@css/root" 141 | -------------------------------------------------------------------------------- /Store/src/findtarget/findtarget.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Commands; 4 | using CounterStrikeSharp.API.Modules.Commands.Targeting; 5 | using CounterStrikeSharp.API.Modules.Entities; 6 | using static Store.Config_Config; 7 | using static Store.Store; 8 | using static StoreApi.Store; 9 | 10 | namespace Store; 11 | 12 | public static class FindTarget 13 | { 14 | public class TargetFind 15 | { 16 | public List<CCSPlayerController> Players = []; 17 | public Store_Player? StorePlayer; 18 | public string? TargetName; 19 | } 20 | 21 | public static TargetFind Find(CommandInfo command, bool singleTarget, bool allowSteamID) 22 | { 23 | TargetResult targetResult = command.GetArgTargetResult(1); 24 | if (targetResult.Players.Count == 0) 25 | { 26 | if (allowSteamID) 27 | { 28 | string arg = command.GetArg(1).Trim(); 29 | 30 | if (!SteamID.TryParse(arg, out SteamID? steamId) || steamId == null) 31 | { 32 | if (ulong.TryParse(arg, out ulong steamIdNum)) 33 | { 34 | steamId = new SteamID(steamIdNum); 35 | } 36 | } 37 | 38 | if (steamId != null) 39 | { 40 | Store_Player? playerdata = Instance.GlobalStorePlayers 41 | .SingleOrDefault(player => player.SteamID == steamId.SteamId64); 42 | 43 | if (playerdata == null) 44 | { 45 | playerdata = new Store_Player 46 | { 47 | SteamID = steamId.SteamId64, 48 | Credits = 0, 49 | PlayerName = steamId.SteamId64.ToString() 50 | }; 51 | Instance.GlobalStorePlayers.Add(playerdata); 52 | } 53 | 54 | string finalTargetName = (!string.IsNullOrEmpty(playerdata.PlayerName) && 55 | playerdata.PlayerName != steamId.SteamId64.ToString()) 56 | ? playerdata.PlayerName 57 | : steamId.SteamId64.ToString(); 58 | 59 | return new TargetFind() { StorePlayer = playerdata, TargetName = finalTargetName }; 60 | } 61 | } 62 | command.ReplyToCommand($"{Config.Settings.Tag}{Instance.Localizer["No matching client"]}"); 63 | return new TargetFind(); 64 | } 65 | else if (singleTarget && targetResult.Players.Count > 1) 66 | { 67 | command.ReplyToCommand($"{Config.Settings.Tag}{Instance.Localizer["More than one client matched"]}"); 68 | return new TargetFind(); 69 | } 70 | 71 | string targetName = targetResult.Players.Count == 1 72 | ? targetResult.Players[0].PlayerName 73 | : GetTargetGroupName(command.GetArg(1), targetResult); 74 | 75 | return new TargetFind() { Players = targetResult.Players, TargetName = targetName }; 76 | } 77 | 78 | public static CCSPlayerController? FindTargetFromWeapon(CBasePlayerWeapon weapon) 79 | { 80 | SteamID steamId = new(weapon.OriginalOwnerXuidLow); 81 | 82 | CCSPlayerController? player = steamId.IsValid() 83 | ? Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == steamId.SteamId64) ?? Utilities.GetPlayerFromSteamId(weapon.OriginalOwnerXuidLow) 84 | : Utilities.GetPlayerFromIndex((int)weapon.OwnerEntity.Index) ?? Utilities.GetPlayerFromIndex((int)weapon.As<CCSWeaponBaseGun>().OwnerEntity.Value!.Index); 85 | 86 | return !string.IsNullOrEmpty(player?.PlayerName) ? player : null; 87 | } 88 | 89 | private static string GetTargetGroupName(string targetArg, TargetResult targetResult) 90 | { 91 | return !Target.TargetTypeMap.TryGetValue(targetArg, out TargetType type) 92 | ? targetResult.Players.First().PlayerName 93 | : type switch 94 | { 95 | TargetType.GroupAll => Instance.Localizer["all"], 96 | TargetType.GroupBots => Instance.Localizer["bots"], 97 | TargetType.GroupHumans => Instance.Localizer["humans"], 98 | TargetType.GroupAlive => Instance.Localizer["alive"], 99 | TargetType.GroupDead => Instance.Localizer["dead"], 100 | TargetType.GroupNotMe => Instance.Localizer["notme"], 101 | TargetType.PlayerMe => targetResult.Players.First().PlayerName, 102 | TargetType.TeamCt => Instance.Localizer["ct"], 103 | TargetType.TeamT => Instance.Localizer["t"], 104 | TargetType.TeamSpec => Instance.Localizer["spec"], 105 | _ => targetResult.Players.First().PlayerName 106 | }; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cs2-store 2 | A store plugin designed to enhance your gameplay by providing a dynamic credit system that allows players to purchase essential items directly from the store. 3 | 4 | # 🔔 Notice 5 | Some companies modify this plugin, remove the original author name, and claim it as their own. This is unethical and against open-source principles. 6 | Please use the official version here and contribute via pull requests if you wish to help improve it. 7 | 8 | - [Installation](https://github.com/schwarper/cs2-store?tab=readme-ov-file#-installation) 9 | - [Installation (Video)](https://github.com/schwarper/cs2-store?tab=readme-ov-file#-installation-video) 10 | - [Modules](https://github.com/schwarper/cs2-store?tab=readme-ov-file#-modules) 11 | - [Api Example](https://github.com/schwarper/cs2-store?tab=readme-ov-file#%EF%B8%8F-api-example) 12 | - [Menu Style](https://github.com/schwarper/cs2-store?tab=readme-ov-file#-menu-style) 13 | --- 14 | 15 | ## 📦 Installation 16 | 17 | ### 1) Prerequisites 18 | - This plugin requires the following dependency: 19 | ➡ **[CS2MenuManager](https://github.com/schwarper/CS2MenuManager)** 20 | ```Make sure to install this dependency before proceeding.``` 21 | 22 | ### 2) Download the Plugin 23 | - Download the latest release from: 24 | **[https://github.com/schwarper/cs2-store/releases](https://github.com/schwarper/cs2-store/releases)** 25 | 26 | ### 3) Configure Plugin Settings 27 | After installation: 28 | - Rename the configuration files in: 29 | `addons/counterstrikesharp/configs/plugins/cs2-store/` 30 | to the following: 31 | - `cs2-store.json` → Define available store items here. 32 | - `config.toml` → Configure plugin and database settings. 33 | 34 | ### 4) Load/Reload the Plugin 35 | To activate: 36 | - Restart your server 37 | **OR** 38 | - Run these commands in the server console: 39 | ```css_plugins load cs2-store``` (Load the plugin) 40 | ```css_plugins reload Store``` (Reload after changes) 41 | 42 | #### 🎥 Installation Video 43 | Watch the step-by-step guide: 44 | [Installation Guide](https://files.catbox.moe/uzadjw.mp4) 45 | 46 | 47 | --- 48 | 49 | ## 🎲 Modules 50 | You can find the offical modules: 51 | [CS2 Store Modules](https://github.com/schwarper/cs2-store-modules) 52 | 53 | ## 🕸️ Api Example 54 | - Give player an item or credits 55 | ```csharp 56 | public class TestModule : BasePlugin 57 | { 58 | public override string ModuleName => "Test Module"; 59 | public override string ModuleVersion => "0.0.1"; 60 | 61 | private IStoreApi? _storeApi; 62 | 63 | public override void OnAllPluginsLoaded(bool hotReload) 64 | { 65 | _storeApi = IStoreApi.Capability.Get(); 66 | } 67 | 68 | public void GivePlayerCredits(CCSPlayerController player, int credits) 69 | { 70 | _storeApi?.GivePlayerCredits(player, credits); 71 | } 72 | 73 | public bool GivePlayerItem(CCSPlayerController player, string uniqueId) 74 | { 75 | // Checks if item is exist. 76 | if (_storeApi?.GetItem(uniqueId) is not { } item) 77 | return false; 78 | 79 | // Checks if player has already this item 80 | if (_storeApi.Item_PlayerHas(player, item["type"], uniqueId, ignoreVip: false)) 81 | return false; 82 | 83 | // Give item 84 | _storeApi.Item_Give(player, item); 85 | return true; 86 | } 87 | } 88 | ``` 89 | 90 | - Add module 91 | ```csharp 92 | //Module type 93 | [StoreItemType("test")] 94 | //We use IItemModule 95 | public class TestModule : BasePlugin, IItemModule 96 | { 97 | public override string ModuleName => "Test Module"; 98 | public override string ModuleVersion => "0.0.1"; 99 | 100 | // You can also use this way. 101 | // However, we won't use _storeApi anywhere for this example. 102 | //private IStoreApi? _storeApi; 103 | 104 | public override void OnAllPluginsLoaded(bool hotReload) 105 | { 106 | // You need to use assembly here. 107 | IStoreApi.Capability.Get()?.RegisterModules(Assembly.GetExecutingAssembly()); 108 | //_storeApi = IStoreApi.Capability.Get(); 109 | //_storeApi?.RegisterModules(Test.Assembly); 110 | } 111 | 112 | // ============================ 113 | // IItemModule dependencies 114 | // ============================ 115 | 116 | // Sets if item is equipable 117 | public bool Equipable => false; 118 | 119 | // Sets if player has to be alive/dead to purchase 120 | // True => alive only 121 | // False => dead only 122 | // Null => everyone can purchase 123 | public bool? RequiresAlive => null; 124 | 125 | // You can use this execute as OnAllPluginsLoaded. 126 | public void OnPluginStart() { Console.WriteLine($"Test OnPluginStart"); } 127 | public void OnMapStart() { } 128 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 129 | 130 | // If you set false, they cannot equip / unequip, if true, they can. 131 | public bool OnEquip(CCSPlayerController player, Dictionary<string, string> item) 132 | { 133 | return true; 134 | } 135 | public bool OnUnequip(CCSPlayerController player, Dictionary<string, string> item, bool update) 136 | { 137 | return true; 138 | } 139 | } 140 | ``` 141 | ## 🔖 Menu Style 142 | **CenterHtmlMenu** 143 | 144 | ![image](https://files.catbox.moe/gz8x5e.png) 145 | 146 | **ChatMenu** 147 | 148 | ![image](https://files.catbox.moe/85ix04.png) 149 | 150 | **ConsoleMenu** 151 | 152 | ![image](https://files.catbox.moe/m47qri.png) 153 | 154 | **WasdMenu** 155 | 156 | ![image](https://files.catbox.moe/kogxzp.png) 157 | -------------------------------------------------------------------------------- /Store/src/item/items/wings.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | using Store.Extension; 5 | using static Store.Store; 6 | using static StoreApi.Store; 7 | 8 | namespace Store; 9 | 10 | [StoreItemType("wings")] 11 | public class Item_Wings : IItemModule 12 | { 13 | public bool Equipable => true; 14 | public bool? RequiresAlive => null; 15 | 16 | private static readonly Dictionary<CCSPlayerController, Dictionary<int, CDynamicProp>> PlayerWingsEntities = []; 17 | 18 | public void OnPluginStart() 19 | { 20 | if (Item.IsAnyItemExistInType("wings")) 21 | { 22 | Instance.RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn); 23 | Instance.RegisterEventHandler<EventPlayerTeam>(OnPlayerTeam); 24 | Instance.RegisterEventHandler<EventPlayerDisconnect>(OnPlayerDisconnect); 25 | } 26 | } 27 | 28 | public void OnMapStart() 29 | { 30 | PlayerWingsEntities.Clear(); 31 | } 32 | 33 | public void OnServerPrecacheResources(ResourceManifest manifest) 34 | { 35 | var items = Item.GetItemsByType("wings"); 36 | foreach (var item in items) 37 | { 38 | if (item.Value.TryGetValue("model", out var model) && !string.IsNullOrEmpty(model)) 39 | manifest.AddResource(model); 40 | } 41 | } 42 | 43 | public bool OnEquip(CCSPlayerController player, Dictionary<string, string> item) 44 | { 45 | if (!item.TryGetValue("slot", out var slotStr) || !int.TryParse(slotStr, out var slot) || slot < 0) 46 | return false; 47 | var animation = item.TryGetValue("animation", out var anim) ? anim : string.Empty; 48 | EquipWings(player, item["model"], slot, animation); 49 | return true; 50 | } 51 | 52 | public bool OnUnequip(CCSPlayerController player, Dictionary<string, string> item, bool update) 53 | { 54 | if (!item.TryGetValue("slot", out var slotStr) || !int.TryParse(slotStr, out var slot)) 55 | return false; 56 | UnEquipWings(player, slot); 57 | return true; 58 | } 59 | 60 | public static void EquipWings(CCSPlayerController player, string model, int slot, string animation = "") 61 | { 62 | UnEquipWings(player, slot); 63 | Server.NextFrame(() => 64 | { 65 | var entity = CreateWings(player, model, animation); 66 | if (entity != null && entity.IsValid) 67 | { 68 | if (!PlayerWingsEntities.ContainsKey(player)) 69 | PlayerWingsEntities[player] = []; 70 | PlayerWingsEntities[player][slot] = entity; 71 | } 72 | }); 73 | } 74 | 75 | public static void UnEquipWings(CCSPlayerController player, int slot) 76 | { 77 | if (!PlayerWingsEntities.TryGetValue(player, out var value) || !value.ContainsKey(slot)) 78 | return; 79 | var entity = value[slot]; 80 | if (entity != null && entity.IsValid) 81 | entity.Remove(); 82 | value.Remove(slot); 83 | if (value.Count == 0) 84 | PlayerWingsEntities.Remove(player); 85 | } 86 | 87 | public static CDynamicProp? CreateWings(CCSPlayerController player, string model, string animation = "") 88 | { 89 | var pawn = player.PlayerPawn.Value; 90 | if (pawn == null) return null; 91 | var entity = Utilities.CreateEntityByName<CDynamicProp>("prop_dynamic_override"); 92 | if (entity == null) return null; 93 | entity.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags &= ~(uint)(1 << 2); 94 | entity.SetModel(model); 95 | entity.DispatchSpawn(); 96 | entity.AcceptInput("FollowEntity", pawn, pawn, "!activator"); 97 | if (!string.IsNullOrEmpty(animation)) 98 | { 99 | entity.AcceptInput("SetAnimation", value: animation); 100 | } 101 | var origin = pawn.AbsOrigin; 102 | if (origin != null) 103 | { 104 | var offset = new Vector(0, 0, 0); 105 | entity.Teleport(origin + offset, pawn.EyeAngles, pawn.AbsVelocity); 106 | } 107 | return entity; 108 | } 109 | 110 | public HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) 111 | { 112 | var player = @event.Userid; 113 | if (player == null) return HookResult.Continue; 114 | var wings = Item.GetPlayerEquipments(player, "wings"); 115 | foreach (var equip in wings) 116 | { 117 | var item = Item.GetItem(equip.UniqueId); 118 | if (item != null && item.TryGetValue("model", out var model)) 119 | { 120 | var animation = item.TryGetValue("animation", out var anim) ? anim : string.Empty; 121 | EquipWings(player, model, equip.Slot, animation); 122 | } 123 | } 124 | return HookResult.Continue; 125 | } 126 | 127 | public HookResult OnPlayerTeam(EventPlayerTeam @event, GameEventInfo info) 128 | { 129 | var player = @event.Userid; 130 | if (player == null) return HookResult.Continue; 131 | if (PlayerWingsEntities.ContainsKey(player)) 132 | { 133 | foreach (var slot in PlayerWingsEntities[player].Keys.ToList()) 134 | UnEquipWings(player, slot); 135 | } 136 | return HookResult.Continue; 137 | } 138 | 139 | public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info) 140 | { 141 | var player = @event.Userid; 142 | if (player == null) return HookResult.Continue; 143 | if (PlayerWingsEntities.ContainsKey(player)) 144 | { 145 | foreach (var slot in PlayerWingsEntities[player].Keys.ToList()) 146 | UnEquipWings(player, slot); 147 | } 148 | return HookResult.Continue; 149 | } 150 | } -------------------------------------------------------------------------------- /Store/src/config/config.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Core.Translations; 4 | using Store.Extension; 5 | using System.Reflection; 6 | using System.Text.Json; 7 | using Tomlyn; 8 | using Tomlyn.Model; 9 | 10 | namespace Store; 11 | 12 | public class Item_Config : BasePluginConfig 13 | { 14 | public JsonElement Items { get; set; } = new(); 15 | } 16 | 17 | public static class Config_Config 18 | { 19 | private static readonly string ConfigPath; 20 | 21 | static Config_Config() 22 | { 23 | string assemblyName = Assembly.GetExecutingAssembly().GetName().Name ?? string.Empty; 24 | 25 | ConfigPath = Path.Combine(Server.GameDirectory, 26 | "csgo", 27 | "addons", 28 | "counterstrikesharp", 29 | "configs", 30 | "plugins", 31 | assemblyName, 32 | "config.toml" 33 | ); 34 | } 35 | 36 | public static Cfg Config { get; } = new(); 37 | 38 | public static void Load() 39 | { 40 | if (!File.Exists(ConfigPath)) 41 | throw new FileNotFoundException($"Configuration file not found: {ConfigPath}"); 42 | 43 | LoadConfig(ConfigPath); 44 | Task.Run(async () => await Database.CreateDatabaseAsync(Config.DatabaseConnection)); 45 | } 46 | 47 | private static void LoadConfig(string configPath) 48 | { 49 | string configText = File.ReadAllText(configPath); 50 | TomlTable model = Toml.ToModel(configText); 51 | 52 | Config.DatabaseConnection = model.GetSection<Config_DatabaseConnection>("DatabaseConnection") ?? new(); 53 | Config.Commands = model.GetSection<Config_Commands>("Commands") ?? new(); 54 | Config.DefaultModels = model.GetSection<Config_DefaultModels>("DefaultModels") ?? new(); 55 | Config.Menu = model.GetSection<Config_Menu>("Menu") ?? new(); 56 | Config.Settings = model.GetSection<Config_Settings>("Settings") ?? new(); 57 | Config.Permissions = model.GetSection<Config_Permissions>("Permissions") ?? new(); 58 | Config.Credits = model.TryGetValue("Credits", out object creditsObj) && creditsObj is TomlTable creditsTable 59 | ? creditsTable.ToDictionary( 60 | kv => kv.Key, 61 | kv => kv.Value is TomlTable creditTable ? creditTable.MapTomlTableToObject<Config_Credits>() : new(), 62 | StringComparer.OrdinalIgnoreCase 63 | ) 64 | : []; 65 | 66 | Config.Settings.Tag = Config.Settings.Tag.ReplaceColorTags(); 67 | } 68 | } 69 | 70 | public sealed class Cfg 71 | { 72 | public Config_DatabaseConnection DatabaseConnection { get; set; } = new(); 73 | public Config_Commands Commands { get; set; } = new(); 74 | public Config_DefaultModels DefaultModels { get; set; } = new(); 75 | public Dictionary<string, Config_Credits> Credits { get; set; } = []; 76 | public Config_Menu Menu { get; set; } = new(); 77 | public Config_Settings Settings { get; set; } = new(); 78 | public Config_Permissions Permissions { get; set; } = new(); 79 | } 80 | 81 | public sealed class Config_DatabaseConnection 82 | { 83 | public string Host { get; set; } = string.Empty; 84 | public uint Port { get; set; } = 3306; 85 | public string User { get; set; } = string.Empty; 86 | public string Pass { get; set; } = string.Empty; 87 | public string Name { get; set; } = string.Empty; 88 | public string StorePlayersName { get; set; } = string.Empty; 89 | public string StoreItemsName { get; set; } = string.Empty; 90 | public string StoreEquipments { get; set; } = string.Empty; 91 | } 92 | 93 | public sealed class Config_Commands 94 | { 95 | public List<string> Credits { get; set; } = []; 96 | public List<string> Store { get; set; } = []; 97 | public List<string> Inventory { get; set; } = []; 98 | public List<string> GiveCredits { get; set; } = []; 99 | public List<string> Gift { get; set; } = []; 100 | public List<string> ResetPlayer { get; set; } = []; 101 | public List<string> ResetDatabase { get; set; } = []; 102 | public List<string> RefreshPlayersCredits { get; set; } = []; 103 | public List<string> HideTrails { get; set; } = []; 104 | public List<string> PlayerSkinsOff { get; set; } = []; 105 | public List<string> PlayerSkinsOn { get; set; } = []; 106 | } 107 | 108 | public sealed class Config_DefaultModels 109 | { 110 | public List<string> Terrorist { get; set; } = []; 111 | public List<string> CounterTerrorist { get; set; } = []; 112 | public bool DefaultModelDisableLeg { get; set; } 113 | } 114 | 115 | public sealed class Config_Credits 116 | { 117 | public int Start { get; set; } 118 | public bool IgnoreWarmup { get; set; } 119 | public int IntervalActiveInActive { get; set; } 120 | public int AmountActive { get; set; } 121 | public int AmountInActive { get; set; } 122 | public int AmountKill { get; set; } 123 | } 124 | 125 | public sealed class Config_Menu 126 | { 127 | public bool EnableSelling { get; set; } = true; 128 | public bool EnableConfirmMenu { get; set; } 129 | public string MenuType { get; set; } = string.Empty; 130 | public string VipFlag { get; set; } = string.Empty; 131 | public string MenuPressSoundYes { get; set; } = string.Empty; 132 | public string MenuPressSoundNo { get; set; } = string.Empty; 133 | public bool CloseMenuAfterSelect { get; set; } 134 | } 135 | 136 | public sealed class Config_Settings 137 | { 138 | public string Tag { get; set; } = string.Empty; 139 | public int MaxHealth { get; set; } 140 | public int MaxArmor { get; set; } 141 | public float SellRatio { get; set; } 142 | public float ApplyPlayerskinDelay { get; set; } 143 | public bool SellUsePurchaseCredit { get; set; } 144 | public bool EnableCs2Fixes { get; set; } 145 | public bool EnableLog { get; set; } 146 | } 147 | 148 | public sealed class Config_Permissions 149 | { 150 | public string Model0Model1Flag { get; set; } = string.Empty; 151 | public string GiveCredits { get; set; } = string.Empty; 152 | } -------------------------------------------------------------------------------- /Store/src/item/items/equipment.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | using static Store.Store; 5 | using static StoreApi.Store; 6 | 7 | namespace Store; 8 | 9 | [StoreItemType("equipment")] 10 | public class Item_Equipment : IItemModule 11 | { 12 | public bool Equipable => true; 13 | public bool? RequiresAlive => null; 14 | 15 | private static readonly Dictionary<CCSPlayerController, Dictionary<int, CDynamicProp>> PlayerEquipmentEntities = []; 16 | 17 | public void OnPluginStart() 18 | { 19 | if (Item.IsAnyItemExistInType("equipment")) 20 | { 21 | Instance.RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn); 22 | Instance.RegisterEventHandler<EventPlayerTeam>(OnPlayerTeam); 23 | Instance.RegisterEventHandler<EventPlayerDisconnect>(OnPlayerDisconnect); 24 | } 25 | } 26 | 27 | public void OnMapStart() 28 | { 29 | PlayerEquipmentEntities.Clear(); 30 | } 31 | 32 | public void OnServerPrecacheResources(ResourceManifest manifest) 33 | { 34 | List<KeyValuePair<string, Dictionary<string, string>>> items = Item.GetItemsByType("equipment"); 35 | 36 | foreach (KeyValuePair<string, Dictionary<string, string>> item in items) 37 | manifest.AddResource(item.Value["model"]); 38 | } 39 | 40 | public bool OnEquip(CCSPlayerController player, Dictionary<string, string> item) 41 | { 42 | if (!item.TryGetValue("slot", out string? slotStr) || !int.TryParse(slotStr, out int slot) || slot < 0) 43 | return false; 44 | 45 | EquipModel(player, item["model"], slot); 46 | return true; 47 | } 48 | 49 | public bool OnUnequip(CCSPlayerController player, Dictionary<string, string> item, bool update) 50 | { 51 | if (!item.TryGetValue("slot", out string? slotStr) || !int.TryParse(slotStr, out int slot)) 52 | return false; 53 | 54 | UnEquipModel(player, slot); 55 | return true; 56 | } 57 | 58 | public static void EquipModel(CCSPlayerController player, string model, int slot) 59 | { 60 | UnEquipModel(player, slot); 61 | 62 | Server.NextFrame(() => 63 | { 64 | CDynamicProp? entity = CreateItem(player, model); 65 | if (entity != null && entity.IsValid) 66 | { 67 | if (!PlayerEquipmentEntities.ContainsKey(player)) 68 | PlayerEquipmentEntities[player] = []; 69 | 70 | PlayerEquipmentEntities[player][slot] = entity; 71 | } 72 | }); 73 | } 74 | 75 | public static void UnEquipModel(CCSPlayerController player, int slot) 76 | { 77 | if (!PlayerEquipmentEntities.TryGetValue(player, out Dictionary<int, CDynamicProp>? value) || !value.ContainsKey(slot)) 78 | return; 79 | 80 | CDynamicProp? entity = value[slot]; 81 | 82 | if (entity != null && entity.IsValid) 83 | entity.Remove(); 84 | 85 | value.Remove(slot); 86 | 87 | if (value.Count == 0) 88 | PlayerEquipmentEntities.Remove(player); 89 | } 90 | 91 | public static CDynamicProp? CreateItem(CCSPlayerController player, string model) 92 | { 93 | CCSPlayerPawn? pawn = player.PlayerPawn.Value; 94 | if (pawn == null) return null; 95 | 96 | CDynamicProp? entity = Utilities.CreateEntityByName<CDynamicProp>("prop_dynamic_override"); 97 | 98 | if (entity == null) 99 | return null; 100 | 101 | entity.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags &= ~(uint)(1 << 2); 102 | entity.SetModel(model); 103 | entity.DispatchSpawn(); 104 | entity.AcceptInput("FollowEntity", pawn, pawn, "!activator"); 105 | 106 | return entity; 107 | } 108 | 109 | public HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) 110 | { 111 | CCSPlayerController? player = @event.Userid; 112 | if (player == null) return HookResult.Continue; 113 | 114 | List<StoreApi.Store.Store_Equipment> equippedItems = [.. Instance.GlobalStorePlayerEquipments.Where(x => x.SteamID == player.SteamID && x.Type == "equipment")]; 115 | 116 | if (PlayerEquipmentEntities.TryGetValue(player, out Dictionary<int, CDynamicProp>? value)) 117 | { 118 | List<int> slotsToRemove = [.. value.Where(kv => !equippedItems.Any(item => item.Slot == kv.Key)).Select(kv => kv.Key)]; 119 | 120 | foreach (int slot in slotsToRemove) 121 | UnEquipModel(player, slot); 122 | } 123 | 124 | foreach (StoreApi.Store.Store_Equipment? item in equippedItems) 125 | { 126 | if (Item.GetItem(item.UniqueId) is Dictionary<string, string> itemData && 127 | itemData.TryGetValue("model", out string? model) && 128 | itemData.TryGetValue("slot", out string? slotStr) && int.TryParse(slotStr, out int slot)) 129 | { 130 | if (PlayerEquipmentEntities.TryGetValue(player, out Dictionary<int, CDynamicProp>? equipment) && 131 | equipment.TryGetValue(slot, out CDynamicProp? entity) && entity != null && entity.IsValid) 132 | continue; 133 | 134 | EquipModel(player, model, slot); 135 | } 136 | } 137 | 138 | return HookResult.Continue; 139 | } 140 | 141 | public HookResult OnPlayerTeam(EventPlayerTeam @event, GameEventInfo info) 142 | { 143 | CleanUpModels(@event.Userid); 144 | return HookResult.Continue; 145 | } 146 | 147 | public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info) 148 | { 149 | CleanUpModels(@event.Userid); 150 | return HookResult.Continue; 151 | } 152 | 153 | public static void CleanUpModels(CCSPlayerController? player) 154 | { 155 | if (player != null && PlayerEquipmentEntities.TryGetValue(player, out Dictionary<int, CDynamicProp>? value)) 156 | { 157 | foreach (CDynamicProp entity in value.Values) 158 | if (entity != null && entity.IsValid) 159 | entity.Remove(); 160 | 161 | PlayerEquipmentEntities.Remove(player); 162 | } 163 | } 164 | } -------------------------------------------------------------------------------- /Store/src/item/items/tags.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Core.Translations; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | using TagsApi; 5 | using static Store.Store; 6 | using static StoreApi.Store; 7 | using static TagsApi.Tags; 8 | 9 | namespace Store; 10 | 11 | [StoreItemTypes(["chatcolor", "namecolor", "scoretag", "chattag"])] 12 | public class Item_Tags : IItemModule 13 | { 14 | private static ITagApi? _tagApi; 15 | private static bool _scoreTagExists = false; 16 | private static bool _othersExists = false; 17 | private static bool _loaded = false; 18 | 19 | public bool Equipable => true; 20 | public bool? RequiresAlive => null; 21 | 22 | public void OnPluginStart() 23 | { 24 | _scoreTagExists = Item.IsAnyItemExistInType("scoretag"); 25 | _othersExists = Item.IsAnyItemExistInTypes(["chatcolor", "namecolor", "chattag"]); 26 | 27 | OnPluginsAllLoaded(); 28 | } 29 | 30 | public static void OnPluginEnd() 31 | { 32 | if (_tagApi == null) 33 | return; 34 | 35 | if (_othersExists) 36 | _tagApi.OnMessageProcessPre -= OnMessageProcess; 37 | 38 | if (_scoreTagExists) 39 | _tagApi.OnTagsUpdatedPre -= OnTagsUpdatedPre; 40 | } 41 | 42 | public static void OnPluginsAllLoaded() 43 | { 44 | if (_loaded) 45 | return; 46 | 47 | _loaded = true; 48 | 49 | try 50 | { 51 | _tagApi = ITagApi.Capability.Get(); 52 | 53 | if (_tagApi != null) 54 | { 55 | if (_othersExists) 56 | _tagApi.OnMessageProcessPre += OnMessageProcess; 57 | 58 | if (_scoreTagExists) 59 | _tagApi.OnTagsUpdatedPre += OnTagsUpdatedPre; 60 | 61 | Console.WriteLine("[Store] TagsApi features successfully loaded"); 62 | } 63 | } 64 | catch (KeyNotFoundException) 65 | { 66 | Console.WriteLine("[Store] TagsApi plugin not found, tag features will be disabled"); 67 | _tagApi = null; 68 | } 69 | catch (Exception ex) 70 | { 71 | Console.WriteLine($"[Store] Error loading TagsApi: {ex.Message}"); 72 | _tagApi = null; 73 | } 74 | } 75 | 76 | public void OnMapStart() { } 77 | public void OnServerPrecacheResources(ResourceManifest manifest) { } 78 | 79 | public bool OnEquip(CCSPlayerController player, Dictionary<string, string> item) 80 | { 81 | if (_tagApi != null && item["type"] == "scoretag") 82 | { 83 | string tag = item["value"]; 84 | TagPrePost prePost = item.TryGetValue("pre", out string? p) && p == "true" ? TagPrePost.Pre : TagPrePost.Post; 85 | _tagApi.AddAttribute(player, TagType.ScoreTag, prePost, tag); 86 | } 87 | return true; 88 | } 89 | 90 | public bool OnUnequip(CCSPlayerController player, Dictionary<string, string> item, bool update) 91 | { 92 | if (_tagApi != null && item["type"] == "scoretag") 93 | { 94 | string? scoreTag = _tagApi.GetAttribute(player, TagType.ScoreTag); 95 | string valueToRemove = item["value"]; 96 | 97 | if (scoreTag != null && scoreTag.Contains(valueToRemove)) 98 | { 99 | scoreTag = scoreTag.Replace(valueToRemove, string.Empty); 100 | _tagApi.SetAttribute(player, TagType.ScoreTag, scoreTag); 101 | } 102 | } 103 | return true; 104 | } 105 | 106 | private static HookResult OnMessageProcess(MessageProcess mp) 107 | { 108 | if (_tagApi == null) return HookResult.Continue; 109 | 110 | if (!Instance.GlobalStorePlayerEquipments.Any(kvp => kvp.Type is "chattag" or "chatcolor" or "namecolor")) 111 | return HookResult.Continue; 112 | 113 | ProcessChatTags(mp); 114 | ProcessChatColor(mp); 115 | ProcessNameColor(mp); 116 | 117 | return HookResult.Continue; 118 | } 119 | 120 | private static void ProcessChatTags(MessageProcess mp) 121 | { 122 | Item.GetPlayerEquipments(mp.Player, "chattag").ForEach(tag => 123 | { 124 | Dictionary<string, string>? item = Item.GetItem(tag.UniqueId); 125 | if (item == null) return; 126 | 127 | TagPrePost pre = item.TryGetValue("pre", out string? p) && p == "true" ? TagPrePost.Pre : TagPrePost.Post; 128 | string color = item.TryGetValue("color", out string? c) ? c : "{white}"; 129 | string newTag = color.ReplaceColorTags() + item["value"]!; 130 | 131 | if (pre == TagPrePost.Pre) 132 | mp.Tag.ChatTag = newTag + mp.Tag.ChatTag; 133 | else 134 | mp.Tag.ChatTag += newTag; 135 | }); 136 | } 137 | 138 | private static void ProcessChatColor(MessageProcess mp) 139 | { 140 | StoreApi.Store.Store_Equipment? chatColor = Item.GetPlayerEquipments(mp.Player, "chatcolor").FirstOrDefault(); 141 | if (chatColor == null) return; 142 | 143 | Dictionary<string, string>? item = Item.GetItem(chatColor.UniqueId); 144 | if (item == null) return; 145 | 146 | mp.Tag.ChatColor = item["value"]; 147 | } 148 | 149 | private static void ProcessNameColor(MessageProcess mp) 150 | { 151 | StoreApi.Store.Store_Equipment? nameColor = Item.GetPlayerEquipments(mp.Player, "namecolor").FirstOrDefault(); 152 | if (nameColor == null) return; 153 | 154 | Dictionary<string, string>? item = Item.GetItem(nameColor.UniqueId); 155 | if (item == null) return; 156 | 157 | mp.Tag.NameColor = item["value"]; 158 | } 159 | 160 | private static void OnTagsUpdatedPre(CCSPlayerController player, Tag tag) 161 | { 162 | if (_tagApi == null) return; 163 | 164 | StoreApi.Store.Store_Equipment? scoreTag = Item.GetPlayerEquipments(player, "scoretag").FirstOrDefault(); 165 | if (scoreTag == null) return; 166 | 167 | Dictionary<string, string>? item = Item.GetItem(scoreTag.UniqueId); 168 | if (item == null) return; 169 | 170 | if (_tagApi.GetAttribute(player, TagType.ScoreTag)?.Contains(item["value"]) == true) 171 | return; 172 | 173 | TagPrePost prePost = item.TryGetValue("pre", out string? p) && p == "true" ? TagPrePost.Pre : TagPrePost.Post; 174 | string newTag = item["value"]!; 175 | _tagApi.AddAttribute(player, TagType.ScoreTag, prePost, newTag); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Store/src/item/items/trail.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Commands; 4 | using CounterStrikeSharp.API.Modules.Utils; 5 | using Store.Extension; 6 | using System.Drawing; 7 | using System.Globalization; 8 | using static Store.Config_Config; 9 | using static Store.Store; 10 | using static StoreApi.Store; 11 | 12 | namespace Store; 13 | 14 | [StoreItemType("trail")] 15 | public class Item_Trail : IItemModule 16 | { 17 | private static readonly Vector[] GlobalTrailLastOrigin = new Vector[64]; 18 | private static readonly Vector[] GlobalTrailEndOrigin = new Vector[64]; 19 | public static HashSet<CCSPlayerController> HideTrailPlayerList { get; set; } = []; 20 | public static readonly Dictionary<CEntityInstance, CCSPlayerController> TrailList = []; 21 | private static bool trailExists = false; 22 | 23 | public bool Equipable => true; 24 | public bool? RequiresAlive => null; 25 | 26 | public void OnPluginStart() 27 | { 28 | if (Item.IsAnyItemExistInType("trail")) 29 | { 30 | trailExists = true; 31 | 32 | for (int i = 0; i < 64; i++) 33 | { 34 | GlobalTrailLastOrigin[i] = new(); 35 | GlobalTrailEndOrigin[i] = new(); 36 | } 37 | 38 | foreach (string command in Config.Commands.HideTrails) 39 | Instance.AddCommand(command, "Hide trails", Command_HideTrails); 40 | } 41 | } 42 | 43 | public void OnMapStart() { } 44 | 45 | public void OnServerPrecacheResources(ResourceManifest manifest) 46 | { 47 | Item.GetItemsByType("trail") 48 | .Where(item => item.Value.TryGetValue("model", out string? model) && !string.IsNullOrEmpty(model)) 49 | .ToList() 50 | .ForEach(item => manifest.AddResource(item.Value["model"])); 51 | } 52 | 53 | public bool OnEquip(CCSPlayerController player, Dictionary<string, string> item) 54 | { 55 | return true; 56 | } 57 | 58 | public bool OnUnequip(CCSPlayerController player, Dictionary<string, string> item, bool update) 59 | { 60 | return true; 61 | } 62 | 63 | public static void OnTick(CCSPlayerController player) 64 | { 65 | if (!trailExists) 66 | return; 67 | 68 | Store_Equipment? playertrail = Instance.GlobalStorePlayerEquipments.FirstOrDefault(p => p.SteamID == player.SteamID && p.Type == "trail"); 69 | if (playertrail == null) 70 | return; 71 | 72 | Dictionary<string, string>? itemdata = Item.GetItem(playertrail.UniqueId); 73 | if (itemdata == null) 74 | return; 75 | 76 | CCSPlayerPawn? playerPawn = player.PlayerPawn.Value; 77 | if (playerPawn == null || playerPawn.AbsOrigin == null) 78 | return; 79 | 80 | Vector absorigin = playerPawn.AbsOrigin; 81 | if (VectorExtensions.CalculateDistance(GlobalTrailLastOrigin[player.Slot], absorigin) <= 5.0f) 82 | return; 83 | 84 | VectorExtensions.Copy(absorigin, GlobalTrailLastOrigin[player.Slot]); 85 | 86 | float lifetime = itemdata.TryGetValue("lifetime", out string? ltvalue) && float.TryParse(ltvalue, CultureInfo.InvariantCulture, out float lt) ? lt : 1.3f; 87 | 88 | if (itemdata.TryGetValue("color", out string? cvalue)) 89 | { 90 | Color? color = null; 91 | 92 | if (!string.IsNullOrEmpty(cvalue)) 93 | { 94 | string[] colorValues = cvalue.Split(' '); 95 | color = Color.FromArgb(int.Parse(colorValues[0]), int.Parse(colorValues[1]), int.Parse(colorValues[2])); 96 | } 97 | 98 | CreateBeam(player, absorigin, lifetime, color, itemdata); 99 | } 100 | else 101 | { 102 | CreateParticle(absorigin, itemdata["model"], lifetime, itemdata, player); 103 | } 104 | } 105 | 106 | public static void CreateParticle(Vector absOrigin, string effectName, float lifetime, Dictionary<string, string> itemdata, CCSPlayerController player) 107 | { 108 | CParticleSystem? entity = Utilities.CreateEntityByName<CParticleSystem>("info_particle_system"); 109 | if (entity == null || !entity.IsValid) 110 | return; 111 | 112 | string acceptinputvalue = itemdata.GetValueOrDefault("acceptInputValue", "Start"); 113 | QAngle angle = ParseAngle(itemdata.GetValueOrDefault("angleValue", "90 90 90")); 114 | 115 | entity.EffectName = effectName; 116 | entity.DispatchSpawn(); 117 | entity.Teleport(absOrigin, angle, new Vector()); 118 | entity.AcceptInput(acceptinputvalue); 119 | entity.AcceptInput("FollowEntity", player.PlayerPawn?.Value!, player.PlayerPawn?.Value!, "!activator"); 120 | 121 | TrailList[entity] = player; 122 | 123 | Instance.AddTimer(lifetime, () => 124 | { 125 | if (entity.IsValid) 126 | entity.Remove(); 127 | TrailList.Remove(entity); 128 | }); 129 | } 130 | 131 | public static void CreateBeam(CCSPlayerController player, Vector absOrigin, float lifetime, Color? color, Dictionary<string, string> itemdata) 132 | { 133 | CBeam? beam = Utilities.CreateEntityByName<CBeam>("env_beam"); 134 | if (beam == null) 135 | return; 136 | 137 | if (VectorExtensions.IsZero(GlobalTrailEndOrigin[player.Slot])) 138 | VectorExtensions.Copy(absOrigin, GlobalTrailEndOrigin[player.Slot]); 139 | 140 | color ??= GetRandomColor(); 141 | if (color == null) 142 | return; 143 | 144 | beam.RenderMode = RenderMode_t.kRenderTransColor; 145 | beam.Width = itemdata.TryGetValue("width", out string? widthValue) && float.TryParse(widthValue, CultureInfo.InvariantCulture, out float width) ? width : 1.0f; 146 | beam.Render = (Color)color; 147 | 148 | beam.Teleport(absOrigin, new QAngle(), new Vector()); 149 | VectorExtensions.Copy(GlobalTrailEndOrigin[player.Slot], beam.EndPos); 150 | VectorExtensions.Copy(absOrigin, GlobalTrailEndOrigin[player.Slot]); 151 | 152 | Utilities.SetStateChanged(beam, "CBeam", "m_vecEndPos"); 153 | 154 | TrailList[beam] = player; 155 | 156 | Instance.AddTimer(lifetime, () => 157 | { 158 | if (beam.IsValid) 159 | beam.Remove(); 160 | TrailList.Remove(beam); 161 | }); 162 | } 163 | 164 | private static Color? GetRandomColor() 165 | { 166 | KnownColor? randomColorName = (KnownColor?)Enum.GetValues(typeof(KnownColor)).GetValue(Instance.Random.Next(Enum.GetValues(typeof(KnownColor)).Length)); 167 | return randomColorName.HasValue ? Color.FromKnownColor(randomColorName.Value) : null; 168 | } 169 | 170 | private static QAngle ParseAngle(string angleValue) 171 | { 172 | string[] angleValues = angleValue.Split(' '); 173 | return new QAngle(int.Parse(angleValues[0]), int.Parse(angleValues[1]), int.Parse(angleValues[2])); 174 | } 175 | 176 | public static void Command_HideTrails(CCSPlayerController? player, CommandInfo info) 177 | { 178 | if (player == null) 179 | return; 180 | 181 | if (!HideTrailPlayerList.Remove(player)) 182 | { 183 | HideTrailPlayerList.Add(player); 184 | player.PrintToChatMessage("Hidetrails on"); 185 | } 186 | else 187 | { 188 | player.PrintToChatMessage("Hidetrails off"); 189 | } 190 | } 191 | } -------------------------------------------------------------------------------- /Store/src/menu/menu.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API.Core; 2 | using CounterStrikeSharp.API.Core.Translations; 3 | using CS2MenuManager.API.Class; 4 | using CS2MenuManager.API.Enum; 5 | using CS2MenuManager.API.Interface; 6 | using Store.Extension; 7 | using System.Text.Json; 8 | using static Store.Config_Config; 9 | using static Store.MenuBase; 10 | using static Store.Store; 11 | 12 | namespace Store; 13 | 14 | public static class Menu 15 | { 16 | public static void DisplayStore(CCSPlayerController player, bool inventory) 17 | { 18 | OpenMenu(player, Instance.Localizer.ForPlayer(player, "menu_store<title>", Credits.Get(player)), Instance.Config.Items, inventory, null); 19 | } 20 | 21 | public static void OpenMenu(CCSPlayerController player, string title, JsonElement elementData, bool inventory, IMenu? prevMenu) 22 | { 23 | BaseMenu menu = CreateMenuByType(title); 24 | menu.PrevMenu = prevMenu; 25 | 26 | List<JsonProperty> items = elementData.GetElementJsonProperty(["flag", "team"]); 27 | foreach (JsonProperty item in items) 28 | { 29 | if (item.Value.TryGetProperty("flag", out JsonElement flagElement) && !CheckFlag(player, flagElement.ToString(), true)) 30 | continue; 31 | 32 | if (item.Value.TryGetProperty("team", out JsonElement teamElement) && player.Team.ToString() != teamElement.ToString()) 33 | continue; 34 | 35 | if (item.Value.TryGetProperty("uniqueid", out JsonElement uniqueIdElement)) 36 | { 37 | menu.AddItems(player, uniqueIdElement, inventory, menu); 38 | continue; 39 | } 40 | 41 | if (inventory && !Item.PlayerHasAny(player, item.Value)) 42 | continue; 43 | 44 | string categoryName = GetCategoryName(player, item); 45 | menu.AddItem(categoryName, (p, o) => OpenMenu(p, categoryName, item.Value, inventory, menu)); 46 | } 47 | 48 | menu.Display(player, 0); 49 | } 50 | 51 | public static void AddItems(this IMenu menu, CCSPlayerController player, JsonElement uniqueIdElement, bool inventory, IMenu prevMenu) 52 | { 53 | if (!Instance.Items.TryGetValue(uniqueIdElement.ToString(), out Dictionary<string, string>? item)) 54 | return; 55 | 56 | if (item.TryGetValue("enable", out string? enable) && enable != "true") 57 | return; 58 | 59 | if (!CheckFlag(player, item) || (inventory && !Item.PlayerHas(player, item["type"], item["uniqueid"], false))) 60 | return; 61 | 62 | if (Item.PlayerHas(player, item["type"], item["uniqueid"], false)) 63 | { 64 | menu.AddMenuOption(player, (p, o) => 65 | { 66 | p.ExecuteClientCommand($"play {Config.Menu.MenuPressSoundYes}"); 67 | DisplayItemOption(p, item, inventory, prevMenu); 68 | }, Item.GetItemName(player, item)); 69 | } 70 | else if (!inventory && !item.IsHidden()) 71 | { 72 | menu.AddMenuOption(player, (p, o) => SelectPurchase(p, item, int.Parse(item["price"]) > 0, inventory, prevMenu), 73 | Item.CanBuy(player, item) ? DisableOption.None : DisableOption.DisableHideNumber, 74 | int.Parse(item["price"]) <= 0 ? "menu_store<purchase1>" : "menu_store<purchase>", 75 | Item.GetItemName(player, item), item["price"]); 76 | } 77 | } 78 | 79 | private static void SelectPurchase(CCSPlayerController player, Dictionary<string, string> item, bool confirm, bool inventory, IMenu prevMenu) 80 | { 81 | player.ExecuteClientCommand($"play {Config.Menu.MenuPressSoundYes}"); 82 | 83 | if (confirm && Config.Menu.EnableConfirmMenu) 84 | { 85 | DisplayConfirmationMenu(player, item, inventory, prevMenu); 86 | } 87 | else if (Item.Purchase(player, item)) 88 | { 89 | DisplayItemOption(player, item, inventory, prevMenu); 90 | } 91 | else 92 | { 93 | player.ExecuteClientCommand($"play {Config.Menu.MenuPressSoundNo}"); 94 | 95 | if (Config.Menu.CloseMenuAfterSelect) 96 | DisplayStore(player, inventory); 97 | } 98 | } 99 | 100 | public static void DisplayItemOption(CCSPlayerController player, Dictionary<string, string> item, bool inventory, IMenu prevMenu) 101 | { 102 | BaseMenu menu = CreateMenuByType(Item.GetItemName(player, item)); 103 | menu.PrevMenu = prevMenu; 104 | 105 | menu.AddInspectOption(player, item); 106 | 107 | if (Item.PlayerUsing(player, item["type"], item["uniqueid"])) 108 | { 109 | menu.AddMenuOption(player, (p, o) => 110 | { 111 | if (Item.Unequip(p, item, true)) 112 | { 113 | p.ExecuteClientCommand($"play {Config.Menu.MenuPressSoundYes}"); 114 | p.PrintToChatMessage("Purchase Unequip", Item.GetItemName(p, item)); 115 | } 116 | DisplayItemOption(p, item, inventory, prevMenu); 117 | }, "menu_store<unequip>"); 118 | } 119 | else 120 | { 121 | menu.AddMenuOption(player, (p, o) => 122 | { 123 | if (Item.Equip(p, item)) 124 | { 125 | p.ExecuteClientCommand($"play {Config.Menu.MenuPressSoundYes}"); 126 | p.PrintToChatMessage("Purchase Equip", Item.GetItemName(p, item)); 127 | } 128 | DisplayItemOption(p, item, inventory, prevMenu); 129 | }, "menu_store<equip>"); 130 | } 131 | 132 | StoreApi.Store.Store_Item? playerItem = Instance.GlobalStorePlayerItems.FirstOrDefault(p => p.SteamID == player.SteamID && p.Type == item["type"] && p.UniqueId == item["uniqueid"]); 133 | if (playerItem != null) 134 | { 135 | if (Config.Menu.EnableSelling && !Item.IsPlayerVip(player) && !CheckFlag(player, item, true)) 136 | { 137 | int sellingPrice = GetSellingPrice(item, playerItem); 138 | if (sellingPrice > 1) 139 | { 140 | menu.AddMenuOption(player, (p, o) => 141 | { 142 | p.ExecuteClientCommand($"play {Config.Menu.MenuPressSoundYes}"); 143 | Item.Sell(p, item); 144 | p.PrintToChatMessage("Item Sell", Item.GetItemName(p, item)); 145 | DisplayStore(player, inventory); 146 | }, "menu_store<sell>", sellingPrice); 147 | } 148 | } 149 | 150 | if (playerItem.DateOfExpiration > DateTime.MinValue) 151 | menu.AddItem(playerItem.DateOfExpiration.ToString(), DisableOption.DisableHideNumber); 152 | } 153 | 154 | menu.Display(player, 0); 155 | } 156 | 157 | public static void DisplayConfirmationMenu(CCSPlayerController player, Dictionary<string, string> item, bool inventory, IMenu prevMenu) 158 | { 159 | BaseMenu menu = CreateMenuByType(Instance.Localizer.ForPlayer(player, "menu_store<confirm_title>")); 160 | menu.PrevMenu = prevMenu; 161 | 162 | menu.AddMenuOption(player, DisableOption.DisableHideNumber, Item.GetItemName(player, item), item["price"]); 163 | menu.AddInspectOption(player, item); 164 | 165 | menu.AddMenuOption(player, (p, o) => 166 | { 167 | if (Item.Purchase(p, item)) 168 | { 169 | p.ExecuteClientCommand($"play {Config.Menu.MenuPressSoundYes}"); 170 | DisplayItemOption(p, item, inventory, prevMenu); 171 | } 172 | else 173 | { 174 | p.ExecuteClientCommand($"play {Config.Menu.MenuPressSoundNo}"); 175 | DisplayStore(player, inventory); 176 | } 177 | }, "menu_store<yes>"); 178 | 179 | menu.AddMenuOption(player, (p, o) => 180 | { 181 | p.ExecuteClientCommand($"play {Config.Menu.MenuPressSoundNo}"); 182 | DisplayStore(p, inventory); 183 | }, "menu_store<no>"); 184 | menu.Display(player, 0); 185 | } 186 | 187 | public static void AddInspectOption(this IMenu menu, CCSPlayerController player, Dictionary<string, string> item) 188 | { 189 | if (item["type"] is not ("playerskin" or "customweapon")) 190 | return; 191 | 192 | menu.AddMenuOption(player, (p, o) => 193 | { 194 | o.PostSelectAction = PostSelectAction.Nothing; 195 | 196 | if (Instance.InspectList.ContainsValue(p)) 197 | return; 198 | 199 | InspectAction(p, item, item["type"]); 200 | }, "menu_store<inspect>"); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /Store/src/item/items/playerskin.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Admin; 4 | using CounterStrikeSharp.API.Modules.Commands; 5 | using CounterStrikeSharp.API.Modules.Utils; 6 | using Store.Extension; 7 | using static Store.Config_Config; 8 | using static Store.Store; 9 | using static StoreApi.Store; 10 | 11 | namespace Store; 12 | 13 | [StoreItemType("playerskin")] 14 | public class Item_PlayerSkin : IItemModule 15 | { 16 | public static bool ForceModelDefault { get; set; } = false; 17 | private static bool DisableLeg(Dictionary<string, string> item) 18 | { 19 | return item.ContainsKey("disable_leg") && item["disable_leg"] is "true" or "1"; 20 | } 21 | 22 | public bool Equipable => true; 23 | public bool? RequiresAlive => null; 24 | 25 | public void OnPluginStart() 26 | { 27 | if (Item.IsAnyItemExistInType("playerskin")) 28 | { 29 | foreach (string command in Config.Commands.PlayerSkinsOff) 30 | Instance.AddCommand(command, "Turn off playerskins models", Command_Model0); 31 | 32 | foreach (string command in Config.Commands.PlayerSkinsOn) 33 | Instance.AddCommand(command, "Turn on playerskins models", Command_Model1); 34 | 35 | Instance.RegisterEventHandler<EventPlayerSpawn>(OnPlayerSpawn); 36 | Instance.RegisterEventHandler<EventRoundStart>(OnRoundStart, HookMode.Pre); 37 | } 38 | } 39 | 40 | public void OnMapStart() { } 41 | 42 | public void OnServerPrecacheResources(ResourceManifest manifest) 43 | { 44 | foreach (KeyValuePair<string, Dictionary<string, string>> item in Item.GetItemsByType("playerskin")) 45 | { 46 | manifest.AddResource(item.Value["model"]); 47 | if (item.Value.TryGetValue("armModel", out string? armModel) && !string.IsNullOrEmpty(armModel)) 48 | manifest.AddResource(armModel); 49 | } 50 | } 51 | 52 | public bool OnEquip(CCSPlayerController player, Dictionary<string, string> item) 53 | { 54 | if (!item.TryGetValue("slot", out string? slot) || string.IsNullOrEmpty(slot) || ForceModelDefault) 55 | return false; 56 | 57 | player.ChangeModelDelay(item["model"], DisableLeg(item), int.Parse(item["slot"]), item.GetValueOrDefault("skin")); 58 | return true; 59 | } 60 | 61 | public bool OnUnequip(CCSPlayerController player, Dictionary<string, string> item, bool update) 62 | { 63 | if (!update || !item.TryGetValue("slot", out string? slot) || string.IsNullOrEmpty(slot) || ForceModelDefault) 64 | return false; 65 | 66 | (string modelname, bool disableleg, string? skin)? defaultModel = GetDefaultModel(player); 67 | if (defaultModel.HasValue) 68 | player.ChangeModelDelay(defaultModel.Value.modelname, defaultModel.Value.disableleg, player.TeamNum, defaultModel.Value.skin); 69 | 70 | return true; 71 | } 72 | 73 | public static HookResult OnPlayerSpawn(EventPlayerSpawn @event, GameEventInfo info) 74 | { 75 | CCSPlayerController? player = @event.Userid; 76 | if (player == null || player.TeamNum < 2) 77 | return HookResult.Continue; 78 | 79 | (string modelname, bool disableleg, string? skin)? modelData = GetModel(player, player.TeamNum); 80 | if (modelData.HasValue) 81 | player.ChangeModelDelay(modelData.Value.modelname, modelData.Value.disableleg, player.TeamNum, modelData.Value.skin); 82 | 83 | return HookResult.Continue; 84 | } 85 | 86 | public static HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) 87 | { 88 | Instance.InspectList.Clear(); 89 | ForceModelDefault = false; 90 | return HookResult.Continue; 91 | } 92 | 93 | private static void Command_Model0(CCSPlayerController? player, CommandInfo info) 94 | { 95 | if (string.IsNullOrEmpty(Config.Permissions.Model0Model1Flag) || !AdminManager.PlayerHasPermissions(player, Config.Permissions.Model0Model1Flag)) 96 | return; 97 | 98 | List<CCSPlayerController> players = Utilities.GetPlayers(); 99 | foreach (CCSPlayerController target in players) 100 | { 101 | (string modelname, bool disableleg, string? skin)? modelDatas = GetDefaultModel(target); 102 | if (modelDatas.HasValue) 103 | target.PlayerPawn.Value?.ChangeModel(modelDatas.Value.modelname, modelDatas.Value.disableleg, modelDatas.Value.skin); 104 | } 105 | 106 | Server.PrintToChatAll(Config.Settings.Tag + Instance.Localizer["css_model0", player?.PlayerName ?? Instance.Localizer["Console"]]); 107 | ForceModelDefault = true; 108 | } 109 | 110 | private static void Command_Model1(CCSPlayerController? player, CommandInfo info) 111 | { 112 | if (string.IsNullOrEmpty(Config.Permissions.Model0Model1Flag) || !AdminManager.PlayerHasPermissions(player, Config.Permissions.Model0Model1Flag)) 113 | return; 114 | 115 | List<CCSPlayerController> players = Utilities.GetPlayers(); 116 | foreach (CCSPlayerController target in players) 117 | { 118 | (string modelname, bool disableleg, string? skin)? modelDatas = GetModel(target, target.TeamNum); 119 | if (modelDatas.HasValue) 120 | target.PlayerPawn.Value?.ChangeModel(modelDatas.Value.modelname, modelDatas.Value.disableleg, modelDatas.Value.skin); 121 | } 122 | 123 | Server.PrintToChatAll(Config.Settings.Tag + Instance.Localizer["css_model1", player?.PlayerName ?? Instance.Localizer["Console"]]); 124 | ForceModelDefault = false; 125 | } 126 | 127 | private static (string modelname, bool disableleg, string? skin)? GetModel(CCSPlayerController player, int teamnum) 128 | { 129 | Store_Equipment? item = Instance.GlobalStorePlayerEquipments.FirstOrDefault(p => p.SteamID == player.SteamID && p.Type == "playerskin" && (p.Slot == teamnum || p.Slot == 1)); 130 | return item == null || ForceModelDefault ? GetDefaultModel(player) : GetStoreModel(item); 131 | } 132 | 133 | private static (string modelname, bool disableleg, string? skin)? GetDefaultModel(CCSPlayerController player) 134 | { 135 | List<string> modelsArray = player.Team == CsTeam.CounterTerrorist ? Config.DefaultModels.CounterTerrorist : Config.DefaultModels.Terrorist; 136 | return modelsArray.Count > 0 137 | ? (modelsArray[Instance.Random.Next(0, modelsArray.Count)], Config.DefaultModels.DefaultModelDisableLeg, null) 138 | : null; 139 | } 140 | 141 | private static (string modelname, bool disableleg, string? skin)? GetStoreModel(Store_Equipment item) 142 | { 143 | Dictionary<string, string>? itemdata = Item.GetItem(item.UniqueId); 144 | return itemdata == null ? null : (itemdata["model"], DisableLeg(itemdata), itemdata.GetValueOrDefault("skin")); 145 | } 146 | 147 | public static void Inspect(CCSPlayerController player, string model, string? skin) 148 | { 149 | CBaseModelEntity? entity = Utilities.CreateEntityByName<CBaseModelEntity>("prop_dynamic"); 150 | if (entity == null || !entity.IsValid || player.PlayerPawn.Value is not CCSPlayerPawn playerPawn) 151 | return; 152 | 153 | Vector _origin = GetFrontPosition(playerPawn.AbsOrigin!, playerPawn.EyeAngles); 154 | QAngle modelAngles = new(0, playerPawn.EyeAngles.Y + 180, 0); 155 | 156 | entity.Spawnflags = 256u; 157 | entity.Collision.SolidType = SolidType_t.SOLID_VPHYSICS; 158 | entity.Teleport(_origin, modelAngles, playerPawn.AbsVelocity); 159 | entity.DispatchSpawn(); 160 | 161 | Server.NextFrame(() => 162 | { 163 | if (entity.IsValid) 164 | { 165 | entity.SetModel(model); 166 | if (skin != null) 167 | entity.AcceptInput("Skin", null, entity, skin); 168 | } 169 | }); 170 | 171 | Instance.InspectList[entity] = player; 172 | Instance.AddTimer(1.0f, () => RotateEntity(player, entity, 0.0f)); 173 | } 174 | 175 | public static void RotateEntity(CCSPlayerController player, CBaseModelEntity entity, float elapsed) 176 | { 177 | if (!entity.IsValid) 178 | return; 179 | 180 | float totalTime = 4.0f; 181 | float totalRotation = 360.0f; 182 | float interval = 0.04f; 183 | float rotationStep = (interval / totalTime) * totalRotation; 184 | 185 | QAngle currentAngles = entity.AbsRotation!; 186 | entity.Teleport(null, new QAngle(currentAngles.X, currentAngles.Y + rotationStep, currentAngles.Z), null); 187 | 188 | if (elapsed < totalTime) 189 | Instance.AddTimer(interval, () => RotateEntity(player, entity, elapsed + interval)); 190 | else 191 | { 192 | Instance.InspectList.Remove(entity); 193 | entity.Remove(); 194 | } 195 | } 196 | 197 | public static Vector GetFrontPosition(Vector position, QAngle angles, float distance = 100.0f) 198 | { 199 | float radYaw = angles.Y * (MathF.PI / 180.0f); 200 | return position + new Vector(MathF.Cos(radYaw), MathF.Sin(radYaw), 0) * distance; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /cs2-store-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "Items": { 3 | "FreePlayerSkin": { 4 | "CT": { 5 | "team": "CounterTerrorist", 6 | "Fernandez Frogman [CT]": { 7 | "uniqueid": "frogman", 8 | "model": "characters/models/ctm_diver/ctm_diver_variantb.vmdl", 9 | "armModel": "", 10 | "type": "playerskin", 11 | "price": "1000", 12 | "slot": "3", 13 | "disable_leg": "0", 14 | "expiration": "0", 15 | "hide": "false" 16 | } 17 | }, 18 | "T": { 19 | "team": "Terrorist", 20 | "Number K": { 21 | "uniqueid": "numberk", 22 | "model": "characters/models/tm_professional/tm_professional_vari.vmdl", 23 | "armModel": "", 24 | "type": "playerskin", 25 | "price": "1000", 26 | "slot": "2", 27 | "disable_leg": "false", 28 | "expiration": "0", 29 | "hide": "false" 30 | } 31 | } 32 | }, 33 | "Admin Player Skins": { 34 | "flag": "@css/ban,@css/unban,76561199165718810", 35 | "Lieutenant Rex Krikey [ROOT-ALL]": { 36 | "uniqueid": "rexkrikey", 37 | "model": "characters/models/ctm_diver/ctm_diver_variantc.vmdl", 38 | "armModel": "", 39 | "type": "playerskin", 40 | "price": "1000", 41 | "slot": "1", 42 | "flag": "@css/root,76561199165718810", 43 | "disable_leg": "false", 44 | "expiration": "0", 45 | "hide": "false" 46 | } 47 | }, 48 | "Buy Weapon": { 49 | "Deagle": { 50 | "uniqueid": "buydeagle", 51 | "weapon": "weapon_deagle", 52 | "type": "weapon", 53 | "price": "1000" 54 | }, 55 | "AK47 [T]": { 56 | "uniqueid": "buyak47", 57 | "weapon": "weapon_ak47", 58 | "type": "weapon", 59 | "price": "2000", 60 | "team": "2", 61 | "no_pistol_round": "true" 62 | }, 63 | "M4A4 [CT]": { 64 | "uniqueid": "buym4a4ct", 65 | "weapon": "weapon_m4a1", 66 | "type": "weapon", 67 | "price": "2000", 68 | "team": "3", 69 | "no_pistol_round": "true" 70 | } 71 | }, 72 | "Features": { 73 | "Gravity": { 74 | "0.1 Gravity": { 75 | "uniqueid": "gravity0.1", 76 | "type": "gravity", 77 | "price": "1", 78 | "gravityValue": "0.1" 79 | }, 80 | "0.2 Gravity": { 81 | "uniqueid": "gravity0.2", 82 | "type": "gravity", 83 | "price": "1000", 84 | "gravityValue": "0.2" 85 | } 86 | }, 87 | "Speed": { 88 | "1.1f Speed 1 Round": { 89 | "uniqueid": "speed10", 90 | "type": "speed", 91 | "price": "1000", 92 | "speedValue": "1.1", 93 | "speedTimerValue": "0" 94 | }, 95 | "5 Sec 1.1f Speed": { 96 | "uniqueid": "speed51.1", 97 | "type": "speed", 98 | "price": "1000", 99 | "speedValue": "1.1", 100 | "speedTimerValue": "5" 101 | } 102 | }, 103 | "Godmode": { 104 | "5 Sec Godmode": { 105 | "uniqueid": "god5", 106 | "type": "godmode", 107 | "price": "1000", 108 | "godmodeTimerValue": "5" 109 | }, 110 | "10 Sec Godmode": { 111 | "uniqueid": "god10", 112 | "type": "godmode", 113 | "price": "1000", 114 | "godmodeTimerValue": "10" 115 | } 116 | }, 117 | "Respawn": { 118 | "uniqueid": "respawn", 119 | "type": "respawn", 120 | "price": "1000" 121 | }, 122 | "50 HP": { 123 | "uniqueid": "health50", 124 | "type": "health", 125 | "price": "1000", 126 | "healthValue": "50" 127 | }, 128 | "10 Armor": { 129 | "uniqueid": "armor10", 130 | "type": "armor", 131 | "price": "1000", 132 | "armorValue": "10" 133 | }, 134 | "Open Doors": { 135 | "uniqueid": "open", 136 | "type": "open", 137 | "price": "1000" 138 | }, 139 | "Sound Thunder": { 140 | "uniqueid": "thunderclose", 141 | "sound": "sounds/ambient/ambience/rainscapes/thunder_close01.vsnd_c", 142 | "type": "sound", 143 | "price": "1000" 144 | }, 145 | "Bunnyhop": { 146 | "uniqueid": "bunnyhop", 147 | "type": "bunnyhop", 148 | "price": "1000", 149 | "maxSpeed": "320.0" 150 | }, 151 | "Kill yourself": { 152 | "uniqueid": "killurself", 153 | "type": "link", 154 | "link": "kill", 155 | "price": "1000" 156 | } 157 | }, 158 | "Smoke": { 159 | "Random Smoke Color": { 160 | "uniqueid": "colorsmoke", 161 | "type": "smoke", 162 | "price": "1000", 163 | "slot": "1" 164 | }, 165 | "Red Smoke": { 166 | "uniqueid": "redsmoke", 167 | "type": "smoke", 168 | "color": "255 0 0", 169 | "price": "1000", 170 | "slot": "1" 171 | } 172 | }, 173 | "Trail": { 174 | "Player Trail": { 175 | "Energycirc Trail": { 176 | "uniqueid": "energycircltrail", 177 | "model": "particles/ui/status_levels/ui_status_level_8_energycirc.vpcf", 178 | "type": "trail", 179 | "price": "1000", 180 | "slot": "1", 181 | "lifetime": "1.3", 182 | "acceptInputValue": "Start", 183 | "angleValue": "90 0 0" 184 | }, 185 | "Random color trail": { 186 | "uniqueid": "trailrandomcolor", 187 | "type": "trail", 188 | "price": "1000", 189 | "slot": "1", 190 | "lifetime": "1.3", 191 | "widthValue": "1.0", 192 | "color": "" 193 | }, 194 | "Green color trail": { 195 | "uniqueid": "trailgreencolor", 196 | "type": "trail", 197 | "price": "1000", 198 | "slot": "1", 199 | "lifetime": "1.3", 200 | "widthValue": "1.0", 201 | "color": "0 255 0" 202 | } 203 | }, 204 | "Grenade Trail": { 205 | "Molotov effect": { 206 | "uniqueid": "molotovfire01", 207 | "model": "particles/inferno_fx/molotov_fire01.vpcf", 208 | "type": "grenadetrail", 209 | "price": "1000", 210 | "slot": "1", 211 | "acceptInputValue": "Start" 212 | } 213 | } 214 | }, 215 | "Tracer": { 216 | "Energycirc Tracer": { 217 | "uniqueid": "energycirctracer", 218 | "model": "particles/ui/status_levels/ui_status_level_8_energycirc.vpcf", 219 | "type": "tracer", 220 | "price": "1000", 221 | "slot": "1", 222 | "lifetime": "0.3", 223 | "acceptInputValue": "Start" 224 | } 225 | }, 226 | "Colored Skin": { 227 | "Random coloredskin": { 228 | "uniqueid": "coloredskin_random", 229 | "type": "coloredskin", 230 | "price": "1000", 231 | "slot": "1" 232 | }, 233 | "Green coloredskin": { 234 | "uniqueid": "coloredskin_green", 235 | "type": "coloredskin", 236 | "price": "1000", 237 | "slot": "1", 238 | "color": "0 255 0" 239 | } 240 | }, 241 | "Custom Weapon": { 242 | "AK47": { 243 | "Default AK47": { 244 | "uniqueid": "defaultak47cw", 245 | "viewmodel": "weapons/models/ak47/weapon_rif_ak47.vmdl", 246 | "worldmodel": "", 247 | "type": "customweapon", 248 | "weapon": "weapon_ak47", 249 | "price": "1000", 250 | "slot": "1" 251 | } 252 | } 253 | }, 254 | "Pet": { 255 | "Chicken": { 256 | "uniqueid": "mychicken", 257 | "model": "models/chicken/chicken.vmdl", 258 | "type": "equipment", 259 | "price": "1000", 260 | "slot": "1" 261 | } 262 | }, 263 | "Wings": { 264 | "Wings hostage": { 265 | "uniqueid": "mywings", 266 | "model": "models/hostage/hostage_carry.vmdl", 267 | "type": "wings", 268 | "price": "1000", 269 | "slot": "1", 270 | "animation": "" 271 | } 272 | }, 273 | "Tags": { 274 | "Chat Color": { 275 | "Red": { 276 | "uniqueid": "chatcolorred", 277 | "value": "{Red}", 278 | "type": "chatcolor", 279 | "price": "1000", 280 | "slot": "1" 281 | } 282 | }, 283 | "Name Color": { 284 | "Red": { 285 | "uniqueid": "ncred", 286 | "value": "{Red}", 287 | "type": "namecolor", 288 | "price": "1000", 289 | "slot": "1" 290 | } 291 | }, 292 | "Score Tag": { 293 | "King": { 294 | "uniqueid": "stking", 295 | "value": "King", 296 | "pre": "false", 297 | "type": "scoretag", 298 | "price": "1000", 299 | "slot": "1" 300 | } 301 | }, 302 | "Chat Tag": { 303 | "Queen": { 304 | "uniqueid": "ctqueen", 305 | "value": "Queen", 306 | "pre": "false", 307 | "color": "{red}", 308 | "type": "chattag", 309 | "price": "1000", 310 | "slot": "1" 311 | } 312 | } 313 | } 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /Store/src/command/command.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Admin; 4 | using CounterStrikeSharp.API.Modules.Commands; 5 | using Store.Extension; 6 | using static Store.Config_Config; 7 | using static Store.FindTarget; 8 | using static Store.Store; 9 | 10 | namespace Store; 11 | 12 | public static class Command 13 | { 14 | public static void Load() 15 | { 16 | Config_Commands config = Config.Commands; 17 | 18 | Dictionary<IEnumerable<string>, (string Description, CommandInfo.CommandCallback Handler)> commands = new() 19 | { 20 | {config.Credits, ("Show credits", Command_Credits)}, 21 | {config.Store, ("Store menu", Command_Store)}, 22 | {config.Inventory, ("Open inventory menu", Command_Inv)}, 23 | {config.GiveCredits, ("Give credits", Command_GiveCredits)}, 24 | {config.Gift, ("Gift", Command_Gift)}, 25 | {config.ResetPlayer, ("Reset player's inventory", Command_ResetPlayer)}, 26 | {config.ResetDatabase, ("Reset database", Command_ResetDatabase)}, 27 | {config.RefreshPlayersCredits, ("Refresh players' credits", Command_RefreshPlayersCredits)} 28 | }; 29 | 30 | foreach ((IEnumerable<string> commandList, (string description, CommandInfo.CommandCallback handler)) in commands) 31 | { 32 | foreach (string command in commandList) 33 | { 34 | Instance.AddCommand($"css_{command}", description, handler); 35 | } 36 | } 37 | } 38 | 39 | [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_ONLY)] 40 | public static void Command_Credits(CCSPlayerController? player, CommandInfo command) 41 | { 42 | if (player == null) return; 43 | 44 | player.PrintToChatMessage("css_credits", Credits.Get(player)); 45 | } 46 | 47 | [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_ONLY)] 48 | public static void Command_Store(CCSPlayerController? player, CommandInfo command) 49 | { 50 | MenuBase.DisplayStoreMenu(player, false); 51 | } 52 | 53 | [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_ONLY)] 54 | public static void Command_Inv(CCSPlayerController? player, CommandInfo command) 55 | { 56 | MenuBase.DisplayStoreMenu(player, true); 57 | } 58 | 59 | [CommandHelper(minArgs: 2, "<name, #userid, all @ commands> <credits>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] 60 | [RequiresPermissions("@css/root")] 61 | public static void Command_GiveCredits(CCSPlayerController? player, CommandInfo command) 62 | { 63 | if (string.IsNullOrEmpty(Config.Permissions.GiveCredits) || !AdminManager.PlayerHasPermissions(player, Config.Permissions.GiveCredits)) 64 | return; 65 | 66 | if (!int.TryParse(command.GetArg(2), out int credits)) 67 | { 68 | command.ReplyToCommand($"{Config.Settings.Tag}{Instance.Localizer["Must be an integer"]}"); 69 | return; 70 | } 71 | 72 | TargetFind target = Find(command, false, true); 73 | 74 | if (string.IsNullOrEmpty(target.TargetName)) return; 75 | 76 | if (target.StorePlayer != null) 77 | { 78 | target.StorePlayer.Credits += credits; 79 | 80 | Database.ExecuteAsync("UPDATE store_players SET Credits = Credits + @Credits WHERE SteamId = @SteamId;", new { Credits = credits, SteamId = target.StorePlayer.SteamID }); 81 | 82 | Server.PrintToChatAll($"{Config.Settings.Tag}{Instance.Localizer["css_givecredits<steamid>", player?.PlayerName ?? "Console", target.TargetName, credits]}"); 83 | return; 84 | } 85 | 86 | foreach (CCSPlayerController targetPlayer in target.Players) 87 | { 88 | Credits.Give(targetPlayer, credits); 89 | } 90 | 91 | if (Config.Settings.EnableLog) 92 | { 93 | string giverName = player?.PlayerName ?? Instance.Localizer["Console"]; 94 | string giverLink = player == null ? Instance.Localizer["Console"] : $"https://steamcommunity.com/profiles/{player.SteamID}/"; 95 | string receiverName; 96 | string receiverLink; 97 | 98 | if (target.Players.Count > 1) 99 | { 100 | receiverName = $"@{target.TargetName}"; 101 | receiverLink = "0"; 102 | } 103 | else 104 | { 105 | CCSPlayerController Target = target.Players.First(); 106 | receiverName = Target.PlayerName; 107 | receiverLink = $"https://steamcommunity.com/profiles/{Target.SteamID}/"; 108 | } 109 | 110 | Log.SaveLog( 111 | giverName, 112 | giverLink, 113 | receiverName, 114 | receiverLink, 115 | credits, 116 | Log.LogType.GiveCredit 117 | ); 118 | } 119 | 120 | Server.PrintToChatAll($"{Config.Settings.Tag}{Instance.Localizer[target.Players.Count == 1 ? "css_givecredits<player>" : "css_givecredits<multiple>", player?.PlayerName ?? "Console", target.TargetName, credits]}"); 121 | } 122 | 123 | [CommandHelper(minArgs: 2, "<name, #userid> <credits>", whoCanExecute: CommandUsage.CLIENT_ONLY)] 124 | public static void Command_Gift(CCSPlayerController? player, CommandInfo command) 125 | { 126 | if (player == null) 127 | return; 128 | 129 | float currentTime = Server.CurrentTime; 130 | if (Instance.GlobalGiftTimeout.TryGetValue(player, out float time) && time > currentTime) 131 | { 132 | command.ReplyToCommand($"{Config.Settings.Tag}{Instance.Localizer["Gift timeout", Math.Ceiling(Instance.GlobalGiftTimeout[player] - Server.CurrentTime)]}"); 133 | return; 134 | } 135 | 136 | if (!int.TryParse(command.GetArg(2), out int value)) 137 | { 138 | command.ReplyToCommand($"{Config.Settings.Tag}{Instance.Localizer["Must be an integer"]}"); 139 | return; 140 | } 141 | 142 | if (value <= 0) 143 | { 144 | command.ReplyToCommand($"{Config.Settings.Tag}{Instance.Localizer["Must be higher than zero"]}"); 145 | return; 146 | } 147 | 148 | TargetFind target = Find(command, true, false); 149 | 150 | if (string.IsNullOrEmpty(target.TargetName)) return; 151 | 152 | CCSPlayerController targetPlayer = target.Players[0]; 153 | 154 | if (targetPlayer == player) 155 | { 156 | command.ReplyToCommand($"{Config.Settings.Tag}{Instance.Localizer["No gift yourself"]}"); 157 | return; 158 | } 159 | 160 | if (Credits.Get(player) < value) 161 | { 162 | player.PrintToChatMessage("No credits enough"); 163 | return; 164 | } 165 | 166 | Credits.Give(player, -value); 167 | Credits.Give(targetPlayer, value); 168 | 169 | if (Config.Settings.EnableLog) 170 | { 171 | Log.SaveLog( 172 | player.PlayerName, 173 | $"https://steamcommunity.com/profiles/{player.SteamID}/", 174 | targetPlayer.PlayerName, 175 | $"https://steamcommunity.com/profiles/{targetPlayer.SteamID}/", 176 | value, 177 | Log.LogType.GiftCredit 178 | ); 179 | } 180 | 181 | Instance.GlobalGiftTimeout[player] = currentTime + 5.0f; 182 | 183 | player.PrintToChatMessage("css_gift<player>", targetPlayer.PlayerName, value); 184 | targetPlayer.PrintToChatMessage("css_gift<target>", player.PlayerName, value); 185 | } 186 | 187 | [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.SERVER_ONLY)] 188 | public static void Command_ResetDatabase(CCSPlayerController? player, CommandInfo command) 189 | { 190 | if (player != null) return; 191 | 192 | Instance.GlobalStorePlayers.Clear(); 193 | Instance.GlobalStorePlayerItems.Clear(); 194 | Instance.GlobalStorePlayerEquipments.Clear(); 195 | 196 | Database.ResetDatabase(); 197 | 198 | foreach (CCSPlayerController target in Utilities.GetPlayers()) 199 | { 200 | Database.LoadPlayer(target); 201 | } 202 | } 203 | 204 | [CommandHelper(minArgs: 1, whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] 205 | [RequiresPermissions("@css/root")] 206 | public static void Command_ResetPlayer(CCSPlayerController? player, CommandInfo command) 207 | { 208 | TargetFind target = Find(command, true, true); 209 | 210 | if (string.IsNullOrEmpty(target.TargetName)) return; 211 | 212 | if (target.StorePlayer != null) 213 | { 214 | Instance.GlobalStorePlayers.RemoveAll(p => p.SteamID == target.StorePlayer.SteamID); 215 | Instance.GlobalStorePlayerItems.RemoveAll(p => p.SteamID == target.StorePlayer.SteamID); 216 | Instance.GlobalStorePlayerEquipments.RemoveAll(p => p.SteamID == target.StorePlayer.SteamID); 217 | 218 | Database.ExecuteAsync( 219 | $"DELETE FROM {Config.DatabaseConnection.StorePlayersName} WHERE SteamId = @SteamId; " + 220 | $"DELETE FROM {Config.DatabaseConnection.StoreItemsName} WHERE SteamId = @SteamId; " + 221 | $"DELETE FROM {Config.DatabaseConnection.StoreEquipments} WHERE SteamId = @SteamId;", 222 | new { target.StorePlayer.SteamID }); 223 | 224 | Server.PrintToChatAll($"{Config.Settings.Tag}{Instance.Localizer["css_reset", player?.PlayerName ?? "Console", target.StorePlayer.SteamID]}"); 225 | return; 226 | } 227 | 228 | CCSPlayerController targetPlayer = target.Players[0]; 229 | 230 | Credits.Set(targetPlayer, 0); 231 | Instance.GlobalStorePlayerItems.RemoveAll(p => p.SteamID == targetPlayer.SteamID); 232 | Instance.GlobalStorePlayerEquipments.RemoveAll(p => p.SteamID == targetPlayer.SteamID); 233 | 234 | Database.ResetPlayer(targetPlayer); 235 | 236 | Server.PrintToChatAll($"{Config.Settings.Tag}{Instance.Localizer["css_reset", player?.PlayerName ?? "Console", targetPlayer.PlayerName]}"); 237 | } 238 | 239 | [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] 240 | public static void Command_RefreshPlayersCredits(CCSPlayerController? player, CommandInfo info) 241 | { 242 | foreach (CCSPlayerController target in Utilities.GetPlayers()) 243 | { 244 | Database.SavePlayer(target); 245 | } 246 | 247 | Console.ForegroundColor = ConsoleColor.Cyan; 248 | Console.WriteLine($"{Config.Settings.Tag}{Instance.Localizer["Players' credits are refreshed"]}"); 249 | Console.ResetColor(); 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /Store/src/event/event.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Admin; 4 | using CounterStrikeSharp.API.Modules.Entities; 5 | using CounterStrikeSharp.API.Modules.Timers; 6 | using CounterStrikeSharp.API.Modules.Utils; 7 | using Store.Extension; 8 | using static CounterStrikeSharp.API.Core.Listeners; 9 | using static Store.Config_Config; 10 | using static Store.Store; 11 | using static StoreApi.Store; 12 | 13 | namespace Store; 14 | 15 | public static class Event 16 | { 17 | public static void Unload() 18 | { 19 | Instance.RemoveListener<OnMapStart>(OnMapStart); 20 | Instance.RemoveListener<OnServerPrecacheResources>(OnServerPrecacheResources); 21 | Instance.RemoveListener<OnTick>(OnTick); 22 | Instance.RemoveListener<OnEntityCreated>(OnEntityCreated); 23 | Instance.RemoveListener<OnClientAuthorized>(OnClientAuthorized); 24 | Instance.RemoveListener<CheckTransmit>(OnCheckTransmit); 25 | } 26 | 27 | public static void Load() 28 | { 29 | Instance.RegisterListener<OnMapStart>(OnMapStart); 30 | Instance.RegisterListener<OnServerPrecacheResources>(OnServerPrecacheResources); 31 | Instance.RegisterListener<OnTick>(OnTick); 32 | Instance.RegisterListener<OnEntityCreated>(OnEntityCreated); 33 | Instance.RegisterListener<OnClientAuthorized>(OnClientAuthorized); 34 | Instance.RegisterListener<CheckTransmit>(OnCheckTransmit); 35 | 36 | Instance.RegisterEventHandler<EventRoundStart>(OnRoundStart); 37 | Instance.RegisterEventHandler<EventPlayerConnectFull>(OnPlayerConnectFull); 38 | Instance.RegisterEventHandler<EventPlayerDisconnect>(OnPlayerDisconnect); 39 | Instance.RegisterEventHandler<EventPlayerDeath>(OnPlayerDeath); 40 | Instance.RegisterEventHandler<EventPlayerTeam>(OnPlayerTeam); 41 | 42 | Instance.AddTimer(5.0f, StartCreditsTimer); 43 | } 44 | 45 | private static void StartCreditsTimer() 46 | { 47 | if (!Config.Credits.TryGetValue("default", out Config_Credits? defaultCredits) || 48 | defaultCredits.IntervalActiveInActive <= 0) 49 | return; 50 | 51 | List<KeyValuePair<string, Config_Credits>> orderedCredits = Config.Credits 52 | .Where(x => x.Key != "default" && (x.Value.AmountActive > 0 || x.Value.AmountInActive > 0)) 53 | .ToList(); 54 | 55 | Instance.AddTimer(defaultCredits.IntervalActiveInActive, () => 56 | { 57 | if (GameRules.IgnoreWarmUp()) 58 | return; 59 | 60 | List<CCSPlayerController> players = Utilities.GetPlayers() 61 | .Where(p => !p.IsBot) 62 | .ToList(); 63 | 64 | foreach (CCSPlayerController player in players) 65 | { 66 | bool granted = orderedCredits.Where(credits => AdminManager.PlayerHasPermissions(player, credits.Key)).Any(credits => GiveCreditsTimer(player, credits.Value.AmountActive, credits.Value.AmountInActive)); 67 | 68 | if (!granted) 69 | { 70 | GiveCreditsTimer(player, defaultCredits.AmountActive, defaultCredits.AmountInActive); 71 | } 72 | } 73 | 74 | }, TimerFlags.REPEAT); 75 | } 76 | 77 | private static bool GiveCreditsTimer(CCSPlayerController player, int active, int inactive) 78 | { 79 | switch (player.Team) 80 | { 81 | case CsTeam.Terrorist: 82 | case CsTeam.CounterTerrorist when active > 0: 83 | Credits.Give(player, active); 84 | player.PrintToChatMessage("credits_earned<active>", active); 85 | return true; 86 | case CsTeam.Spectator when inactive > 0: 87 | Credits.Give(player, inactive); 88 | player.PrintToChatMessage("credits_earned<inactive>", inactive); 89 | return true; 90 | case CsTeam.None: 91 | default: return false; 92 | } 93 | } 94 | 95 | 96 | public static void OnMapStart(string mapname) 97 | { 98 | foreach (var module in ItemModuleManager.Modules) 99 | { 100 | module.Value.OnMapStart(); 101 | } 102 | } 103 | 104 | public static void OnServerPrecacheResources(ResourceManifest manifest) 105 | { 106 | foreach (string? model in Config.DefaultModels.CounterTerrorist.Concat(Config.DefaultModels.Terrorist)) 107 | { 108 | manifest.AddResource(model); 109 | } 110 | 111 | foreach (var module in ItemModuleManager.Modules) 112 | { 113 | module.Value.OnServerPrecacheResources(manifest); 114 | } 115 | } 116 | 117 | public static void OnTick() 118 | { 119 | List<CCSPlayerController> players = Utilities.GetPlayers(); 120 | 121 | foreach (CCSPlayerController player in players) 122 | { 123 | if (!player.PawnIsAlive) continue; 124 | 125 | Item_Bunnyhop.OnTick(player); 126 | } 127 | 128 | Instance.GlobalTickrate++; 129 | 130 | if (Instance.GlobalTickrate % 10 != 0) return; 131 | 132 | Instance.GlobalTickrate = 0; 133 | 134 | foreach (CCSPlayerController player in players) 135 | { 136 | Item_Trail.OnTick(player); 137 | Item_ColoredSkin.OnTick(player); 138 | } 139 | } 140 | 141 | public static void OnEntityCreated(CEntityInstance entity) 142 | { 143 | Item_Smoke.OnEntityCreated(entity); 144 | Item_GrenadeTrail.OnEntityCreated(entity); 145 | //Item_CustomWeapon.OnEntityCreated(entity); 146 | } 147 | 148 | private static void OnClientAuthorized(int playerSlot, SteamID steamId) 149 | { 150 | CCSPlayerController? player = Utilities.GetPlayerFromSlot(playerSlot); 151 | 152 | if (player == null) return; 153 | 154 | Database.LoadPlayer(player); 155 | } 156 | 157 | public static HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) 158 | { 159 | Item.RemoveExpiredItems(); 160 | return HookResult.Continue; 161 | } 162 | 163 | public static HookResult OnPlayerConnectFull(EventPlayerConnectFull @event, GameEventInfo info) 164 | { 165 | CCSPlayerController? player = @event.Userid; 166 | 167 | if (player == null) return HookResult.Continue; 168 | 169 | if (!Instance.GlobalDictionaryPlayer.ContainsKey(player)) 170 | { 171 | Instance.GlobalDictionaryPlayer[player] = new PlayerTimer(); 172 | } 173 | 174 | Instance.GlobalGiftTimeout[player] = 0; 175 | 176 | Database.UpdateVip(player); 177 | 178 | return HookResult.Continue; 179 | } 180 | 181 | public static HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info) 182 | { 183 | CCSPlayerController? player = @event.Userid; 184 | 185 | if (player == null) return HookResult.Continue; 186 | 187 | Item_Trail.HideTrailPlayerList.Remove(player); 188 | 189 | if (Instance.GlobalDictionaryPlayer.TryGetValue(player, out PlayerTimer? value)) 190 | { 191 | value.CreditIntervalTimer?.Kill(); 192 | } 193 | 194 | Database.SavePlayer(player); 195 | 196 | Instance.GlobalStorePlayers.RemoveAll(p => p.SteamID == player.SteamID); 197 | Instance.GlobalStorePlayerItems.RemoveAll(i => i.SteamID == player.SteamID); 198 | Instance.GlobalStorePlayerEquipments.RemoveAll(e => e.SteamID == player.SteamID); 199 | Instance.GlobalGiftTimeout.Remove(player); 200 | 201 | return HookResult.Continue; 202 | } 203 | 204 | public static HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) 205 | { 206 | if (GameRules.IgnoreWarmUp()) return HookResult.Continue; 207 | 208 | CCSPlayerController? victim = @event.Userid; 209 | CCSPlayerController? attacker = @event.Attacker; 210 | 211 | if (victim == null || attacker == null || victim == attacker) return HookResult.Continue; 212 | 213 | Server.NextFrame(() => Database.SavePlayer(victim)); 214 | 215 | int amountKill = 0; 216 | 217 | KeyValuePair<string, Config_Credits> credits = Config.Credits 218 | .Where(x => x.Key != "default" && x.Value.AmountKill > 0) 219 | .FirstOrDefault(x => AdminManager.PlayerHasPermissions(attacker, x.Key)); 220 | 221 | if (credits.Value is not null) 222 | { 223 | amountKill = credits.Value.AmountKill; 224 | } 225 | 226 | if (amountKill <= 0 && Config.Credits.TryGetValue("default", out Config_Credits? defaultCredits)) 227 | { 228 | amountKill = defaultCredits.AmountKill; 229 | } 230 | 231 | if (amountKill > 0) 232 | { 233 | Credits.Give(attacker, amountKill); 234 | attacker.PrintToChat($"{Config.Settings.Tag}{Instance.Localizer["credits_earned<kill>", amountKill]}"); 235 | } 236 | 237 | return HookResult.Continue; 238 | } 239 | 240 | public static HookResult OnPlayerTeam(EventPlayerTeam @event, GameEventInfo info) 241 | { 242 | CCSPlayerController? player = @event.Userid; 243 | 244 | if (player == null) return HookResult.Continue; 245 | 246 | List<Store_Equipment> currentItems = Instance.GlobalStorePlayerEquipments.FindAll(p => p.SteamID == player.SteamID); 247 | 248 | foreach (Store_Equipment currentItem in currentItems) 249 | { 250 | Dictionary<string, string>? item = Item.GetItem(currentItem.UniqueId); 251 | 252 | if (item == null) continue; 253 | 254 | if (item.TryGetValue("team", out string? teamStr) && int.TryParse(teamStr, out int team) && team >= 1 && team <= 3 && @event.Team != team) 255 | { 256 | Item.Unequip(player, item, true); 257 | } 258 | } 259 | 260 | return HookResult.Continue; 261 | } 262 | 263 | public static void OnCheckTransmit(CCheckTransmitInfoList infoList) 264 | { 265 | if (Instance.InspectList.Count == 0 && Item_Trail.TrailList.Count == 0) 266 | return; 267 | 268 | foreach ((CCheckTransmitInfo info, CCSPlayerController? player) in infoList) 269 | { 270 | if (player is not { IsValid: true, IsBot: false }) 271 | continue; 272 | 273 | ulong playerSteamId = player.SteamID; 274 | 275 | foreach ((CBaseModelEntity? entity, CCSPlayerController? owner) in Instance.InspectList) 276 | { 277 | if (owner.IsValid && owner.SteamID != playerSteamId) 278 | info.TransmitEntities.Remove(entity); 279 | } 280 | 281 | if (!Item_Trail.HideTrailPlayerList.Contains(player)) 282 | continue; 283 | 284 | foreach ((CEntityInstance? entity, CCSPlayerController? owner) in Item_Trail.TrailList) 285 | { 286 | if (owner.IsValid && owner.SteamID != playerSteamId) 287 | info.TransmitEntities.Remove(entity); 288 | } 289 | } 290 | } 291 | } -------------------------------------------------------------------------------- /Store/src/item/item.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Core.Translations; 4 | using CounterStrikeSharp.API.Modules.Admin; 5 | using CounterStrikeSharp.API.Modules.Utils; 6 | using Store.Extension; 7 | using System.Text.Json; 8 | using static Store.Config_Config; 9 | using static Store.Store; 10 | using static StoreApi.Store; 11 | 12 | namespace Store; 13 | 14 | public static class Item 15 | { 16 | public static bool IsHidden(this Dictionary<string, string> item) 17 | { 18 | return item.ContainsKey("hide") && item["hide"] == "true"; 19 | } 20 | 21 | public static string GetItemName(CCSPlayerController player, Dictionary<string, string> item) 22 | { 23 | string name = item["name"]; 24 | 25 | return name.StartsWith('*') && name.EndsWith('*') ? Instance.Localizer.ForPlayer(player, name) : name; 26 | } 27 | 28 | public static bool Give(CCSPlayerController player, Dictionary<string, string> item) 29 | { 30 | if (!ItemModuleManager.Modules.TryGetValue(item["type"], out IItemModule? type)) 31 | { 32 | player.PrintToChatMessage("No type found", item["type"]); 33 | return false; 34 | } 35 | 36 | if (!type.Equipable && !type.OnEquip(player, item)) return false; 37 | 38 | if (type.Equipable) 39 | { 40 | item.TryGetValue("expiration", out string? expirationtime); 41 | int expiration = Convert.ToInt32(expirationtime); 42 | 43 | Store_Item playerItem = new() 44 | { 45 | SteamID = player.SteamID, 46 | Price = int.Parse(item["price"]), 47 | Type = item["type"], 48 | UniqueId = item["uniqueid"], 49 | DateOfPurchase = DateTime.Now, 50 | DateOfExpiration = expiration <= 0 ? DateTime.MinValue : DateTime.Now.AddSeconds(expiration) 51 | }; 52 | 53 | Instance.GlobalStorePlayerItems.Add(playerItem); 54 | Server.NextFrame(() => Database.SavePlayerItem(player, playerItem)); 55 | } 56 | else 57 | { 58 | return false; 59 | } 60 | 61 | return true; 62 | } 63 | 64 | public static bool CanBuy(CCSPlayerController player, Dictionary<string, string> item) 65 | { 66 | if (Credits.Get(player) < int.Parse(item["price"])) 67 | return false; 68 | 69 | if (!ItemModuleManager.Modules.TryGetValue(item["type"], out IItemModule? type)) 70 | return false; 71 | 72 | if (type.RequiresAlive == true && !player.PawnIsAlive) 73 | return false; 74 | 75 | else if (type.RequiresAlive == false && player.PawnIsAlive) 76 | return false; 77 | 78 | if (!type.Equipable) 79 | { 80 | if (item.TryGetValue("team", out string? steam) && int.TryParse(steam, out int team) && team >= 1 && team <= 3 && player.TeamNum != team) 81 | return false; 82 | } 83 | 84 | return true; 85 | } 86 | 87 | public static bool Purchase(CCSPlayerController player, Dictionary<string, string> item) 88 | { 89 | if (Credits.Get(player) < int.Parse(item["price"])) 90 | { 91 | player.PrintToChatMessage("No credits enough"); 92 | return false; 93 | } 94 | 95 | if (!ItemModuleManager.Modules.TryGetValue(item["type"], out IItemModule? type)) 96 | { 97 | player.PrintToChatMessage("No type found", item["type"]); 98 | return false; 99 | } 100 | 101 | if (type.RequiresAlive == true && !player.PawnIsAlive) 102 | { 103 | player.PrintToChatMessage("You are not alive"); 104 | return false; 105 | } 106 | else if (type.RequiresAlive == false && player.PawnIsAlive) 107 | { 108 | player.PrintToChatMessage("You are alive"); 109 | return false; 110 | } 111 | 112 | if (!type.Equipable) 113 | { 114 | if (item.TryGetValue("team", out string? steam) && int.TryParse(steam, out int team) && team >= 1 && team <= 3 && player.TeamNum != team) 115 | { 116 | player.PrintToChatMessage("No purchase because team", (CsTeam)team); 117 | return false; 118 | } 119 | 120 | if (!type.OnEquip(player, item)) 121 | return false; 122 | } 123 | 124 | int price = int.Parse(item["price"]); 125 | if (price > 0) 126 | { 127 | Credits.Give(player, -price); 128 | player.PrintToChatMessage("Purchase Succeeded", GetItemName(player, item)); 129 | } 130 | 131 | Store.Api.PlayerPurchaseItem(player, item); 132 | 133 | if (type.Equipable) 134 | { 135 | item.TryGetValue("expiration", out string? expirationtime); 136 | int expiration = Convert.ToInt32(expirationtime); 137 | 138 | Store_Item playerItem = new() 139 | { 140 | SteamID = player.SteamID, 141 | Price = price, 142 | Type = item["type"], 143 | UniqueId = item["uniqueid"], 144 | DateOfPurchase = DateTime.Now, 145 | DateOfExpiration = expiration <= 0 ? DateTime.MinValue : DateTime.Now.AddSeconds(expiration) 146 | }; 147 | 148 | Instance.GlobalStorePlayerItems.Add(playerItem); 149 | Store.Api.PlayerEquipItem(player, item); 150 | Server.NextFrame(() => Database.SavePlayerItem(player, playerItem)); 151 | } 152 | else return false; 153 | 154 | return true; 155 | } 156 | 157 | public static bool Equip(CCSPlayerController player, Dictionary<string, string> item) 158 | { 159 | string itemType = item["type"]; 160 | 161 | if (!ItemModuleManager.Modules.TryGetValue(itemType, out IItemModule? type)) 162 | return false; 163 | 164 | if (item.TryGetValue("team", out string? steam) && int.TryParse(steam, out int team) && team >= 1 && team <= 3 && player.TeamNum != team) 165 | { 166 | player.PrintToChatMessage("No equip because team", (CsTeam)team); 167 | return false; 168 | } 169 | 170 | List<Store_Equipment> currentItems = GetConflictingItems(player, item, itemType); 171 | 172 | foreach (Store_Equipment currentItem in currentItems) 173 | { 174 | Dictionary<string, string>? citem = GetItem(currentItem.UniqueId); 175 | if (citem != null) Unequip(player, citem, false); 176 | } 177 | 178 | if (!type.OnEquip(player, item)) return false; 179 | 180 | int slot = item.TryGetValue("slot", out string? sslot) && int.TryParse(sslot, out int islot) ? islot : 0; 181 | 182 | Store_Equipment playerItem = new() 183 | { 184 | SteamID = player.SteamID, 185 | Type = itemType, 186 | UniqueId = item["uniqueid"], 187 | Slot = slot 188 | }; 189 | 190 | Instance.GlobalStorePlayerEquipments.Add(playerItem); 191 | Store.Api.PlayerEquipItem(player, item); 192 | Server.NextFrame(() => Database.SavePlayerEquipment(player, playerItem)); 193 | 194 | return true; 195 | } 196 | 197 | private static List<Store_Equipment> GetConflictingItems(CCSPlayerController player, Dictionary<string, string> item, string itemType) 198 | { 199 | return itemType switch 200 | { 201 | "playerskin" => [.. Instance.GlobalStorePlayerEquipments.FindAll(p => 202 | p.SteamID == player.SteamID && 203 | p.Type == itemType && 204 | (p.Slot == int.Parse(item["slot"]) || (item["slot"] == "1" || p.Slot == 1)))], 205 | 206 | "customweapon" => [.. Instance.GlobalStorePlayerEquipments.FindAll(p => 207 | { 208 | if (p.SteamID != player.SteamID || p.Type != itemType) 209 | return false; 210 | 211 | Dictionary<string, string>? equippedItem = GetItem(p.UniqueId); 212 | return equippedItem != null && 213 | equippedItem.TryGetValue("weapon", out string? equippedWeapon) && 214 | item.TryGetValue("weapon", out string? newWeapon) && 215 | equippedWeapon == newWeapon; 216 | })], 217 | 218 | "equipment" => [.. Instance.GlobalStorePlayerEquipments.FindAll(p => 219 | p.SteamID == player.SteamID && 220 | p.Type == itemType && 221 | p.Slot == int.Parse(item["slot"]))], 222 | 223 | _ => [.. Instance.GlobalStorePlayerEquipments.FindAll(p => 224 | p.SteamID == player.SteamID && 225 | p.Type == itemType && 226 | p.Slot == int.Parse(item["slot"]))] 227 | }; 228 | } 229 | 230 | public static bool Unequip(CCSPlayerController player, Dictionary<string, string> item, bool update) 231 | { 232 | if (!ItemModuleManager.Modules.TryGetValue(item["type"], out IItemModule? type)) 233 | return false; 234 | 235 | Store_Equipment? equippedItem = Instance.GlobalStorePlayerEquipments.FirstOrDefault(p => p.SteamID == player.SteamID && p.UniqueId == item["uniqueid"]); 236 | if (equippedItem == null) return false; 237 | 238 | Instance.GlobalStorePlayerEquipments.Remove(equippedItem); 239 | Store.Api.PlayerUnequipItem(player, item); 240 | Server.NextFrame(() => Database.RemovePlayerEquipment(player, item["uniqueid"])); 241 | 242 | return type.OnUnequip(player, item, update); 243 | } 244 | 245 | public static bool Sell(CCSPlayerController player, Dictionary<string, string> item) 246 | { 247 | Store_Item? playerItem = Instance.GlobalStorePlayerItems.FirstOrDefault(p => p.SteamID == player.SteamID && p.UniqueId == item["uniqueid"]); 248 | if (playerItem == null) return false; 249 | 250 | Credits.Give(player, (int)(playerItem.Price * Config.Settings.SellRatio)); 251 | Unequip(player, item, true); 252 | Instance.GlobalStorePlayerItems.Remove(playerItem); 253 | Store.Api.PlayerSellItem(player, item); 254 | Server.NextFrame(() => Database.RemovePlayerItem(player, playerItem)); 255 | 256 | return true; 257 | } 258 | 259 | public static bool PlayerHas(CCSPlayerController player, string type, string uniqueId, bool ignoreVip) 260 | { 261 | Dictionary<string, string>? item = GetItem(uniqueId); 262 | if (item == null) return false; 263 | 264 | if (!ItemModuleManager.Modules.TryGetValue(item["type"], out IItemModule? moduletype)) 265 | return false; 266 | 267 | if (moduletype.Equipable == false) return false; 268 | 269 | if (!ignoreVip && IsPlayerVip(player)) return true; 270 | 271 | item.TryGetValue("flag", out string? flag); 272 | return MenuBase.CheckFlag(player, flag, false) || Instance.GlobalStorePlayerItems.Any(p => p.SteamID == player.SteamID && p.Type == type && p.UniqueId == uniqueId); 273 | } 274 | 275 | public static bool PlayerUsing(CCSPlayerController player, string type, string uniqueId) 276 | { 277 | return Instance.GlobalStorePlayerEquipments.Any(p => p.SteamID == player.SteamID && p.Type == type && p.UniqueId == uniqueId); 278 | } 279 | 280 | public static bool IsInJson(string uniqueId) 281 | { 282 | return Instance.Items.ContainsKey(uniqueId); 283 | } 284 | 285 | public static Dictionary<string, string>? GetItem(string uniqueId) 286 | { 287 | return Instance.Items.TryGetValue(uniqueId, out Dictionary<string, string>? item) ? item : null; 288 | } 289 | 290 | public static bool IsAnyItemExistInType(string type) 291 | { 292 | return Instance.Items.Any(kvp => kvp.Value["type"] == type); 293 | } 294 | 295 | public static bool IsAnyItemExistInTypes(string[] type) 296 | { 297 | return Instance.Items.Any(kvp => type.Contains(kvp.Value["type"])); 298 | } 299 | 300 | public static List<KeyValuePair<string, Dictionary<string, string>>> GetItemsByType(string type) 301 | { 302 | return [.. Instance.Items.Where(kvp => kvp.Value["type"] == type)]; 303 | } 304 | 305 | public static List<Store_Item> GetPlayerItems(CCSPlayerController player, string? type) 306 | { 307 | return [.. Instance.GlobalStorePlayerItems.Where(item => item.SteamID == player.SteamID && (type == null || type == item.Type))]; 308 | } 309 | 310 | public static List<Store_Equipment> GetPlayerEquipments(CCSPlayerController player, string? type) 311 | { 312 | return [.. Instance.GlobalStorePlayerEquipments.Where(item => item.SteamID == player.SteamID && (type == null || type == item.Type))]; 313 | } 314 | 315 | public static bool IsPlayerVip(CCSPlayerController player) 316 | { 317 | return !string.IsNullOrEmpty(Config.Menu.VipFlag) && AdminManager.PlayerHasPermissions(player, Config.Menu.VipFlag); 318 | } 319 | 320 | public static bool PlayerHasAny(CCSPlayerController player, JsonElement item) 321 | { 322 | return item.ExtractItems().Values.Any(item => PlayerHas(player, item["type"], item["uniqueid"], false)); 323 | } 324 | 325 | public static void RemoveExpiredItems() 326 | { 327 | Database.ExecuteAsync($"DELETE FROM {Config.DatabaseConnection.StoreItemsName} WHERE DateOfExpiration < NOW() AND DateOfExpiration > '0001-01-01 00:00:00';", null); 328 | 329 | List<Store_Item> itemsToRemove = [.. Instance.GlobalStorePlayerItems.Where(item => item.DateOfExpiration < DateTime.Now && item.DateOfExpiration > DateTime.MinValue)]; 330 | 331 | string storeEquipmentTableName = Config.DatabaseConnection.StoreEquipments; 332 | 333 | foreach (Store_Item? item in itemsToRemove) 334 | { 335 | Database.ExecuteAsync($"DELETE FROM {storeEquipmentTableName} WHERE SteamID = @SteamID AND UniqueId = @UniqueId", new { item.SteamID, item.UniqueId }); 336 | 337 | Instance.GlobalStorePlayerItems.Remove(item); 338 | Instance.GlobalStorePlayerEquipments.RemoveAll(i => i.UniqueId == item.UniqueId); 339 | } 340 | } 341 | } --------------------------------------------------------------------------------