mirror of
https://github.com/daffyyyy/CS2-SimpleAdmin.git
synced 2026-02-18 02:41:55 +00:00
Refactor fun commands to external module
Commented out fun command implementations (noclip, godmode, freeze, unfreeze, resize) in funcommands.cs and removed their registration from RegisterCommands.cs. These commands are now intended to be provided by the new CS2-SimpleAdmin_FunCommands external module, improving modularity and maintainability.
This commit is contained in:
BIN
Modules/CS2-SimpleAdmin_FunCommands/CS2-SimpleAdminApi.dll
Normal file
BIN
Modules/CS2-SimpleAdmin_FunCommands/CS2-SimpleAdminApi.dll
Normal file
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS2-SimpleAdmin_FunCommands", "CS2-SimpleAdmin_FunCommands\CS2-SimpleAdmin_FunCommands.csproj", "{72713A40-688F-401F-8211-3D28B068C791}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{72713A40-688F-401F-8211-3D28B068C791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{72713A40-688F-401F-8211-3D28B068C791}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{72713A40-688F-401F-8211-3D28B068C791}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{72713A40-688F-401F-8211-3D28B068C791}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,237 @@
|
||||
using System.Globalization;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CS2_SimpleAdmin_FunCommands;
|
||||
|
||||
public partial class CS2_SimpleAdmin_FunCommands
|
||||
{
|
||||
private void God(CCSPlayerController? caller, CCSPlayerController player)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
var callerName = caller?.PlayerName ?? "Console";
|
||||
|
||||
// Toggle god mode for the player (like in main plugin)
|
||||
if (!GodPlayers.Add(player.Slot))
|
||||
{
|
||||
GodPlayers.Remove(player.Slot);
|
||||
}
|
||||
|
||||
// Show admin activity using module's own localizer with per-player language support
|
||||
var activityArgs = new object[] { "CALLER", player.PlayerName };
|
||||
if (caller == null || !_sharedApi!.IsAdminSilent(caller))
|
||||
{
|
||||
if (Localizer != null)
|
||||
{
|
||||
_sharedApi!.ShowAdminActivityLocalized(Localizer, "fun_admin_god_message", callerName, false,
|
||||
activityArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sharedApi!.ShowAdminActivity("fun_admin_god_message", callerName, false, activityArgs);
|
||||
}
|
||||
}
|
||||
|
||||
// Log command using API
|
||||
_sharedApi!.LogCommand(caller,
|
||||
$"css_god {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
}
|
||||
|
||||
private void NoClip(CCSPlayerController? caller, CCSPlayerController player)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
var callerName = caller?.PlayerName ?? "Console";
|
||||
|
||||
// Toggle no-clip mode using PlayerExtensions
|
||||
player.Pawn.Value?.ToggleNoclip();
|
||||
|
||||
// Show admin activity using module's own localizer with per-player language support
|
||||
var activityArgs = new object[] { "CALLER", player.PlayerName };
|
||||
if (caller == null || !_sharedApi!.IsAdminSilent(caller))
|
||||
{
|
||||
if (Localizer != null)
|
||||
{
|
||||
_sharedApi!.ShowAdminActivityLocalized(Localizer, "fun_admin_noclip_message", callerName, false,
|
||||
activityArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sharedApi!.ShowAdminActivity("fun_admin_noclip_message", callerName, false, activityArgs);
|
||||
}
|
||||
}
|
||||
|
||||
// Log command using API
|
||||
_sharedApi!.LogCommand(caller,
|
||||
$"css_noclip {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
}
|
||||
|
||||
private void Freeze(CCSPlayerController? caller, CCSPlayerController player, int time)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
var callerName = caller?.PlayerName ?? "Console";
|
||||
|
||||
// Freeze player using PlayerExtensions
|
||||
player.Pawn.Value?.Freeze();
|
||||
|
||||
// Show admin activity using module's own localizer with per-player language support
|
||||
var activityArgs = new object[] { "CALLER", player.PlayerName };
|
||||
if (caller == null || !_sharedApi!.IsAdminSilent(caller))
|
||||
{
|
||||
if (Localizer != null)
|
||||
{
|
||||
_sharedApi!.ShowAdminActivityLocalized(Localizer, "fun_admin_freeze_message", callerName, false,
|
||||
activityArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sharedApi!.ShowAdminActivity("fun_admin_freeze_message", callerName, false, activityArgs);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-unfreeze after duration
|
||||
if (time > 0)
|
||||
{
|
||||
AddTimer(time, () => player.Pawn.Value?.Unfreeze(),
|
||||
CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
// Log command using API
|
||||
_sharedApi!.LogCommand(caller,
|
||||
$"css_freeze {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {time}");
|
||||
}
|
||||
|
||||
private void Unfreeze(CCSPlayerController? caller, CCSPlayerController player)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
var callerName = caller?.PlayerName ?? "Console";
|
||||
|
||||
// Unfreeze player using PlayerExtensions
|
||||
player.Pawn.Value?.Unfreeze();
|
||||
|
||||
// Show admin activity using module's own localizer with per-player language support
|
||||
var activityArgs = new object[] { "CALLER", player.PlayerName };
|
||||
if (caller == null || !_sharedApi!.IsAdminSilent(caller))
|
||||
{
|
||||
if (Localizer != null)
|
||||
{
|
||||
_sharedApi!.ShowAdminActivityLocalized(Localizer, "fun_admin_unfreeze_message", callerName, false,
|
||||
activityArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sharedApi!.ShowAdminActivity("fun_admin_unfreeze_message", callerName, false, activityArgs);
|
||||
}
|
||||
}
|
||||
|
||||
// Log command using API
|
||||
_sharedApi!.LogCommand(caller,
|
||||
$"css_unfreeze {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Respawns a player and teleports them to their last death position if available.
|
||||
/// This demonstrates using the GetPlayerInfo API to access player data.
|
||||
/// </summary>
|
||||
private void Respawn(CCSPlayerController? caller, CCSPlayerController player)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
var callerName = caller?.PlayerName ?? "Console";
|
||||
|
||||
// Respawn the player
|
||||
player.Respawn();
|
||||
|
||||
// Get death position from API and teleport player to it
|
||||
// BEST PRACTICE: Use API to access player data like death position
|
||||
if (_sharedApi != null && player.UserId.HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var playerInfo = _sharedApi.GetPlayerInfo(player);
|
||||
|
||||
// Teleport to death position if available
|
||||
if (playerInfo?.DiePosition != null && player.PlayerPawn?.Value != null)
|
||||
{
|
||||
player.PlayerPawn.Value.Teleport(
|
||||
playerInfo.DiePosition.Position,
|
||||
playerInfo.DiePosition.Angle);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning($"Failed to get player info for respawn: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Show admin activity using module's own localizer with per-player language support
|
||||
var activityArgs = new object[] { "CALLER", player.PlayerName };
|
||||
if (caller == null || !_sharedApi!.IsAdminSilent(caller))
|
||||
{
|
||||
if (Localizer != null)
|
||||
{
|
||||
_sharedApi!.ShowAdminActivityLocalized(Localizer, "fun_admin_respawn_message", callerName, false,
|
||||
activityArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sharedApi!.ShowAdminActivity("fun_admin_respawn_message", callerName, false, activityArgs);
|
||||
}
|
||||
}
|
||||
|
||||
// Log command using API
|
||||
_sharedApi!.LogCommand(caller,
|
||||
$"css_respawn {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resizes a player's model to the specified scale.
|
||||
/// </summary>
|
||||
private void Resize(CCSPlayerController? caller, CCSPlayerController player, float size)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
var callerName = caller?.PlayerName ?? "Console";
|
||||
|
||||
// Resize the player
|
||||
var sceneNode = player.PlayerPawn.Value!.CBodyComponent?.SceneNode;
|
||||
if (sceneNode != null)
|
||||
{
|
||||
sceneNode.GetSkeletonInstance().Scale = size;
|
||||
player.PlayerPawn.Value.AcceptInput("SetScale", null, null, size.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
Server.NextWorldUpdate(() =>
|
||||
{
|
||||
Utilities.SetStateChanged(player.PlayerPawn.Value, "CBaseEntity", "m_CBodyComponent");
|
||||
});
|
||||
}
|
||||
|
||||
// Show admin activity using module's own localizer with per-player language support
|
||||
var activityArgs = new object[] { "CALLER", player.PlayerName, size.ToString(CultureInfo.InvariantCulture) };
|
||||
if (caller == null || !_sharedApi!.IsAdminSilent(caller))
|
||||
{
|
||||
if (Localizer != null)
|
||||
{
|
||||
_sharedApi!.ShowAdminActivityLocalized(Localizer, "fun_admin_resize_message", callerName, false,
|
||||
activityArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sharedApi!.ShowAdminActivity("fun_admin_resize_message", callerName, false, activityArgs);
|
||||
}
|
||||
}
|
||||
|
||||
// Log command using API
|
||||
_sharedApi!.LogCommand(caller,
|
||||
$"css_resize {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {size}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Capabilities;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using CS2_SimpleAdminApi;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Globalization;
|
||||
|
||||
namespace CS2_SimpleAdmin_FunCommands;
|
||||
|
||||
/// <summary>
|
||||
/// CS2-SimpleAdmin Fun Commands Module
|
||||
///
|
||||
/// This module serves as a REFERENCE IMPLEMENTATION for creating CS2-SimpleAdmin modules.
|
||||
/// Study this code to learn best practices for:
|
||||
/// - Command registration from configuration
|
||||
/// - Menu creation with SimpleAdmin API
|
||||
/// - Per-player translation support
|
||||
/// - Proper cleanup on module unload
|
||||
/// - Code organization using partial classes
|
||||
///
|
||||
/// File Structure:
|
||||
/// - CS2-SimpleAdmin_FunCommands.cs (this file) - Plugin initialization and registration
|
||||
/// - Commands.cs - Command handlers
|
||||
/// - Actions.cs - Action methods (God, NoClip, Freeze, etc.)
|
||||
/// - Menus.cs - Menu creation
|
||||
/// - Config.cs - Configuration with command lists
|
||||
/// - lang/ - Translation files (13 languages)
|
||||
///
|
||||
/// See README.md for detailed explanation of all patterns demonstrated here.
|
||||
/// </summary>
|
||||
public partial class CS2_SimpleAdmin_FunCommands : BasePlugin, IPluginConfig<Config>
|
||||
{
|
||||
public Config Config { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// BEST PRACTICE: Cache expensive operations
|
||||
/// Weapons enum values don't change, so we cache them on first access
|
||||
/// </summary>
|
||||
private static Dictionary<int, CsItem>? _weaponsCache;
|
||||
private static Dictionary<int, CsItem> GetWeaponsCache()
|
||||
{
|
||||
if (_weaponsCache != null) return _weaponsCache;
|
||||
|
||||
var weaponsArray = Enum.GetValues(typeof(CsItem));
|
||||
_weaponsCache = new Dictionary<int, CsItem>();
|
||||
|
||||
foreach (CsItem item in weaponsArray)
|
||||
{
|
||||
if (item == CsItem.Tablet) continue; // Skip tablet (invalid weapon)
|
||||
_weaponsCache[(int)item] = item;
|
||||
}
|
||||
|
||||
return _weaponsCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Track players with god mode enabled
|
||||
/// HashSet for O(1) lookup performance
|
||||
/// </summary>
|
||||
private static readonly HashSet<int> GodPlayers = [];
|
||||
|
||||
/// <summary>
|
||||
/// Track players with modified speed
|
||||
/// Dictionary for storing speed values per player
|
||||
/// </summary>
|
||||
private static readonly Dictionary<CCSPlayerController, float> SpeedPlayers = [];
|
||||
|
||||
/// <summary>
|
||||
/// Track players with modified gravity
|
||||
/// Dictionary for storing gravity values per player
|
||||
/// </summary>
|
||||
private static readonly Dictionary<CCSPlayerController, float> GravityPlayers = [];
|
||||
|
||||
/// <summary>
|
||||
/// BEST PRACTICE: Use capability system to get SimpleAdmin API
|
||||
/// This ensures your module works even if SimpleAdmin loads after your module
|
||||
/// </summary>
|
||||
private ICS2_SimpleAdminApi? _sharedApi;
|
||||
private readonly PluginCapability<ICS2_SimpleAdminApi> _pluginCapability = new("simpleadmin:api");
|
||||
|
||||
/// <summary>
|
||||
/// BEST PRACTICE: Track menu registration state to prevent duplicate registrations
|
||||
/// </summary>
|
||||
private bool _menusRegistered = false;
|
||||
|
||||
// Plugin metadata
|
||||
public override string ModuleName => "CS2-SimpleAdmin Fun Commands";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
public override string ModuleAuthor => "Your Name";
|
||||
public override string ModuleDescription => "Fun commands extension for CS2-SimpleAdmin";
|
||||
|
||||
/// <summary>
|
||||
/// BEST PRACTICE: Initialize plugin after all plugins are loaded
|
||||
/// This ensures SimpleAdmin API is available
|
||||
/// </summary>
|
||||
public override void OnAllPluginsLoaded(bool hotReload)
|
||||
{
|
||||
// STEP 1: Get SimpleAdmin API using capability system
|
||||
_sharedApi = _pluginCapability.Get();
|
||||
if (_sharedApi == null)
|
||||
{
|
||||
Logger.LogError("CS2-SimpleAdmin API not found - make sure CS2-SimpleAdmin is loaded!");
|
||||
Unload(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// STEP 2: Register commands (can be done immediately)
|
||||
RegisterFunCommands();
|
||||
|
||||
// STEP 3: Register menus (wait for SimpleAdmin to be ready)
|
||||
// BEST PRACTICE: Use event + fallback to handle both normal load and hot reload
|
||||
_sharedApi.OnSimpleAdminReady += RegisterFunMenus;
|
||||
RegisterFunMenus(); // Fallback for hot reload case
|
||||
|
||||
// STEP 4: Start timer to maintain speed and gravity modifications
|
||||
StartSpeedGravityTimer();
|
||||
}
|
||||
|
||||
public override void Unload(bool hotReload)
|
||||
{
|
||||
if (_sharedApi == null) return;
|
||||
|
||||
// Unregister commands
|
||||
if (Config.NoclipCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.NoclipCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.GodCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.GodCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.FreezeCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.FreezeCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.UnfreezeCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.UnfreezeCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.RespawnCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.RespawnCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.GiveCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.GiveCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.StripCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.StripCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.HpCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.HpCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.SpeedCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.SpeedCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.GravityCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.GravityCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.MoneyCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.MoneyCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.ResizeCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.ResizeCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
// Unregister menus
|
||||
if (Config.NoclipCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "noclip");
|
||||
|
||||
if (Config.GodCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "god");
|
||||
|
||||
if (Config.RespawnCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "respawn");
|
||||
|
||||
if (Config.GiveCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "give");
|
||||
|
||||
if (Config.StripCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "strip");
|
||||
|
||||
if (Config.FreezeCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "freeze");
|
||||
|
||||
if (Config.HpCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "hp");
|
||||
|
||||
if (Config.SpeedCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "speed");
|
||||
|
||||
if (Config.GravityCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "gravity");
|
||||
|
||||
if (Config.MoneyCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "money");
|
||||
|
||||
if (Config.ResizeCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "resize");
|
||||
|
||||
_sharedApi.OnSimpleAdminReady -= RegisterFunMenus;
|
||||
}
|
||||
|
||||
private void RegisterFunCommands()
|
||||
{
|
||||
if (_sharedApi == null) return;
|
||||
|
||||
if (Config.NoclipCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.NoclipCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Enable noclip", OnNoclipCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.GodCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.GodCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Enable god mode", OnGodCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.FreezeCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.FreezeCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Freeze player", OnFreezeCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.UnfreezeCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.UnfreezeCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Unfreeze player", OnUnfreezeCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.RespawnCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.RespawnCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Respawn player", OnRespawnCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.GiveCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.GiveCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Give weapon", OnGiveWeaponCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.StripCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.StripCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Strip weapons", OnStripWeaponsCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.HpCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.HpCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Set HP", OnSetHpCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.SpeedCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.SpeedCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Set speed", OnSetSpeedCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.GravityCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.GravityCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Set gravity", OnSetGravityCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.MoneyCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.MoneyCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Set money", OnSetMoneyCommand);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.ResizeCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.ResizeCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Resize player", OnSetResizeCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterFunMenus()
|
||||
{
|
||||
if (_sharedApi == null || _menusRegistered) return;
|
||||
|
||||
try
|
||||
{
|
||||
_sharedApi.RegisterMenuCategory("fun", Localizer?["fun_category_name"] ?? "Fun Commands", "@css/generic");
|
||||
|
||||
if (Config.GodCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "god",
|
||||
Localizer?["fun_menu_god"] ?? "God Mode",
|
||||
CreateGodModeMenu, "@css/cheats");
|
||||
|
||||
if (Config.NoclipCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "noclip",
|
||||
Localizer?["fun_menu_noclip"] ?? "No Clip",
|
||||
CreateNoClipMenu, "@css/cheats");
|
||||
|
||||
if (Config.RespawnCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "respawn",
|
||||
Localizer?["fun_menu_respawn"] ?? "Respawn",
|
||||
CreateRespawnMenu, "@css/cheats");
|
||||
|
||||
if (Config.GiveCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "give",
|
||||
Localizer?["fun_menu_give"] ?? "Give Weapon",
|
||||
CreateGiveWeaponMenu, "@css/cheats");
|
||||
|
||||
if (Config.StripCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "strip",
|
||||
Localizer?["fun_menu_strip"] ?? "Strip Weapons",
|
||||
CreateStripWeaponsMenu, "@css/slay");
|
||||
|
||||
if (Config.FreezeCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "freeze",
|
||||
Localizer?["fun_menu_freeze"] ?? "Freeze",
|
||||
CreateFreezeMenu, "@css/slay");
|
||||
|
||||
if (Config.HpCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "hp",
|
||||
Localizer?["fun_menu_hp"] ?? "Set HP",
|
||||
CreateSetHpMenu, "@css/slay");
|
||||
|
||||
if (Config.SpeedCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "speed",
|
||||
Localizer?["fun_menu_speed"] ?? "Set Speed",
|
||||
CreateSetSpeedMenu, "@css/slay");
|
||||
|
||||
if (Config.GravityCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "gravity",
|
||||
Localizer?["fun_menu_gravity"] ?? "Set Gravity",
|
||||
CreateSetGravityMenu, "@css/slay");
|
||||
|
||||
if (Config.MoneyCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "money",
|
||||
Localizer?["fun_menu_money"] ?? "Set Money",
|
||||
CreateSetMoneyMenu, "@css/slay");
|
||||
|
||||
if (Config.ResizeCommands.Count > 0)
|
||||
_sharedApi.RegisterMenu("fun", "resize",
|
||||
Localizer?["fun_menu_resize"] ?? "Resize Player",
|
||||
CreateSetResizeMenu, "@css/slay");
|
||||
|
||||
_menusRegistered = true;
|
||||
Logger.LogInformation("Fun menus registered successfully!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Failed to register Fun menus: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnConfigParsed(Config config)
|
||||
{
|
||||
Config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a repeating timer to maintain speed and gravity modifications for players.
|
||||
/// This ensures that speed/gravity changes persist even after respawns or round changes.
|
||||
/// </summary>
|
||||
private void StartSpeedGravityTimer()
|
||||
{
|
||||
AddTimer(0.12f, () =>
|
||||
{
|
||||
// Early exit if no players have modified speed or gravity
|
||||
var hasSpeedPlayers = SpeedPlayers.Count > 0;
|
||||
var hasGravityPlayers = GravityPlayers.Count > 0;
|
||||
|
||||
if (!hasSpeedPlayers && !hasGravityPlayers)
|
||||
return;
|
||||
|
||||
if (hasSpeedPlayers)
|
||||
{
|
||||
// Iterate through players with modified speed
|
||||
foreach (var kvp in SpeedPlayers)
|
||||
{
|
||||
var player = kvp.Key;
|
||||
// Early validation check - avoid accessing PlayerPawn if player is invalid
|
||||
if (player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected)
|
||||
{
|
||||
var pawn = player.PlayerPawn?.Value;
|
||||
if (pawn != null && pawn.LifeState == (int)LifeState_t.LIFE_ALIVE)
|
||||
{
|
||||
player.SetSpeed(kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasGravityPlayers)
|
||||
{
|
||||
// Iterate through players with modified gravity
|
||||
foreach (var kvp in GravityPlayers)
|
||||
{
|
||||
var player = kvp.Key;
|
||||
if (player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected)
|
||||
{
|
||||
var pawn = player.PlayerPawn?.Value;
|
||||
if (pawn != null && pawn.LifeState == (int)LifeState_t.LIFE_ALIVE)
|
||||
{
|
||||
player.SetGravity(kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.REPEAT);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>CS2_SimpleAdmin_FunCommands</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="CS2-SimpleAdminApi">
|
||||
<HintPath>..\CS2-SimpleAdminApi.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.340" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="lang\**\*.json" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,320 @@
|
||||
using System.Globalization;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
|
||||
namespace CS2_SimpleAdmin_FunCommands;
|
||||
|
||||
public partial class CS2_SimpleAdmin_FunCommands
|
||||
{
|
||||
// =================================
|
||||
// COMMAND HANDLERS
|
||||
// =================================
|
||||
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
private void OnNoclipCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
NoClip(caller, player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
private void OnGodCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
God(caller, player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[CommandHelper(1, "<#userid or name> [duration]")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
private void OnFreezeCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
int.TryParse(command.GetArg(2), out var time);
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Freeze(caller, player, time);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
private void OnUnfreezeCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Unfreeze(caller, player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
private void OnRespawnCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Respawn(caller, player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[CommandHelper(2, "<#userid or name> <weapon>")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
private void OnGiveWeaponCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var weaponName = command.GetArg(2);
|
||||
if (Enum.TryParse(weaponName, true, out CsItem weapon))
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
player.GiveNamedItem(weapon);
|
||||
LogAndShowActivity(caller, player, "fun_admin_give_message", "css_give", weapon.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
private void OnStripWeaponsCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
player.RemoveWeapons();
|
||||
LogAndShowActivity(caller, player, "fun_admin_strip_message", "css_strip");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[CommandHelper(2, "<#userid or name> <hp>")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
private void OnSetHpCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (int.TryParse(command.GetArg(2), out var hp))
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
player.SetHp(hp);
|
||||
LogAndShowActivity(caller, player, "fun_admin_hp_message", "css_hp", hp.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[CommandHelper(2, "<#userid or name> <speed>")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
private void OnSetSpeedCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (float.TryParse(command.GetArg(2), NumberStyles.Float, CultureInfo.InvariantCulture, out var speed))
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
player.SetSpeed(speed);
|
||||
|
||||
// Track speed modification for timer
|
||||
if (speed == 1f)
|
||||
SpeedPlayers.Remove(player);
|
||||
else
|
||||
SpeedPlayers[player] = speed;
|
||||
|
||||
LogAndShowActivity(caller, player, "fun_admin_speed_message", "css_speed", speed.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[CommandHelper(2, "<#userid or name> <gravity>")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
private void OnSetGravityCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (float.TryParse(command.GetArg(2), NumberStyles.Float, CultureInfo.InvariantCulture, out var gravity))
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
player.SetGravity(gravity);
|
||||
|
||||
// Track gravity modification for timer
|
||||
if (gravity == 1f)
|
||||
GravityPlayers.Remove(player);
|
||||
else
|
||||
GravityPlayers[player] = gravity;
|
||||
|
||||
LogAndShowActivity(caller, player, "fun_admin_gravity_message", "css_gravity", gravity.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[CommandHelper(2, "<#userid or name> <money>")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
private void OnSetMoneyCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (int.TryParse(command.GetArg(2), out var money))
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
player.SetMoney(money);
|
||||
LogAndShowActivity(caller, player, "fun_admin_money_message", "css_money", money.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[CommandHelper(2, "<#userid or name> <size>")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
private void OnSetResizeCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (float.TryParse(command.GetArg(2), NumberStyles.Float, CultureInfo.InvariantCulture, out var size))
|
||||
{
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Resize(caller, player, size);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// =================================
|
||||
// HELPER METHOD FOR ACTIVITIES WITH INDIVIDUAL COMMAND LOGGING
|
||||
// =================================
|
||||
|
||||
private void LogAndShowActivity(CCSPlayerController? caller, CCSPlayerController target, string messageKey, string baseCommand, params string[] extraArgs)
|
||||
{
|
||||
var callerName = caller?.PlayerName ?? "Console";
|
||||
|
||||
// Build activity args
|
||||
var args = new List<object> { "CALLER", target.PlayerName };
|
||||
args.AddRange(extraArgs);
|
||||
|
||||
// Show admin activity using module's own localizer with per-player language support
|
||||
if (caller == null || !_sharedApi!.IsAdminSilent(caller))
|
||||
{
|
||||
// Use module's own translations with automatic per-player language support
|
||||
if (Localizer != null)
|
||||
{
|
||||
// This will send the message in each player's configured language
|
||||
_sharedApi!.ShowAdminActivityLocalized(Localizer, messageKey, callerName, false, args.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback to old method if localizer is not available
|
||||
_sharedApi!.ShowAdminActivity(messageKey, callerName, false, args.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
// Build and log command using API string method
|
||||
var logCommand = $"{baseCommand} {(string.IsNullOrEmpty(target.PlayerName) ? target.SteamID.ToString() : target.PlayerName)}";
|
||||
if (extraArgs.Length > 0)
|
||||
{
|
||||
logCommand += $" {string.Join(" ", extraArgs)}";
|
||||
}
|
||||
|
||||
_sharedApi!.LogCommand(caller, logCommand);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace CS2_SimpleAdmin_FunCommands;
|
||||
|
||||
public class Config : IBasePluginConfig
|
||||
{
|
||||
public int Version { get; set; } = 1;
|
||||
|
||||
public List<string> NoclipCommands { get; set; } = ["css_noclip"];
|
||||
public List<string> GodCommands { get; set; } = ["css_god"];
|
||||
public List<string> FreezeCommands { get; set; } = ["css_freeze"];
|
||||
public List<string> UnfreezeCommands { get; set; } = ["css_unfreeze"];
|
||||
public List<string> RespawnCommands { get; set; } = ["css_respawn"];
|
||||
public List<string> GiveCommands { get; set; } = ["css_give"];
|
||||
public List<string> StripCommands { get; set; } = ["css_strip"];
|
||||
public List<string> HpCommands { get; set; } = ["css_hp"];
|
||||
public List<string> SpeedCommands { get; set; } = ["css_speed"];
|
||||
public List<string> GravityCommands { get; set; } = ["css_gravity"];
|
||||
public List<string> MoneyCommands { get; set; } = ["css_money"];
|
||||
public List<string> ResizeCommands { get; set; } = ["css_resize"];
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
|
||||
namespace CS2_SimpleAdmin_FunCommands;
|
||||
|
||||
public partial class CS2_SimpleAdmin_FunCommands
|
||||
{
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info)
|
||||
{
|
||||
var player = @event.Userid;
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
|
||||
// Check if player has god mode (similar to main plugin)
|
||||
if (!GodPlayers.Contains(player.Slot)) return HookResult.Continue;
|
||||
|
||||
// Cancel damage
|
||||
@event.DmgHealth = 0;
|
||||
@event.DmgArmor = 0;
|
||||
|
||||
// Reset health to full
|
||||
if (player.PlayerPawn?.Value == null) return HookResult.Continue;
|
||||
|
||||
player.PlayerPawn.Value.Health = player.PlayerPawn.Value.MaxHealth;
|
||||
Utilities.SetStateChanged(player.PlayerPawn.Value, "CBaseEntity", "m_iHealth");
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
|
||||
{
|
||||
var player = @event.Userid;
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
|
||||
// Remove player from god mode, speed, and gravity tracking on death
|
||||
GodPlayers.Remove(player.Slot);
|
||||
SpeedPlayers.Remove(player);
|
||||
GravityPlayers.Remove(player);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info)
|
||||
{
|
||||
// Clear all fun command modifications at round start
|
||||
GodPlayers.Clear();
|
||||
SpeedPlayers.Clear();
|
||||
GravityPlayers.Clear();
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
|
||||
{
|
||||
var player = @event.Userid;
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
|
||||
// Clean up player from all tracking when they disconnect
|
||||
GodPlayers.Remove(player.Slot);
|
||||
SpeedPlayers.Remove(player);
|
||||
GravityPlayers.Remove(player);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
using System.Globalization;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace CS2_SimpleAdmin_FunCommands;
|
||||
|
||||
/// <summary>
|
||||
/// Menu creation methods for Fun Commands module.
|
||||
/// This file demonstrates different menu patterns using SimpleAdmin API.
|
||||
/// </summary>
|
||||
public partial class CS2_SimpleAdmin_FunCommands
|
||||
{
|
||||
// =================================
|
||||
// SIMPLE PLAYER SELECTION MENUS
|
||||
// =================================
|
||||
// Pattern: Direct player selection with immediate action
|
||||
// Use CreateMenuWithPlayers when you just need to select a player and execute an action
|
||||
|
||||
/// <summary>
|
||||
/// Creates a simple player selection menu for god mode.
|
||||
/// PATTERN: CreateMenuWithPlayers with method reference
|
||||
/// </summary>
|
||||
private object CreateGodModeMenu(CCSPlayerController admin)
|
||||
{
|
||||
return _sharedApi!.CreateMenuWithPlayers(
|
||||
Localizer?["fun_menu_god"] ?? "God Mode", // Menu title from translation
|
||||
"fun", // Category ID (for back button navigation)
|
||||
admin, // Admin opening the menu
|
||||
player => player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(player), // Filter: only alive, targetable players
|
||||
God); // Action to execute (method reference)
|
||||
}
|
||||
|
||||
private object CreateNoClipMenu(CCSPlayerController admin)
|
||||
{
|
||||
return _sharedApi!.CreateMenuWithPlayers(
|
||||
Localizer?["fun_menu_noclip"] ?? "No Clip",
|
||||
"fun",
|
||||
admin,
|
||||
player => player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(player),
|
||||
NoClip);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a player selection menu for respawn command.
|
||||
/// PATTERN: CreateMenuWithPlayers with method reference
|
||||
/// </summary>
|
||||
private object CreateRespawnMenu(CCSPlayerController admin)
|
||||
{
|
||||
return _sharedApi!.CreateMenuWithPlayers(
|
||||
Localizer?["fun_menu_respawn"] ?? "Respawn", // Menu title from translation
|
||||
"fun", // Category ID
|
||||
admin, // Admin
|
||||
admin.CanTarget, // Filter: only targetable players (no LifeState check - can respawn dead players)
|
||||
Respawn); // Use the Respawn method which includes death position teleport
|
||||
}
|
||||
|
||||
// =================================
|
||||
// NESTED MENUS - PLAYER → VALUE SELECTION
|
||||
// =================================
|
||||
// Pattern: First select player, then select a value/option for that player
|
||||
// Use CreateMenuWithBack + AddSubMenu for multi-level menus
|
||||
|
||||
/// <summary>
|
||||
/// Creates a nested menu: Player selection → Weapon selection.
|
||||
/// PATTERN: CreateMenuWithBack + foreach + AddSubMenu
|
||||
/// </summary>
|
||||
private object CreateGiveWeaponMenu(CCSPlayerController admin)
|
||||
{
|
||||
var menu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_give"] ?? "Give Weapon",
|
||||
"fun",
|
||||
admin);
|
||||
var players = _sharedApi.GetValidPlayers().Where(p =>
|
||||
p.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(p));
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
var playerName = player.PlayerName.Length > 26 ? player.PlayerName[..26] : player.PlayerName;
|
||||
|
||||
// AddSubMenu automatically adds a "Back" button to the submenu
|
||||
// The lambda receives 'p' but we use captured 'player' variable (closure)
|
||||
_sharedApi.AddSubMenu(menu, playerName, p => CreateWeaponSelectionMenu(admin, player));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates weapon selection submenu for a specific player.
|
||||
/// PATTERN: CreateMenuWithBack + foreach + AddMenuOption
|
||||
/// </summary>
|
||||
private object CreateWeaponSelectionMenu(CCSPlayerController admin, CCSPlayerController target)
|
||||
{
|
||||
var weaponMenu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_give_player", target.PlayerName] ?? $"Give Weapon: {target.PlayerName}",
|
||||
"fun",
|
||||
admin);
|
||||
|
||||
// Loop through cached weapons (performance optimization)
|
||||
foreach (var weapon in GetWeaponsCache())
|
||||
{
|
||||
// AddMenuOption for each selectable option
|
||||
// IMPORTANT: Always validate target.IsValid before executing action
|
||||
_sharedApi.AddMenuOption(weaponMenu, weapon.Value.ToString(), _ =>
|
||||
{
|
||||
if (target.IsValid) // Player might disconnect before selection
|
||||
{
|
||||
target.GiveNamedItem(weapon.Value);
|
||||
LogAndShowActivity(admin, target, "fun_admin_give_message", $"css_give", weapon.Value.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return weaponMenu;
|
||||
}
|
||||
|
||||
private object CreateStripWeaponsMenu(CCSPlayerController admin)
|
||||
{
|
||||
return _sharedApi!.CreateMenuWithPlayers(
|
||||
Localizer?["fun_menu_strip"] ?? "Strip Weapons",
|
||||
"fun",
|
||||
admin,
|
||||
player => player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(player),
|
||||
(adminPlayer, targetPlayer) =>
|
||||
{
|
||||
targetPlayer.RemoveWeapons();
|
||||
LogAndShowActivity(adminPlayer, targetPlayer, "fun_admin_strip_message", "css_strip");
|
||||
});
|
||||
}
|
||||
|
||||
private object CreateFreezeMenu(CCSPlayerController admin)
|
||||
{
|
||||
return _sharedApi!.CreateMenuWithPlayers(
|
||||
Localizer?["fun_menu_freeze"] ?? "Freeze",
|
||||
"fun",
|
||||
admin,
|
||||
player => player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(player),
|
||||
(adminPlayer, targetPlayer) => { Freeze(adminPlayer, targetPlayer, -1); });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a nested menu for setting player HP with predefined values.
|
||||
/// PATTERN: Same as Give Weapon (player selection → value selection)
|
||||
/// This is a common pattern you'll use frequently!
|
||||
/// </summary>
|
||||
private object CreateSetHpMenu(CCSPlayerController admin)
|
||||
{
|
||||
var menu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_hp"] ?? "Set HP",
|
||||
"fun",
|
||||
admin);
|
||||
var players = _sharedApi.GetValidPlayers().Where(p =>
|
||||
p.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(p));
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
var playerName = player.PlayerName.Length > 26 ? player.PlayerName[..26] : player.PlayerName;
|
||||
_sharedApi.AddSubMenu(menu, playerName, p => CreateHpSelectionMenu(admin, player));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates HP value selection submenu.
|
||||
/// TIP: Use arrays for predefined values - easy to modify and maintain
|
||||
/// </summary>
|
||||
private object CreateHpSelectionMenu(CCSPlayerController admin, CCSPlayerController target)
|
||||
{
|
||||
var hpSelectionMenu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_hp_player", target.PlayerName] ?? $"Set HP: {target.PlayerName}",
|
||||
"fun",
|
||||
admin);
|
||||
|
||||
// Predefined HP values - easy to customize
|
||||
var hpValues = new[] { 1, 10, 25, 50, 100, 200, 500, 999 };
|
||||
|
||||
foreach (var hp in hpValues)
|
||||
{
|
||||
_sharedApi.AddMenuOption(hpSelectionMenu,
|
||||
Localizer?["fun_menu_hp_value", hp] ?? $"{hp} HP",
|
||||
_ =>
|
||||
{
|
||||
if (target.IsValid)
|
||||
{
|
||||
target.SetHp(hp);
|
||||
LogAndShowActivity(admin, target, "fun_admin_hp_message", "css_hp", hp.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return hpSelectionMenu;
|
||||
}
|
||||
|
||||
private object CreateSetSpeedMenu(CCSPlayerController admin)
|
||||
{
|
||||
var menu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_speed"] ?? "Set Speed",
|
||||
"fun",
|
||||
admin);
|
||||
var players = _sharedApi.GetValidPlayers().Where(p =>
|
||||
p.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(p));
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
var playerName = player.PlayerName.Length > 26 ? player.PlayerName[..26] : player.PlayerName;
|
||||
_sharedApi.AddSubMenu(menu, playerName, p => CreateSpeedSelectionMenu(admin, player));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates speed value selection submenu.
|
||||
/// TIP: Use tuples (value, display) when you need different internal value vs display text
|
||||
/// Example: (0.5f, "0.5") - float value for code, string for display
|
||||
/// </summary>
|
||||
private object CreateSpeedSelectionMenu(CCSPlayerController admin, CCSPlayerController target)
|
||||
{
|
||||
var speedSelectionMenu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_speed_player", target.PlayerName] ?? $"Set Speed: {target.PlayerName}",
|
||||
"fun",
|
||||
admin);
|
||||
|
||||
// Tuple pattern: (actualValue, displayText)
|
||||
// Useful when display text differs from actual value
|
||||
var speedValues = new[]
|
||||
{
|
||||
(0.1f, "0.1"), (0.25f, "0.25"), (0.5f, "0.5"), (0.75f, "0.75"), (1f, "1"), (2f, "2"), (3f, "3"), (4f, "4")
|
||||
};
|
||||
|
||||
foreach (var (speed, display) in speedValues)
|
||||
{
|
||||
_sharedApi.AddMenuOption(speedSelectionMenu,
|
||||
Localizer?["fun_menu_speed_value", display] ?? $"Speed {display}",
|
||||
_ =>
|
||||
{
|
||||
if (target.IsValid)
|
||||
{
|
||||
target.SetSpeed(speed);
|
||||
|
||||
// Track speed modification for timer
|
||||
if (speed == 1f)
|
||||
SpeedPlayers.Remove(target);
|
||||
else
|
||||
SpeedPlayers[target] = speed;
|
||||
|
||||
LogAndShowActivity(admin, target, "fun_admin_speed_message", "css_speed", speed.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return speedSelectionMenu;
|
||||
}
|
||||
|
||||
private object CreateSetGravityMenu(CCSPlayerController admin)
|
||||
{
|
||||
var menu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_gravity"] ?? "Set Gravity",
|
||||
"fun",
|
||||
admin);
|
||||
var players = _sharedApi.GetValidPlayers().Where(p =>
|
||||
p.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(p));
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
var playerName = player.PlayerName.Length > 26 ? player.PlayerName[..26] : player.PlayerName;
|
||||
_sharedApi.AddSubMenu(menu, playerName, p => CreateGravitySelectionMenu(admin, player));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
private object CreateGravitySelectionMenu(CCSPlayerController admin, CCSPlayerController target)
|
||||
{
|
||||
var gravitySelectionMenu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_gravity_player", target.PlayerName] ?? $"Set Gravity: {target.PlayerName}",
|
||||
"fun",
|
||||
admin);
|
||||
var gravityValues = new[]
|
||||
{ (0.1f, "0.1"), (0.25f, "0.25"), (0.5f, "0.5"), (0.75f, "0.75"), (1f, "1"), (2f, "2") };
|
||||
|
||||
foreach (var (gravity, display) in gravityValues)
|
||||
{
|
||||
_sharedApi.AddMenuOption(gravitySelectionMenu,
|
||||
Localizer?["fun_menu_gravity_value", display] ?? $"Gravity {display}",
|
||||
_ =>
|
||||
{
|
||||
if (target.IsValid)
|
||||
{
|
||||
target.SetGravity(Convert.ToSingle(gravity, CultureInfo.InvariantCulture));
|
||||
|
||||
// Track gravity modification for timer
|
||||
if (gravity == 1f)
|
||||
GravityPlayers.Remove(target);
|
||||
else
|
||||
GravityPlayers[target] = gravity;
|
||||
|
||||
LogAndShowActivity(admin, target, "fun_admin_gravity_message", "css_gravity", gravity.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return gravitySelectionMenu;
|
||||
}
|
||||
|
||||
private object CreateSetMoneyMenu(CCSPlayerController admin)
|
||||
{
|
||||
var menu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_money"] ?? "Set Money",
|
||||
"fun",
|
||||
admin);
|
||||
var players = _sharedApi.GetValidPlayers().Where(p => admin.CanTarget(p));
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
var playerName = player.PlayerName.Length > 26 ? player.PlayerName[..26] : player.PlayerName;
|
||||
_sharedApi.AddSubMenu(menu, playerName, p => CreateMoneySelectionMenu(admin, player));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
private object CreateMoneySelectionMenu(CCSPlayerController admin, CCSPlayerController target)
|
||||
{
|
||||
var moneySelectionMenu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_money_player", target.PlayerName] ?? $"Set Money: {target.PlayerName}",
|
||||
"fun",
|
||||
admin);
|
||||
var moneyValues = new[] { 0, 1000, 2500, 5000, 10000, 16000 };
|
||||
|
||||
foreach (var money in moneyValues)
|
||||
{
|
||||
_sharedApi.AddMenuOption(moneySelectionMenu,
|
||||
Localizer?["fun_menu_money_value", money] ?? $"${money}",
|
||||
_ =>
|
||||
{
|
||||
if (target.IsValid)
|
||||
{
|
||||
target.SetMoney(money);
|
||||
LogAndShowActivity(admin, target, "fun_admin_money_message", "css_money", money.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return moneySelectionMenu;
|
||||
}
|
||||
|
||||
private object CreateSetResizeMenu(CCSPlayerController admin)
|
||||
{
|
||||
var menu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_resize"] ?? "Resize Player",
|
||||
"fun",
|
||||
admin);
|
||||
var players = _sharedApi.GetValidPlayers().Where(p =>
|
||||
p.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(p));
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
var playerName = player.PlayerName.Length > 26 ? player.PlayerName[..26] : player.PlayerName;
|
||||
_sharedApi.AddSubMenu(menu, playerName, p => CreateResizeSelectionMenu(admin, player));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
private object CreateResizeSelectionMenu(CCSPlayerController admin, CCSPlayerController target)
|
||||
{
|
||||
var resizeSelectionMenu = _sharedApi!.CreateMenuWithBack(
|
||||
Localizer?["fun_menu_resize_player", target.PlayerName] ?? $"Resize: {target.PlayerName}",
|
||||
"fun",
|
||||
admin);
|
||||
var resizeValues = new[]
|
||||
{ (0.5f, "0.5"), (0.75f, "0.75"), (1f, "1"), (1.25f, "1.25"), (1.5f, "1.5"), (2f, "2"), (3f, "3") };
|
||||
|
||||
foreach (var (resize, display) in resizeValues)
|
||||
{
|
||||
_sharedApi.AddMenuOption(resizeSelectionMenu,
|
||||
Localizer?["fun_menu_resize_value", display] ?? $"Size {display}",
|
||||
_ =>
|
||||
{
|
||||
if (target.IsValid)
|
||||
{
|
||||
Resize(admin, target, resize);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return resizeSelectionMenu;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.UserMessages;
|
||||
|
||||
namespace CS2_SimpleAdmin_FunCommands;
|
||||
|
||||
public static class PlayerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Slaps the player pawn by applying optional damage and adding a random velocity knockback.
|
||||
/// </summary>
|
||||
/// <param name="pawn">The player pawn to slap.</param>
|
||||
/// <param name="damage">The amount of damage to apply (default is 0).</param>
|
||||
public static void Slap(this CBasePlayerPawn pawn, int damage = 0)
|
||||
{
|
||||
PerformSlap(pawn, damage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the player controller can target another player controller, respecting admin permissions and immunity.
|
||||
/// </summary>
|
||||
/// <param name="controller">The player controller who wants to target.</param>
|
||||
/// <param name="target">The player controller being targeted.</param>
|
||||
/// <returns>True if targeting is allowed, false otherwise.</returns>
|
||||
public static bool CanTarget(this CCSPlayerController? controller, CCSPlayerController? target)
|
||||
{
|
||||
if (controller is null || target is null) return true;
|
||||
if (target.IsBot) return true;
|
||||
|
||||
return AdminManager.CanPlayerTarget(controller, target) ||
|
||||
AdminManager.CanPlayerTarget(new SteamID(controller.SteamID),
|
||||
new SteamID(target.SteamID)) ||
|
||||
AdminManager.GetPlayerImmunity(controller) >= AdminManager.GetPlayerImmunity(target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the controller can target a player by SteamID, considering targeting permissions and immunities.
|
||||
/// </summary>
|
||||
/// <param name="controller">The attacker player controller.</param>
|
||||
/// <param name="steamId">The SteamID of the target player.</param>
|
||||
/// <returns>True if targeting is permitted, false otherwise.</returns>
|
||||
public static bool CanTarget(this CCSPlayerController? controller, SteamID steamId)
|
||||
{
|
||||
if (controller is null) return true;
|
||||
|
||||
return AdminManager.CanPlayerTarget(new SteamID(controller.SteamID), steamId) ||
|
||||
AdminManager.GetPlayerImmunity(controller) >= AdminManager.GetPlayerImmunity(steamId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the movement speed modifier of the player controller.
|
||||
/// </summary>
|
||||
/// <param name="controller">The player controller.</param>
|
||||
/// <param name="speed">The speed modifier value.</param>
|
||||
public static void SetSpeed(this CCSPlayerController? controller, float speed)
|
||||
{
|
||||
var playerPawnValue = controller?.PlayerPawn.Value;
|
||||
if (playerPawnValue == null) return;
|
||||
|
||||
playerPawnValue.VelocityModifier = speed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the gravity scale for the player controller.
|
||||
/// </summary>
|
||||
/// <param name="controller">The player controller.</param>
|
||||
/// <param name="gravity">The gravity scale.</param>
|
||||
public static void SetGravity(this CCSPlayerController? controller, float gravity)
|
||||
{
|
||||
var playerPawnValue = controller?.PlayerPawn.Value;
|
||||
if (playerPawnValue == null) return;
|
||||
|
||||
playerPawnValue.ActualGravityScale = gravity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the player's in-game money amount.
|
||||
/// </summary>
|
||||
/// <param name="controller">The player controller.</param>
|
||||
/// <param name="money">The amount of money to set.</param>
|
||||
public static void SetMoney(this CCSPlayerController? controller, int money)
|
||||
{
|
||||
var moneyServices = controller?.InGameMoneyServices;
|
||||
if (moneyServices == null) return;
|
||||
|
||||
moneyServices.Account = money;
|
||||
|
||||
if (controller != null) Utilities.SetStateChanged(controller, "CCSPlayerController", "m_pInGameMoneyServices");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the player's health points.
|
||||
/// </summary>
|
||||
/// <param name="controller">The player controller.</param>
|
||||
/// <param name="health">The health value, default is 100.</param>
|
||||
public static void SetHp(this CCSPlayerController? controller, int health = 100)
|
||||
{
|
||||
if (controller == null) return;
|
||||
if (health <= 0 || controller.PlayerPawn.Value == null || controller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
controller.PlayerPawn.Value.Health = health;
|
||||
|
||||
if (health > 100)
|
||||
{
|
||||
controller.PlayerPawn.Value.MaxHealth = health;
|
||||
}
|
||||
|
||||
Utilities.SetStateChanged(controller.PlayerPawn.Value, "CBaseEntity", "m_iHealth");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Buries the player pawn by moving it down by a depth offset.
|
||||
/// </summary>
|
||||
/// <param name="pawn">The player pawn to bury.</param>
|
||||
/// <param name="depth">The depth offset (default 10 units).</param>
|
||||
public static void Bury(this CBasePlayerPawn pawn, float depth = 10f)
|
||||
{
|
||||
var newPos = new Vector3(pawn.AbsOrigin!.X, pawn.AbsOrigin.Y,
|
||||
pawn.AbsOrigin!.Z - depth);
|
||||
var newRotation = new Vector3(pawn.AbsRotation!.X, pawn.AbsRotation.Y, pawn.AbsRotation.Z);
|
||||
var newVelocity = new Vector3(pawn.AbsVelocity.X, pawn.AbsVelocity.Y, pawn.AbsVelocity.Z);
|
||||
|
||||
pawn.Teleport(newPos, newRotation, newVelocity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unburies the player pawn by moving it up by a depth offset.
|
||||
/// </summary>
|
||||
/// <param name="pawn">The player pawn to unbury.</param>
|
||||
/// <param name="depth">The depth offset (default 15 units).</param>
|
||||
public static void Unbury(this CBasePlayerPawn pawn, float depth = 15f)
|
||||
{
|
||||
var newPos = new Vector3(pawn.AbsOrigin!.X, pawn.AbsOrigin.Y,
|
||||
pawn.AbsOrigin!.Z + depth);
|
||||
var newRotation = new Vector3(pawn.AbsRotation!.X, pawn.AbsRotation.Y, pawn.AbsRotation.Z);
|
||||
var newVelocity = new Vector3(pawn.AbsVelocity.X, pawn.AbsVelocity.Y, pawn.AbsVelocity.Z);
|
||||
|
||||
pawn.Teleport(newPos, newRotation, newVelocity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Freezes the player pawn, disabling movement.
|
||||
/// </summary>
|
||||
/// <param name="pawn">The player pawn to freeze.</param>
|
||||
public static void Freeze(this CBasePlayerPawn pawn)
|
||||
{
|
||||
pawn.MoveType = MoveType_t.MOVETYPE_INVALID;
|
||||
Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 11); // invalid
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unfreezes the player pawn, enabling movement.
|
||||
/// </summary>
|
||||
/// <param name="pawn">The player pawn to unfreeze.</param>
|
||||
public static void Unfreeze(this CBasePlayerPawn pawn)
|
||||
{
|
||||
pawn.MoveType = MoveType_t.MOVETYPE_WALK;
|
||||
Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 2); // walk
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the player's color tint to specified RGBA values.
|
||||
/// </summary>
|
||||
/// <param name="pawn">The pawn to colorize.</param>
|
||||
/// <param name="r">Red component (0-255).</param>
|
||||
/// <param name="g">Green component (0-255).</param>
|
||||
/// <param name="b">Blue component (0-255).</param>
|
||||
/// <param name="a">Alpha (transparency) component (0-255).</param>
|
||||
public static void Colorize(this CBasePlayerPawn pawn, int r = 255, int g = 255, int b = 255, int a = 255)
|
||||
{
|
||||
pawn.Render = Color.FromArgb(a, r, g, b);
|
||||
Utilities.SetStateChanged(pawn, "CBaseModelEntity", "m_clrRender");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles noclip mode for the player pawn.
|
||||
/// </summary>
|
||||
/// <param name="pawn">The player pawn.</param>
|
||||
public static void ToggleNoclip(this CBasePlayerPawn pawn)
|
||||
{
|
||||
if (pawn.MoveType == MoveType_t.MOVETYPE_NOCLIP)
|
||||
{
|
||||
pawn.MoveType = MoveType_t.MOVETYPE_WALK;
|
||||
Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 2); // walk
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType");
|
||||
}
|
||||
else
|
||||
{
|
||||
pawn.MoveType = MoveType_t.MOVETYPE_NOCLIP;
|
||||
Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 8); // noclip
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Teleports a player controller to the position, rotation, and velocity of another player controller.
|
||||
/// </summary>
|
||||
/// <param name="controller">The controller to teleport.</param>
|
||||
/// <param name="target">The target controller whose position to copy.</param>
|
||||
public static void TeleportPlayer(this CCSPlayerController? controller, CCSPlayerController? target)
|
||||
{
|
||||
if (controller?.PlayerPawn.Value == null && target?.PlayerPawn.Value == null)
|
||||
return;
|
||||
|
||||
if (
|
||||
controller?.PlayerPawn.Value is { AbsOrigin: not null, AbsRotation: not null } &&
|
||||
target?.PlayerPawn.Value is { AbsOrigin: not null, AbsRotation: not null }
|
||||
)
|
||||
{
|
||||
controller.PlayerPawn.Value.Teleport(
|
||||
target.PlayerPawn.Value.AbsOrigin,
|
||||
target.PlayerPawn.Value.AbsRotation,
|
||||
target.PlayerPawn.Value.AbsVelocity
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a slap effect to the given player pawn, optionally inflicting damage and adding velocity knockback.
|
||||
/// </summary>
|
||||
/// <param name="pawn">The player pawn to slap.</param>
|
||||
/// <param name="damage">The amount of damage to deal (default is 0).</param>
|
||||
private static void PerformSlap(CBasePlayerPawn pawn, int damage = 0)
|
||||
{
|
||||
if (pawn.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
|
||||
var controller = pawn.Controller.Value?.As<CCSPlayerController>();
|
||||
|
||||
/* Teleport in a random direction - thank you, Mani!*/
|
||||
/* Thank you AM & al!*/
|
||||
var random = new Random();
|
||||
var vel = new Vector3(pawn.AbsVelocity.X, pawn.AbsVelocity.Y, pawn.AbsVelocity.Z);
|
||||
|
||||
vel.X += (random.Next(180) + 50) * (random.Next(2) == 1 ? -1 : 1);
|
||||
vel.Y += (random.Next(180) + 50) * (random.Next(2) == 1 ? -1 : 1);
|
||||
vel.Z += random.Next(200) + 100;
|
||||
|
||||
pawn.AbsVelocity.X = vel.X;
|
||||
pawn.AbsVelocity.Y = vel.Y;
|
||||
pawn.AbsVelocity.Z = vel.Z;
|
||||
|
||||
if (controller != null && controller.IsValid)
|
||||
{
|
||||
var shakeMessage = UserMessage.FromPartialName("Shake");
|
||||
shakeMessage.SetFloat("duration", 1);
|
||||
shakeMessage.SetFloat("amplitude", 10);
|
||||
shakeMessage.SetFloat("frequency", 1f);
|
||||
shakeMessage.SetInt("command", 0);
|
||||
shakeMessage.Recipients.Add(controller);
|
||||
shakeMessage.Send();
|
||||
}
|
||||
|
||||
if (damage <= 0)
|
||||
return;
|
||||
|
||||
pawn.Health -= damage;
|
||||
Utilities.SetStateChanged(pawn, "CBaseEntity", "m_iHealth");
|
||||
|
||||
if (pawn.Health <= 0)
|
||||
pawn.CommitSuicide(true, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "أوامر المرح",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} أعطى {lightred}{1}{default} {lightred}{2}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} أخذ جميع أسلحة اللاعب {lightred}{1}{default}!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} غيّر عدد نقاط الحياة لـ {lightred}{1}{default}!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} غيّر السرعة لـ {lightred}{1}{default}!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} غيّر الجاذبية لـ {lightred}{1}{default}!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} غيّر المال لـ {lightred}{1}{default}!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} غيّر وضع الله لـ {lightred}{1}{default}!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} فعّل/ألغى نمط اللا تصادم لـ {lightred}{1}{default}!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} جمد {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} أذاب {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} أحيى {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "وضع الله",
|
||||
"fun_menu_noclip": "اللا تصادم",
|
||||
"fun_menu_respawn": "إحياء",
|
||||
"fun_menu_give": "إعطاء سلاح",
|
||||
"fun_menu_give_player": "إعطاء سلاح: {0}",
|
||||
"fun_menu_strip": "نزع الأسلحة",
|
||||
"fun_menu_freeze": "تجميد",
|
||||
"fun_menu_hp": "ضبط الحياة",
|
||||
"fun_menu_hp_player": "ضبط الحياة: {0}",
|
||||
"fun_menu_speed": "ضبط السرعة",
|
||||
"fun_menu_speed_player": "ضبط السرعة: {0}",
|
||||
"fun_menu_gravity": "ضبط الجاذبية",
|
||||
"fun_menu_gravity_player": "ضبط الجاذبية: {0}",
|
||||
"fun_menu_money": "ضبط المال",
|
||||
"fun_menu_money_player": "ضبط المال: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "السرعة {0}",
|
||||
"fun_menu_gravity_value": "الجاذبية {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} غيّر حجم {lightred}{1}{default} إلى {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "تغيير الحجم",
|
||||
"fun_menu_resize_player": "تغيير الحجم: {0}",
|
||||
"fun_menu_resize_value": "الحجم {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Spaß-Befehle",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} hat {lightred}{1}{default} ein {lightred}{2}{default} gegeben!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} hat alle Waffen von Spieler {lightred}{1}{default} entfernt!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} hat die Lebenspunkte von {lightred}{1}{default} geändert!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} hat die Geschwindigkeit von {lightred}{1}{default} geändert!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} hat die Schwerkraft von {lightred}{1}{default} geändert!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} hat das Geld von {lightred}{1}{default} geändert!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} hat den Gottmodus von {lightred}{1}{default} geändert!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} hat den Noclip-Modus für {lightred}{1}{default} aktiviert/deaktiviert!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} hat {lightred}{1}{default} eingefroren!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} hat {lightred}{1}{default} aufgetaut!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} hat {lightred}{1}{default} wiederbelebt!",
|
||||
|
||||
"fun_menu_god": "Gottmodus",
|
||||
"fun_menu_noclip": "Noclip",
|
||||
"fun_menu_respawn": "Wiederbeleben",
|
||||
"fun_menu_give": "Waffe Geben",
|
||||
"fun_menu_give_player": "Waffe Geben: {0}",
|
||||
"fun_menu_strip": "Waffen Entfernen",
|
||||
"fun_menu_freeze": "Einfrieren",
|
||||
"fun_menu_hp": "HP Festlegen",
|
||||
"fun_menu_hp_player": "HP Festlegen: {0}",
|
||||
"fun_menu_speed": "Geschwindigkeit Festlegen",
|
||||
"fun_menu_speed_player": "Geschwindigkeit Festlegen: {0}",
|
||||
"fun_menu_gravity": "Schwerkraft Festlegen",
|
||||
"fun_menu_gravity_player": "Schwerkraft Festlegen: {0}",
|
||||
"fun_menu_money": "Geld Festlegen",
|
||||
"fun_menu_money_player": "Geld Festlegen: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Geschwindigkeit {0}",
|
||||
"fun_menu_gravity_value": "Schwerkraft {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} hat die Größe von {lightred}{1}{default} auf {lightred}{2}{default} geändert!",
|
||||
"fun_menu_resize": "Größe Ändern",
|
||||
"fun_menu_resize_player": "Größe Ändern: {0}",
|
||||
"fun_menu_resize_value": "Größe {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Fun Commands",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} gave {lightred}{1}{default} a {lightred}{2}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} took all of player {lightred}{1}{default} weapons!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} changed {lightred}{1}{default} hp amount!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} changed speed for {lightred}{1}{default}!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} changed gravity for {lightred}{1}{default}!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} changed money for {lightred}{1}{default}!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} changed god mode for {lightred}{1}{default}!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} toggled noclip for {lightred}{1}{default}!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} froze {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} unfroze {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} respawned {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "God Mode",
|
||||
"fun_menu_noclip": "No Clip",
|
||||
"fun_menu_respawn": "Respawn",
|
||||
"fun_menu_give": "Give Weapon",
|
||||
"fun_menu_give_player": "Give Weapon: {0}",
|
||||
"fun_menu_strip": "Strip Weapons",
|
||||
"fun_menu_freeze": "Freeze",
|
||||
"fun_menu_hp": "Set HP",
|
||||
"fun_menu_hp_player": "Set HP: {0}",
|
||||
"fun_menu_speed": "Set Speed",
|
||||
"fun_menu_speed_player": "Set Speed: {0}",
|
||||
"fun_menu_gravity": "Set Gravity",
|
||||
"fun_menu_gravity_player": "Set Gravity: {0}",
|
||||
"fun_menu_money": "Set Money",
|
||||
"fun_menu_money_player": "Set Money: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Speed {0}",
|
||||
"fun_menu_gravity_value": "Gravity {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} resized {lightred}{1}{default} to {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "Resize Player",
|
||||
"fun_menu_resize_player": "Resize: {0}",
|
||||
"fun_menu_resize_value": "Size {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Comandos Divertidos",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} dio {lightred}{1}{default} un {lightred}{2}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} quitó todas las armas del jugador {lightred}{1}{default}!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} cambió la cantidad de HP de {lightred}{1}{default}!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} cambió la velocidad de {lightred}{1}{default}!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} cambió la gravedad de {lightred}{1}{default}!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} cambió el dinero de {lightred}{1}{default}!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} cambió el modo dios de {lightred}{1}{default}!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} alternó noclip para {lightred}{1}{default}!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} congeló a {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} descongeló a {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} reapareció a {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "Modo Dios",
|
||||
"fun_menu_noclip": "Noclip",
|
||||
"fun_menu_respawn": "Reaparecer",
|
||||
"fun_menu_give": "Dar Arma",
|
||||
"fun_menu_give_player": "Dar Arma: {0}",
|
||||
"fun_menu_strip": "Quitar Armas",
|
||||
"fun_menu_freeze": "Congelar",
|
||||
"fun_menu_hp": "Establecer HP",
|
||||
"fun_menu_hp_player": "Establecer HP: {0}",
|
||||
"fun_menu_speed": "Establecer Velocidad",
|
||||
"fun_menu_speed_player": "Establecer Velocidad: {0}",
|
||||
"fun_menu_gravity": "Establecer Gravedad",
|
||||
"fun_menu_gravity_player": "Establecer Gravedad: {0}",
|
||||
"fun_menu_money": "Establecer Dinero",
|
||||
"fun_menu_money_player": "Establecer Dinero: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Velocidad {0}",
|
||||
"fun_menu_gravity_value": "Gravedad {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} cambió el tamaño de {lightred}{1}{default} a {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "Cambiar Tamaño",
|
||||
"fun_menu_resize_player": "Cambiar Tamaño: {0}",
|
||||
"fun_menu_resize_value": "Tamaño {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "دستورات سرگرمی",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} {lightred}{2}{default} را به {lightred}{1}{default} داد!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} تمام سلاحهای بازیکن {lightred}{1}{default} را گرفت!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} مقدار سلامت {lightred}{1}{default} را تغییر داد!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} سرعت {lightred}{1}{default} را تغییر داد!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} جاذبه {lightred}{1}{default} را تغییر داد!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} پول {lightred}{1}{default} را تغییر داد!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} حالت خدا را برای {lightred}{1}{default} تغییر داد!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} ناپدیدی را برای {lightred}{1}{default} فعال/غیرفعال کرد!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} {lightred}{1}{default} را یخزده کرد!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} {lightred}{1}{default} را از حالت یخ خارج کرد!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} {lightred}{1}{default} را دوباره زنده کرد!",
|
||||
|
||||
"fun_menu_god": "حالت خدا",
|
||||
"fun_menu_noclip": "ناپدیدی",
|
||||
"fun_menu_respawn": "احیا",
|
||||
"fun_menu_give": "دادن سلاح",
|
||||
"fun_menu_give_player": "دادن سلاح: {0}",
|
||||
"fun_menu_strip": "گرفتن سلاحها",
|
||||
"fun_menu_freeze": "یخ زدن",
|
||||
"fun_menu_hp": "تنظیم سلامت",
|
||||
"fun_menu_hp_player": "تنظیم سلامت: {0}",
|
||||
"fun_menu_speed": "تنظیم سرعت",
|
||||
"fun_menu_speed_player": "تنظیم سرعت: {0}",
|
||||
"fun_menu_gravity": "تنظیم جاذبه",
|
||||
"fun_menu_gravity_player": "تنظیم جاذبه: {0}",
|
||||
"fun_menu_money": "تنظیم پول",
|
||||
"fun_menu_money_player": "تنظیم پول: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "سرعت {0}",
|
||||
"fun_menu_gravity_value": "جاذبه {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} اندازه {lightred}{1}{default} را به {lightred}{2}{default} تغییر داد!",
|
||||
"fun_menu_resize": "تغییر اندازه",
|
||||
"fun_menu_resize_player": "تغییر اندازه: {0}",
|
||||
"fun_menu_resize_value": "اندازه {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Commandes Amusantes",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} a donné {lightred}{2}{default} à {lightred}{1}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} a retiré toutes les armes de {lightred}{1}{default}!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} a modifié la quantité de HP de {lightred}{1}{default}!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} a modifié la vitesse de {lightred}{1}{default}!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} a modifié la gravité de {lightred}{1}{default}!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} a modifié l'argent de {lightred}{1}{default}!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} a modifié le mode dieu de {lightred}{1}{default}!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} a activé/désactivé le noclip pour {lightred}{1}{default}!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} a gelé {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} a dégivré {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} a réapparu {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "Mode Dieu",
|
||||
"fun_menu_noclip": "Noclip",
|
||||
"fun_menu_respawn": "Réapparition",
|
||||
"fun_menu_give": "Donner Arme",
|
||||
"fun_menu_give_player": "Donner Arme: {0}",
|
||||
"fun_menu_strip": "Retirer Armes",
|
||||
"fun_menu_freeze": "Geler",
|
||||
"fun_menu_hp": "Définir HP",
|
||||
"fun_menu_hp_player": "Définir HP: {0}",
|
||||
"fun_menu_speed": "Définir Vitesse",
|
||||
"fun_menu_speed_player": "Définir Vitesse: {0}",
|
||||
"fun_menu_gravity": "Définir Gravité",
|
||||
"fun_menu_gravity_player": "Définir Gravité: {0}",
|
||||
"fun_menu_money": "Définir Argent",
|
||||
"fun_menu_money_player": "Définir Argent: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Vitesse {0}",
|
||||
"fun_menu_gravity_value": "Gravité {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} a redimensionné {lightred}{1}{default} à {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "Redimensionner",
|
||||
"fun_menu_resize_player": "Redimensionner: {0}",
|
||||
"fun_menu_resize_value": "Taille {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Izklaidējošas Komandas",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} iedeva {lightred}{1}{default} {lightred}{2}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} noņēma visus {lightred}{1}{default} ieročus!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} mainīja {lightred}{1}{default} HP daudzumu!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} mainīja {lightred}{1}{default} ātrumu!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} mainīja {lightred}{1}{default} gravitāciju!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} mainīja {lightred}{1}{default} naudu!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} mainīja dieva režīmu priekš {lightred}{1}{default}!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} aktivizēja/deaktivizēja noclip priekš {lightred}{1}{default}!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} sasaldēja {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} atkausēja {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} atdzīvināja {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "Dieva Režīms",
|
||||
"fun_menu_noclip": "Noclip",
|
||||
"fun_menu_respawn": "Atdzīvināt",
|
||||
"fun_menu_give": "Dot Ieroci",
|
||||
"fun_menu_give_player": "Dot Ieroci: {0}",
|
||||
"fun_menu_strip": "Noņemt Ieročus",
|
||||
"fun_menu_freeze": "Sasaldēt",
|
||||
"fun_menu_hp": "Uzstādīt HP",
|
||||
"fun_menu_hp_player": "Uzstādīt HP: {0}",
|
||||
"fun_menu_speed": "Uzstādīt Ātrumu",
|
||||
"fun_menu_speed_player": "Uzstādīt Ātrumu: {0}",
|
||||
"fun_menu_gravity": "Uzstādīt Gravitāciju",
|
||||
"fun_menu_gravity_player": "Uzstādīt Gravitāciju: {0}",
|
||||
"fun_menu_money": "Uzstādīt Naudu",
|
||||
"fun_menu_money_player": "Uzstādīt Naudu: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Ātrums {0}",
|
||||
"fun_menu_gravity_value": "Gravitācija {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} mainīja {lightred}{1}{default} izmēru uz {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "Mainīt Izmēru",
|
||||
"fun_menu_resize_player": "Mainīt Izmēru: {0}",
|
||||
"fun_menu_resize_value": "Izmērs {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Komendy Rozrywkowe",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} dał {lightred}{1}{default} przedmiot {lightred}{2}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} zabrał wszystkie bronie {lightred}{1}{default}!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} zmienił ilość hp dla {lightred}{1}{default}!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} zmienił prędkość dla {lightred}{1}{default}!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} zmienił grawitację dla {lightred}{1}{default}!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} zmienił pieniądze dla {lightred}{1}{default}!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} zmienił tryb Boga dla {lightred}{1}{default}!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} ustawił latanie dla {lightred}{1}{default}!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} zamroził {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} odmroził {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} odrodził {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "Tryb Boga",
|
||||
"fun_menu_noclip": "Latanie",
|
||||
"fun_menu_respawn": "Odrodzenie",
|
||||
"fun_menu_give": "Daj Broń",
|
||||
"fun_menu_give_player": "Daj Broń: {0}",
|
||||
"fun_menu_strip": "Zabierz Bronie",
|
||||
"fun_menu_freeze": "Zamrożenie",
|
||||
"fun_menu_hp": "Ustaw HP",
|
||||
"fun_menu_hp_player": "Ustaw HP: {0}",
|
||||
"fun_menu_speed": "Ustaw Prędkość",
|
||||
"fun_menu_speed_player": "Ustaw Prędkość: {0}",
|
||||
"fun_menu_gravity": "Ustaw Grawitację",
|
||||
"fun_menu_gravity_player": "Ustaw Grawitację: {0}",
|
||||
"fun_menu_money": "Ustaw Pieniądze",
|
||||
"fun_menu_money_player": "Ustaw Pieniądze: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Prędkość {0}",
|
||||
"fun_menu_gravity_value": "Grawitacja {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} zmienił rozmiar {lightred}{1}{default} na {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "Zmień Rozmiar",
|
||||
"fun_menu_resize_player": "Zmień Rozmiar: {0}",
|
||||
"fun_menu_resize_value": "Rozmiar {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Comandos Divertidos",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} deu {lightred}{1}{default} um(a) {lightred}{2}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} tirou todas as armas de {lightred}{1}{default}!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} mudou a quantidade de HP de {lightred}{1}{default}!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} mudou a velocidade de {lightred}{1}{default}!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} mudou a gravidade de {lightred}{1}{default}!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} mudou a quantidade de dinheiro de {lightred}{1}{default}!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} mudou o modo Deus de {lightred}{1}{default}!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} ativou/desativou o noclip para {lightred}{1}{default}!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} congelou {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} descongelou {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} reanimou {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "Modo Deus",
|
||||
"fun_menu_noclip": "Noclip",
|
||||
"fun_menu_respawn": "Reanimar",
|
||||
"fun_menu_give": "Dar Arma",
|
||||
"fun_menu_give_player": "Dar Arma: {0}",
|
||||
"fun_menu_strip": "Remover Armas",
|
||||
"fun_menu_freeze": "Congelar",
|
||||
"fun_menu_hp": "Definir HP",
|
||||
"fun_menu_hp_player": "Definir HP: {0}",
|
||||
"fun_menu_speed": "Definir Velocidade",
|
||||
"fun_menu_speed_player": "Definir Velocidade: {0}",
|
||||
"fun_menu_gravity": "Definir Gravidade",
|
||||
"fun_menu_gravity_player": "Definir Gravidade: {0}",
|
||||
"fun_menu_money": "Definir Dinheiro",
|
||||
"fun_menu_money_player": "Definir Dinheiro: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Velocidade {0}",
|
||||
"fun_menu_gravity_value": "Gravidade {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} redimensionou {lightred}{1}{default} para {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "Redimensionar",
|
||||
"fun_menu_resize_player": "Redimensionar: {0}",
|
||||
"fun_menu_resize_value": "Tamanho {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Comandos Divertidos",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} deu {lightred}{1}{default} um(a) {lightred}{2}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} tirou todas as armas de {lightred}{1}{default}!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} mudou a quantidade de HP de {lightred}{1}{default}!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} mudou a velocidade de {lightred}{1}{default}!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} mudou a gravidade de {lightred}{1}{default}!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} mudou a quantidade de dinheiro de {lightred}{1}{default}!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} mudou o modo Deus de {lightred}{1}{default}!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} ativou/desativou o noclip para {lightred}{1}{default}!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} congelou {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} descongelou {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} reanimou {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "Modo Deus",
|
||||
"fun_menu_noclip": "Noclip",
|
||||
"fun_menu_respawn": "Reanimar",
|
||||
"fun_menu_give": "Dar Arma",
|
||||
"fun_menu_give_player": "Dar Arma: {0}",
|
||||
"fun_menu_strip": "Remover Armas",
|
||||
"fun_menu_freeze": "Congelar",
|
||||
"fun_menu_hp": "Definir HP",
|
||||
"fun_menu_hp_player": "Definir HP: {0}",
|
||||
"fun_menu_speed": "Definir Velocidade",
|
||||
"fun_menu_speed_player": "Definir Velocidade: {0}",
|
||||
"fun_menu_gravity": "Definir Gravidade",
|
||||
"fun_menu_gravity_player": "Definir Gravidade: {0}",
|
||||
"fun_menu_money": "Definir Dinheiro",
|
||||
"fun_menu_money_player": "Definir Dinheiro: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Velocidade {0}",
|
||||
"fun_menu_gravity_value": "Gravidade {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} redimensionou {lightred}{1}{default} para {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "Redimensionar",
|
||||
"fun_menu_resize_player": "Redimensionar: {0}",
|
||||
"fun_menu_resize_value": "Tamanho {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Развлекательные Команды",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} дал {lightred}{1}{default} {lightred}{2}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} забрал все оружие у {lightred}{1}{default}!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} изменил количество HP у {lightred}{1}{default}!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} изменил скорость {lightred}{1}{default}!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} изменил гравитацию для {lightred}{1}{default}!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} изменил количество денег у {lightred}{1}{default}!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} изменил режим бога для {lightred}{1}{default}!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} включил/выключил noclip для {lightred}{1}{default}!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} заморозил {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} разморозил {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} возродил {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "Режим Бога",
|
||||
"fun_menu_noclip": "Noclip",
|
||||
"fun_menu_respawn": "Возрождение",
|
||||
"fun_menu_give": "Выдать Оружие",
|
||||
"fun_menu_give_player": "Выдать Оружие: {0}",
|
||||
"fun_menu_strip": "Забрать Оружие",
|
||||
"fun_menu_freeze": "Заморозить",
|
||||
"fun_menu_hp": "Установить HP",
|
||||
"fun_menu_hp_player": "Установить HP: {0}",
|
||||
"fun_menu_speed": "Установить Скорость",
|
||||
"fun_menu_speed_player": "Установить Скорость: {0}",
|
||||
"fun_menu_gravity": "Установить Гравитацию",
|
||||
"fun_menu_gravity_player": "Установить Гравитацию: {0}",
|
||||
"fun_menu_money": "Установить Деньги",
|
||||
"fun_menu_money_player": "Установить Деньги: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Скорость {0}",
|
||||
"fun_menu_gravity_value": "Гравитация {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} изменил размер {lightred}{1}{default} на {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "Изменить Размер",
|
||||
"fun_menu_resize_player": "Изменить Размер: {0}",
|
||||
"fun_menu_resize_value": "Размер {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "Eğlence Komutları",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} {lightred}{1}{default}'e {lightred}{2}{default} verdi!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} {lightred}{1}{default}'in tüm silahlarını aldı!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} {lightred}{1}{default}'in HP miktarını değiştirdi!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} {lightred}{1}{default}'in hızını değiştirdi!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} {lightred}{1}{default}'in yer çekimini değiştirdi!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} {lightred}{1}{default}'in parasını değiştirdi!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} {lightred}{1}{default}'in tanrı modunu değiştirdi!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} {lightred}{1}{default} için noclip'i açtı/kapatı!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} {lightred}{1}{default}'i dondurdu!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} {lightred}{1}{default}'in dondurmasını çözdü!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} {lightred}{1}{default}'i yeniden doğurdu!",
|
||||
|
||||
"fun_menu_god": "Tanrı Modu",
|
||||
"fun_menu_noclip": "Noclip",
|
||||
"fun_menu_respawn": "Yeniden Doğma",
|
||||
"fun_menu_give": "Silah Ver",
|
||||
"fun_menu_give_player": "Silah Ver: {0}",
|
||||
"fun_menu_strip": "Silahları Al",
|
||||
"fun_menu_freeze": "Dondur",
|
||||
"fun_menu_hp": "HP Ayarla",
|
||||
"fun_menu_hp_player": "HP Ayarla: {0}",
|
||||
"fun_menu_speed": "Hız Ayarla",
|
||||
"fun_menu_speed_player": "Hız Ayarla: {0}",
|
||||
"fun_menu_gravity": "Yer Çekimi Ayarla",
|
||||
"fun_menu_gravity_player": "Yer Çekimi Ayarla: {0}",
|
||||
"fun_menu_money": "Para Ayarla",
|
||||
"fun_menu_money_player": "Para Ayarla: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "Hız {0}",
|
||||
"fun_menu_gravity_value": "Yer Çekimi {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} {lightred}{1}{default}'in boyutunu {lightred}{2}{default} olarak değiştirdi!",
|
||||
"fun_menu_resize": "Boyut Değiştir",
|
||||
"fun_menu_resize_player": "Boyut Değiştir: {0}",
|
||||
"fun_menu_resize_value": "Boyut {0}"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fun_category_name": "趣味命令",
|
||||
|
||||
"fun_admin_give_message": "{lightred}{0}{default} 给了 {lightred}{1}{default} {lightred}{2}{default}!",
|
||||
"fun_admin_strip_message": "{lightred}{0}{default} 移除了 {lightred}{1}{default} 的所有武器!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} 修改了 {lightred}{1}{default} 的生命值!",
|
||||
"fun_admin_speed_message": "{lightred}{0}{default} 修改了 {lightred}{1}{default} 的速度!",
|
||||
"fun_admin_gravity_message": "{lightred}{0}{default} 修改了 {lightred}{1}{default} 的重力!",
|
||||
"fun_admin_money_message": "{lightred}{0}{default} 修改了 {lightred}{1}{default} 的金钱!",
|
||||
"fun_admin_god_message": "{lightred}{0}{default} 切换了 {lightred}{1}{default} 的上帝模式!",
|
||||
"fun_admin_noclip_message": "{lightred}{0}{default} 切换了 {lightred}{1}{default} 的穿墙模式!",
|
||||
"fun_admin_freeze_message": "{lightred}{0}{default} 冻结了 {lightred}{1}{default}!",
|
||||
"fun_admin_unfreeze_message": "{lightred}{0}{default} 解冻了 {lightred}{1}{default}!",
|
||||
"fun_admin_respawn_message": "{lightred}{0}{default} 复活了 {lightred}{1}{default}!",
|
||||
|
||||
"fun_menu_god": "上帝模式",
|
||||
"fun_menu_noclip": "穿墙模式",
|
||||
"fun_menu_respawn": "复活",
|
||||
"fun_menu_give": "给予武器",
|
||||
"fun_menu_give_player": "给予武器: {0}",
|
||||
"fun_menu_strip": "移除武器",
|
||||
"fun_menu_freeze": "冻结",
|
||||
"fun_menu_hp": "设置生命值",
|
||||
"fun_menu_hp_player": "设置生命值: {0}",
|
||||
"fun_menu_speed": "设置速度",
|
||||
"fun_menu_speed_player": "设置速度: {0}",
|
||||
"fun_menu_gravity": "设置重力",
|
||||
"fun_menu_gravity_player": "设置重力: {0}",
|
||||
"fun_menu_money": "设置金钱",
|
||||
"fun_menu_money_player": "设置金钱: {0}",
|
||||
"fun_menu_hp_value": "{0} HP",
|
||||
"fun_menu_speed_value": "速度 {0}",
|
||||
"fun_menu_gravity_value": "重力 {0}",
|
||||
"fun_menu_money_value": "${0}",
|
||||
|
||||
"fun_admin_resize_message": "{lightred}{0}{default} 将 {lightred}{1}{default} 的大小改为 {lightred}{2}{default}!",
|
||||
"fun_menu_resize": "调整大小",
|
||||
"fun_menu_resize_player": "调整大小: {0}",
|
||||
"fun_menu_resize_value": "大小 {0}"
|
||||
}
|
||||
384
Modules/CS2-SimpleAdmin_FunCommands/README.md
Normal file
384
Modules/CS2-SimpleAdmin_FunCommands/README.md
Normal file
@@ -0,0 +1,384 @@
|
||||
# CS2-SimpleAdmin Fun Commands Module
|
||||
|
||||
This module serves as a **reference implementation** for creating CS2-SimpleAdmin modules. It demonstrates best practices for menu creation, command registration, translation support, and API usage.
|
||||
|
||||
## 📚 What This Module Teaches
|
||||
|
||||
This module is designed to be educational and shows you how to:
|
||||
|
||||
1. ✅ **Register commands dynamically** from configuration
|
||||
2. ✅ **Create menu categories** and menu items
|
||||
3. ✅ **Use per-player translations** with `ShowAdminActivityLocalized`
|
||||
4. ✅ **Handle player targeting** and validation
|
||||
5. ✅ **Implement proper cleanup** on module unload
|
||||
6. ✅ **Structure code** using partial classes for organization
|
||||
7. ✅ **Cache data** for performance (weapons cache)
|
||||
8. ✅ **Use configuration** to enable/disable features
|
||||
|
||||
## 🎯 Features
|
||||
|
||||
This module provides fun admin commands:
|
||||
|
||||
- **God Mode** (`css_god`) - Toggle god mode for players
|
||||
- **No Clip** (`css_noclip`) - Enable no-clip mode
|
||||
- **Freeze/Unfreeze** (`css_freeze`, `css_unfreeze`) - Freeze players in place
|
||||
- **Respawn** (`css_respawn`) - Respawn dead players
|
||||
- **Give Weapon** (`css_give`) - Give weapons to players
|
||||
- **Strip Weapons** (`css_strip`) - Remove all player weapons
|
||||
- **Set HP** (`css_hp`) - Set player health
|
||||
- **Set Speed** (`css_speed`) - Modify player movement speed
|
||||
- **Set Gravity** (`css_gravity`) - Change player gravity
|
||||
- **Set Money** (`css_money`) - Set player money
|
||||
|
||||
## 📁 File Structure
|
||||
|
||||
```
|
||||
CS2-SimpleAdmin_FunCommands/
|
||||
├── CS2-SimpleAdmin_FunCommands.cs # Main plugin file - initialization, registration
|
||||
├── Commands.cs # Command handlers
|
||||
├── Actions.cs # Action methods (God, NoClip, Freeze, etc.)
|
||||
├── Menus.cs # Menu creation using SimpleAdmin API
|
||||
├── Config.cs # Configuration with command lists
|
||||
└── lang/ # Translation files (13 languages)
|
||||
├── en.json
|
||||
├── pl.json
|
||||
├── ru.json
|
||||
└── ... (10 more languages)
|
||||
```
|
||||
|
||||
## 🔍 Code Organization Explained
|
||||
|
||||
### 1. Main Plugin File (`CS2-SimpleAdmin_FunCommands.cs`)
|
||||
|
||||
**Key Concepts Demonstrated:**
|
||||
|
||||
```csharp
|
||||
public partial class CS2_SimpleAdmin_FunCommands : BasePlugin, IPluginConfig<Config>
|
||||
{
|
||||
// ✅ BEST PRACTICE: Use capability system to get API
|
||||
private ICS2_SimpleAdminApi? _sharedApi;
|
||||
private readonly PluginCapability<ICS2_SimpleAdminApi> _pluginCapability = new("simpleadmin:api");
|
||||
|
||||
// ✅ BEST PRACTICE: Cache expensive data
|
||||
private static Dictionary<int, CsItem>? _weaponsCache;
|
||||
|
||||
// ✅ BEST PRACTICE: Track menu registration state
|
||||
private bool _menusRegistered = false;
|
||||
|
||||
public override void OnAllPluginsLoaded(bool hotReload)
|
||||
{
|
||||
// Get the API
|
||||
_sharedApi = _pluginCapability.Get();
|
||||
|
||||
// Register commands
|
||||
RegisterFunCommands();
|
||||
|
||||
// ✅ BEST PRACTICE: Wait for SimpleAdmin to be ready before registering menus
|
||||
_sharedApi.OnSimpleAdminReady += RegisterFunMenus;
|
||||
RegisterFunMenus(); // Fallback for hot reload
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why partial classes?**
|
||||
- Separates concerns (commands, actions, menus)
|
||||
- Makes code easier to navigate
|
||||
- Each file has a specific purpose
|
||||
|
||||
### 2. Configuration (`Config.cs`)
|
||||
|
||||
**Key Concept:** Command lists for flexibility
|
||||
|
||||
```csharp
|
||||
public class Config : IBasePluginConfig
|
||||
{
|
||||
// ✅ BEST PRACTICE: Allow multiple command aliases
|
||||
public List<string> NoclipCommands { get; set; } = ["css_noclip"];
|
||||
public List<string> GodCommands { get; set; } = ["css_god"];
|
||||
// ... more command lists
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Users can disable features by emptying the list
|
||||
- Users can add command aliases (e.g., `["css_god", "css_godmode"]`)
|
||||
- Menus only register if commands exist
|
||||
|
||||
### 3. Commands (`Commands.cs`)
|
||||
|
||||
**Key Concepts Demonstrated:**
|
||||
|
||||
```csharp
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
private void OnGodCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
// ✅ BEST PRACTICE: Use API to get targets (handles target syntax)
|
||||
var targets = _sharedApi!.GetTarget(command);
|
||||
if (targets == null) return;
|
||||
|
||||
// ✅ BEST PRACTICE: Filter for alive players
|
||||
var playersToTarget = targets.Players.Where(player =>
|
||||
player is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
|
||||
// ✅ BEST PRACTICE: Check targeting permissions
|
||||
playersToTarget.ForEach(player =>
|
||||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
God(caller, player);
|
||||
}
|
||||
});
|
||||
|
||||
// ✅ BEST PRACTICE: Always log commands
|
||||
_sharedApi.LogCommand(caller, command);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Actions (`Actions.cs`)
|
||||
|
||||
**Key Concepts Demonstrated:**
|
||||
|
||||
```csharp
|
||||
private void God(CCSPlayerController? caller, CCSPlayerController player)
|
||||
{
|
||||
// Perform the action
|
||||
if (!GodPlayers.Add(player.Slot))
|
||||
{
|
||||
GodPlayers.Remove(player.Slot);
|
||||
}
|
||||
|
||||
// ✅ BEST PRACTICE: Use per-player language support
|
||||
var activityArgs = new object[] { "CALLER", player.PlayerName };
|
||||
if (caller == null || !_sharedApi!.IsAdminSilent(caller))
|
||||
{
|
||||
if (Localizer != null)
|
||||
{
|
||||
// Each player sees message in their configured language!
|
||||
_sharedApi!.ShowAdminActivityLocalized(Localizer, "fun_admin_god_message", callerName, false, activityArgs);
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ BEST PRACTICE: Log the action
|
||||
_sharedApi!.LogCommand(caller, $"css_god {player.PlayerName}");
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Menus (`Menus.cs`)
|
||||
|
||||
**Key Concepts Demonstrated:**
|
||||
|
||||
#### Simple Player Selection Menu
|
||||
```csharp
|
||||
private object CreateGodModeMenu(CCSPlayerController admin)
|
||||
{
|
||||
// ✅ BEST PRACTICE: Use CreateMenuWithPlayers for simple player selection
|
||||
return _sharedApi!.CreateMenuWithPlayers("God Mode", "fun", admin,
|
||||
player => player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(player),
|
||||
God); // Direct method reference
|
||||
}
|
||||
```
|
||||
|
||||
#### Nested Menu with Value Selection
|
||||
```csharp
|
||||
private object CreateSetHpMenu(CCSPlayerController admin)
|
||||
{
|
||||
// ✅ BEST PRACTICE: Use CreateMenuWithBack for menus with back button
|
||||
var menu = _sharedApi!.CreateMenuWithBack("Set HP", "fun", admin);
|
||||
|
||||
var players = _sharedApi.GetValidPlayers().Where(p =>
|
||||
p.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && admin.CanTarget(p));
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
// ✅ BEST PRACTICE: AddSubMenu automatically adds back button to submenu
|
||||
_sharedApi.AddSubMenu(menu, playerName, p => CreateHpSelectionMenu(admin, player));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
private object CreateHpSelectionMenu(CCSPlayerController admin, CCSPlayerController target)
|
||||
{
|
||||
var hpMenu = _sharedApi!.CreateMenuWithBack($"Set HP: {target.PlayerName}", "fun", admin);
|
||||
var hpValues = new[] { 1, 10, 25, 50, 100, 200, 500, 999 };
|
||||
|
||||
foreach (var hp in hpValues)
|
||||
{
|
||||
// ✅ BEST PRACTICE: AddMenuOption for simple actions
|
||||
_sharedApi.AddMenuOption(hpMenu, $"{hp} HP", _ =>
|
||||
{
|
||||
// ✅ BEST PRACTICE: Always validate before executing
|
||||
if (target.IsValid)
|
||||
{
|
||||
target.SetHp(hp);
|
||||
LogAndShowActivity(admin, target, "fun_admin_hp_message", "css_hp", hp.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return hpMenu;
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Translations
|
||||
|
||||
**Key Concept:** Module-specific translations
|
||||
|
||||
```json
|
||||
// lang/en.json
|
||||
{
|
||||
"fun_admin_god_message": "{lightred}{0}{default} changed god mode for {lightred}{1}{default}!",
|
||||
"fun_admin_hp_message": "{lightred}{0}{default} changed {lightred}{1}{default} hp amount!"
|
||||
}
|
||||
```
|
||||
|
||||
**Why module translations?**
|
||||
- Your module is independent from SimpleAdmin
|
||||
- You can update translations without affecting main plugin
|
||||
- Each player sees messages in their language automatically
|
||||
|
||||
## 🛠️ How to Use This as a Template
|
||||
|
||||
### Step 1: Copy the Module
|
||||
```bash
|
||||
cp -r CS2-SimpleAdmin_FunCommands YourModuleName
|
||||
```
|
||||
|
||||
### Step 2: Rename Files
|
||||
- Rename `.csproj` file
|
||||
- Rename all `.cs` files to match your module name
|
||||
- Update namespace in all files
|
||||
|
||||
### Step 3: Update References
|
||||
- Change `namespace CS2_SimpleAdmin_FunCommands` to `namespace YourModuleName`
|
||||
- Update plugin metadata (name, version, author, description)
|
||||
|
||||
### Step 4: Modify Config
|
||||
```csharp
|
||||
public class Config : IBasePluginConfig
|
||||
{
|
||||
public int Version { get; set; } = 1;
|
||||
|
||||
// Add your own command lists
|
||||
public List<string> YourCommands { get; set; } = ["css_yourcommand"];
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Add Your Commands
|
||||
Look at `Commands.cs` for examples of command handlers
|
||||
|
||||
### Step 6: Add Your Menus
|
||||
Look at `Menus.cs` for examples of menu creation
|
||||
|
||||
### Step 7: Add Translations
|
||||
Create language files in `lang/{language}.json` (e.g., `lang/en.json`, `lang/pl.json`)
|
||||
|
||||
## 📖 Learning Path
|
||||
|
||||
If you're new to module development, study files in this order:
|
||||
|
||||
1. **Config.cs** - Understand configuration structure
|
||||
2. **CS2-SimpleAdmin_FunCommands.cs** - See initialization and API acquisition
|
||||
3. **Commands.cs** - Learn command registration and handling
|
||||
4. **Actions.cs** - Understand action methods and translations
|
||||
5. **Menus.cs** - Study menu creation patterns
|
||||
|
||||
## 🎓 Best Practices Demonstrated
|
||||
|
||||
### ✅ Command Registration
|
||||
```csharp
|
||||
// Dynamic registration based on config
|
||||
if (Config.GodCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.GodCommands)
|
||||
{
|
||||
_sharedApi.RegisterCommand(command, "Enable god mode", OnGodCommand);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Target Validation
|
||||
```csharp
|
||||
// Always check if player can be targeted
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
// Always validate player state
|
||||
if (!player.IsValid) return;
|
||||
```
|
||||
|
||||
### ✅ Translation Usage
|
||||
```csharp
|
||||
// Use module's localizer for per-player language support
|
||||
if (Localizer != null)
|
||||
{
|
||||
_sharedApi.ShowAdminActivityLocalized(Localizer, "translation_key", callerName, false, args);
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Cleanup on Unload
|
||||
```csharp
|
||||
public override void Unload(bool hotReload)
|
||||
{
|
||||
// Unregister all commands
|
||||
if (Config.GodCommands.Count > 0)
|
||||
{
|
||||
foreach (var command in Config.GodCommands)
|
||||
{
|
||||
_sharedApi.UnRegisterCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
// Unregister all menus
|
||||
if (Config.GodCommands.Count > 0)
|
||||
_sharedApi.UnregisterMenu("fun", "god");
|
||||
|
||||
// Remove event handlers
|
||||
_sharedApi.OnSimpleAdminReady -= RegisterFunMenus;
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Data Caching
|
||||
```csharp
|
||||
// Cache expensive operations
|
||||
private static Dictionary<int, CsItem> GetWeaponsCache()
|
||||
{
|
||||
if (_weaponsCache != null) return _weaponsCache;
|
||||
|
||||
var weaponsArray = Enum.GetValues(typeof(CsItem));
|
||||
_weaponsCache = new Dictionary<int, CsItem>();
|
||||
// ... populate cache
|
||||
return _weaponsCache;
|
||||
}
|
||||
```
|
||||
|
||||
## 🔗 Related Documentation
|
||||
|
||||
- **[MODULE_DEVELOPMENT.md](../MODULE_DEVELOPMENT.md)** - Complete API reference
|
||||
- **[TRANSLATION_EXAMPLE.md](../TRANSLATION_EXAMPLE.md)** - Translation usage guide
|
||||
- **[CS2-SimpleAdminApi](../../CS2-SimpleAdminApi/)** - API interface definitions
|
||||
|
||||
## 💡 Tips
|
||||
|
||||
1. **Start Simple** - Begin with one command and one menu, then expand
|
||||
2. **Test Thoroughly** - Test with multiple players, different permissions, and languages
|
||||
3. **Handle Errors** - Always validate player state before actions
|
||||
4. **Log Everything** - Use `_sharedApi.LogCommand()` for all admin actions
|
||||
5. **Use Partial Classes** - Split your code into logical files
|
||||
6. **Comment Your Code** - Especially if others will use it as reference
|
||||
|
||||
## 🐛 Common Mistakes to Avoid
|
||||
|
||||
- ❌ **Don't** forget to check `IsValid` before accessing player properties
|
||||
- ❌ **Don't** skip permission checks (`CanTarget`, `RequiresPermissions`)
|
||||
- ❌ **Don't** forget to unregister commands/menus in `Unload()`
|
||||
- ❌ **Don't** use SimpleAdmin's translations - create your own
|
||||
- ❌ **Don't** hardcode command names - use config lists instead
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
If you improve this module or find better patterns, please contribute back so others can learn!
|
||||
|
||||
## 📄 License
|
||||
|
||||
This module is provided as-is for educational purposes. Feel free to use it as a template for your own modules.
|
||||
7
Modules/CS2-SimpleAdmin_FunCommands/global.json
Normal file
7
Modules/CS2-SimpleAdmin_FunCommands/global.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "8.0.0",
|
||||
"rollForward": "latestMinor",
|
||||
"allowPrerelease": false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user