diff --git a/Jailbreak.sln b/Jailbreak.sln index 6098dfce..14d7be99 100644 --- a/Jailbreak.sln +++ b/Jailbreak.sln @@ -28,6 +28,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Logs", "mod\Jailb EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Debug", "mod\Jailbreak.Debug\Jailbreak.Debug.csproj", "{4F10E2B5-E8BB-4253-9BE6-9187575ADB13}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.LastRequest", "mod\Jailbreak.LastRequest\Jailbreak.LastRequest.csproj", "{D8952626-7B8D-4ABB-A3AE-FC81C688787B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -74,6 +76,10 @@ Global {4F10E2B5-E8BB-4253-9BE6-9187575ADB13}.Debug|Any CPU.Build.0 = Debug|Any CPU {4F10E2B5-E8BB-4253-9BE6-9187575ADB13}.Release|Any CPU.ActiveCfg = Release|Any CPU {4F10E2B5-E8BB-4253-9BE6-9187575ADB13}.Release|Any CPU.Build.0 = Release|Any CPU + {D8952626-7B8D-4ABB-A3AE-FC81C688787B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D8952626-7B8D-4ABB-A3AE-FC81C688787B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D8952626-7B8D-4ABB-A3AE-FC81C688787B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D8952626-7B8D-4ABB-A3AE-FC81C688787B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {9135CCC9-66C5-4A9C-AE3C-91475B5F0437} = {177DA48D-8306-4102-918D-992569878581} @@ -86,5 +92,6 @@ Global {CB2391A1-6CDD-496F-B8D6-674FD6268038} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7} {CE6EC648-E7F9-4CE7-B28F-8C7995830F35} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7} {4F10E2B5-E8BB-4253-9BE6-9187575ADB13} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7} + {D8952626-7B8D-4ABB-A3AE-FC81C688787B} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7} EndGlobalSection EndGlobal diff --git a/lang/Jailbreak.English/Generic/GenericCommandNotifications.cs b/lang/Jailbreak.English/Generic/GenericCommandNotifications.cs index bf9ad7a7..063b73c4 100644 --- a/lang/Jailbreak.English/Generic/GenericCommandNotifications.cs +++ b/lang/Jailbreak.English/Generic/GenericCommandNotifications.cs @@ -11,7 +11,7 @@ namespace Jailbreak.English.Generic; public class GenericCommandNotifications : IGenericCommandNotifications, ILanguage { public static FormatObject PREFIX = - new HiddenFormatObject($" {ChatColors.Darkred}[{ChatColors.LightRed}JB{ChatColors.Darkred}]") + new HiddenFormatObject($" {ChatColors.DarkRed}[{ChatColors.LightRed}JB{ChatColors.DarkRed}]") { // Hide in panorama and center text Plain = false, diff --git a/lang/Jailbreak.English/LastRequest/LastRequestMessages.cs b/lang/Jailbreak.English/LastRequest/LastRequestMessages.cs new file mode 100644 index 00000000..703ac27b --- /dev/null +++ b/lang/Jailbreak.English/LastRequest/LastRequestMessages.cs @@ -0,0 +1,89 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Formatting.Base; +using Jailbreak.Formatting.Core; +using Jailbreak.Formatting.Logistics; +using Jailbreak.Formatting.Objects; +using Jailbreak.Formatting.Views; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.English.LastRequest; + +public class LastRequestMessages : ILastRequestMessages, ILanguage +{ + public static FormatObject PREFIX = + new HiddenFormatObject($" {ChatColors.DarkRed}[{ChatColors.LightRed}LR{ChatColors.DarkRed}]") + { + // Hide in panorama and center text + Plain = false, + Panorama = false, + Chat = true + }; + + public IView LastRequestEnabled() => new SimpleView() + { + { PREFIX, "Last Request has been enabled." } + }; + + public IView LastRequestDisabled() => new SimpleView() + { + { PREFIX, "Last Request has been disabled." } + }; + + public IView LastRequestNotEnabled() => new SimpleView() + { + { PREFIX, "Last Request is not enabled." } + }; + + public IView InvalidLastRequest(string query) + { + return new SimpleView() + { + PREFIX, + "Invalid Last Request: ", + query + }; + } + + public IView InvalidPlayerChoice(CCSPlayerController player, string reason) + { + return new SimpleView() + { + PREFIX, + "Invalid player choice: ", + player, + " Reason: ", + reason + }; + } + + public IView InformLastRequest(AbstractLastRequest lr) + { + return new SimpleView() + { + PREFIX, + lr.prisoner, "is preparing a", lr.type.ToFriendlyString(), + "Last Request against", lr.guard + }; + } + + public IView AnnounceLastRequest(AbstractLastRequest lr) + { + return new SimpleView() + { + PREFIX, + lr.prisoner, "is doing a", lr.type.ToFriendlyString(), + "Last Request against", lr.guard + }; + } + + public IView LastRequestDecided(AbstractLastRequest lr, LRResult result) + { + return new SimpleView() + { + PREFIX, + result == LRResult.PrisonerWin ? lr.prisoner : lr.guard, "won the LR." + }; + } +} \ No newline at end of file diff --git a/lang/Jailbreak.English/Rebel/RebelNotifications.cs b/lang/Jailbreak.English/Rebel/RebelNotifications.cs index c4e440a6..37d4c1a7 100644 --- a/lang/Jailbreak.English/Rebel/RebelNotifications.cs +++ b/lang/Jailbreak.English/Rebel/RebelNotifications.cs @@ -10,7 +10,7 @@ namespace Jailbreak.English.Rebel; public class RebelNotifications : IRebelNotifications, ILanguage { - public static FormatObject PREFIX = new HiddenFormatObject($" {ChatColors.Darkred}[{ChatColors.LightRed}Rebel{ChatColors.Darkred}]") + public static FormatObject PREFIX = new HiddenFormatObject($" {ChatColors.DarkRed}[{ChatColors.LightRed}Rebel{ChatColors.DarkRed}]") { // Hide in panorama and center text Plain = false, diff --git a/lang/Jailbreak.English/Warden/SpecialTreatmentNotifications.cs b/lang/Jailbreak.English/Warden/SpecialTreatmentNotifications.cs new file mode 100644 index 00000000..38699f51 --- /dev/null +++ b/lang/Jailbreak.English/Warden/SpecialTreatmentNotifications.cs @@ -0,0 +1,38 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; + +using Jailbreak.Formatting.Base; +using Jailbreak.Formatting.Core; +using Jailbreak.Formatting.Logistics; +using Jailbreak.Formatting.Objects; +using Jailbreak.Formatting.Views; + +namespace Jailbreak.English.Warden; + +public class SpecialTreatmentNotifications : ISpecialTreatmentNotifications, ILanguage +{ + public static FormatObject PREFIX = new HiddenFormatObject( $" {ChatColors.Lime}[{ChatColors.Green}ST{ChatColors.Lime}]" ) + { + // Hide in panorama and center text + Plain = false, + Panorama = false, + Chat = true, + }; + + public IView GRANTED => + new SimpleView { PREFIX, "You now have special treatment!" }; + + public IView REVOKED => + new SimpleView { PREFIX, "Your special treatment was removed" }; + + public IView GRANTED_TO(CCSPlayerController player) + { + return new SimpleView { PREFIX, player, "now has Special Treatment!" }; + } + + public IView REVOKED_FROM(CCSPlayerController player) + { + return new SimpleView { PREFIX, player, "no longer has Special Treatment." }; + } + +} diff --git a/mod/Jailbreak.Debug/DebugCommand.cs b/mod/Jailbreak.Debug/DebugCommand.cs index 016806d1..ee56e7c7 100644 --- a/mod/Jailbreak.Debug/DebugCommand.cs +++ b/mod/Jailbreak.Debug/DebugCommand.cs @@ -11,11 +11,18 @@ namespace Jailbreak.Debug; public class DebugCommand : IPluginBehavior { private readonly Dictionary _commands = new(); + private BasePlugin plugin; + + public void Start(BasePlugin parent) + { + plugin = parent; + } public DebugCommand(IServiceProvider serviceProvider) { _commands.Add("markrebel", new MarkRebel(serviceProvider)); _commands.Add("pardon", new Pardon(serviceProvider)); + _commands.Add("lr", new Subcommands.LastRequest(serviceProvider, plugin)); } diff --git a/mod/Jailbreak.Debug/Jailbreak.Debug.csproj b/mod/Jailbreak.Debug/Jailbreak.Debug.csproj index 7997b564..b868f93e 100644 --- a/mod/Jailbreak.Debug/Jailbreak.Debug.csproj +++ b/mod/Jailbreak.Debug/Jailbreak.Debug.csproj @@ -9,6 +9,7 @@ + diff --git a/mod/Jailbreak.Debug/Subcommands/LastRequest.cs b/mod/Jailbreak.Debug/Subcommands/LastRequest.cs new file mode 100644 index 00000000..375c9af8 --- /dev/null +++ b/mod/Jailbreak.Debug/Subcommands/LastRequest.cs @@ -0,0 +1,81 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; +using Jailbreak.LastRequest; +using Jailbreak.Public.Extensions; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; +using Microsoft.Extensions.DependencyInjection; + +namespace Jailbreak.Debug.Subcommands; + +public class LastRequest : AbstractCommand +{ + private ILastRequestManager manager; + private LastRequestPlayerSelector playerSelector; + private LastRequestMenuSelector menuSelector; + private ILastRequestMessages _messages; + private IGenericCommandNotifications _generic; + + private BasePlugin plugin; + + public LastRequest(IServiceProvider services, BasePlugin plugin) : base(services) + { + this.plugin = plugin; + manager = services.GetRequiredService(); + playerSelector = new LastRequestPlayerSelector(manager, true); + menuSelector = new LastRequestMenuSelector(services.GetRequiredService(), + (type) => "css_debug lastrequest " + type); + _messages = services.GetRequiredService(); + _generic = services.GetRequiredService(); + } + + // css_lastrequest [lr] [player] + public override void OnCommand(CCSPlayerController? executor, WrappedInfo info) + { + if (executor != null && !executor.IsReal()) + return; + + if (info.ArgCount == 1 && executor != null) + { + MenuManager.OpenCenterHtmlMenu(plugin, executor, menuSelector.GetMenu()); + } + + var type = LRTypeExtensions.FromString(info.GetArg(1)); + if (type is null) + { + _messages.InvalidLastRequest(info.GetArg(1)).ToPlayerChat(executor); + return; + } + + if (info.ArgCount == 2) + { + MenuManager.OpenCenterHtmlMenu(plugin, executor, + playerSelector.CreateMenu(executor, (str) => "css_debug lastrequest " + type + " #" + str)); + return; + } + + var fromPlayer = GetVulnerableTarget(info, 2); + if (fromPlayer == null) + return; + + if (info.ArgCount == 3 && executor != null) + { + if (executor.Team == CsTeam.Terrorist) + manager.InitiateLastRequest(executor, fromPlayer.First(), type.Value); + else // They aren't necessarily on different teams, but this is debug so that's OK + manager.InitiateLastRequest(fromPlayer.First(), executor, type.Value); + return; + } + + if (info.ArgCount == 4) + { + var targetPlayer = GetVulnerableTarget(info, 3); + if (targetPlayer == null) + return; + manager.InitiateLastRequest(fromPlayer.First(), targetPlayer.First(), type.Value); + } + } +} \ No newline at end of file diff --git a/mod/Jailbreak.Debug/Subcommands/WrappedInfo.cs b/mod/Jailbreak.Debug/Subcommands/WrappedInfo.cs index cf3bea1b..d5933dde 100644 --- a/mod/Jailbreak.Debug/Subcommands/WrappedInfo.cs +++ b/mod/Jailbreak.Debug/Subcommands/WrappedInfo.cs @@ -32,8 +32,8 @@ public string GetArg(int index) return Info.GetArg(index + 1); } - public void ReplyToCommand(string message, bool console = false) + public void ReplyToCommand(string message) { - Info.ReplyToCommand(message, console); + Info.ReplyToCommand(message); } } \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/Jailbreak.LastRequest.csproj b/mod/Jailbreak.LastRequest/Jailbreak.LastRequest.csproj new file mode 100644 index 00000000..87ee1a09 --- /dev/null +++ b/mod/Jailbreak.LastRequest/Jailbreak.LastRequest.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + + + + + + + + diff --git a/mod/Jailbreak.LastRequest/LastRequestCommand.cs b/mod/Jailbreak.LastRequest/LastRequestCommand.cs new file mode 100644 index 00000000..5a69329d --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequestCommand.cs @@ -0,0 +1,139 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Commands.Targeting; +using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; +using Jailbreak.Public.Behaviors; +using Jailbreak.Public.Extensions; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; +using Microsoft.Extensions.DependencyModel; + +namespace Jailbreak.LastRequest; + +public class LastRequestCommand : IPluginBehavior +{ + private ILastRequestManager _lrManager; + private LastRequestMenuSelector menuSelector; + private LastRequestPlayerSelector playerSelector; + private BasePlugin plugin; + private ILastRequestMessages _messages; + private IGenericCommandNotifications _generic; + private ILastRequestFactory _factory; + + // css_lr + public LastRequestCommand(ILastRequestManager manager, ILastRequestMessages messages, + IGenericCommandNotifications generic, ILastRequestFactory factory) + { + _lrManager = manager; + _messages = messages; + _generic = generic; + _factory = factory; + } + + public void Start(BasePlugin plugin) + { + this.plugin = plugin; + playerSelector = new LastRequestPlayerSelector(_lrManager); + menuSelector = new LastRequestMenuSelector(_factory); + } + + + [ConsoleCommand("css_lr", "Start a last request as a prisoner")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + public void Command_LastRequest(CCSPlayerController? executor, CommandInfo info) + { + if (executor == null || !executor.IsReal()) + return; + if (executor.Team != CsTeam.Terrorist) + { + info.ReplyToCommand("You must be a terrorist to LR."); + return; + } + + if (!executor.PawnIsAlive) + { + info.ReplyToCommand("You must be alive to LR."); + return; + } + + if (!_lrManager.IsLREnabled) + { + _messages.LastRequestNotEnabled().ToPlayerChat(executor); + return; + } + + if (!playerSelector.WouldHavePlayers()) + { + info.ReplyToCommand("There are no players available to LR."); + return; + } + + if (_lrManager.IsInLR(executor)) + { + info.ReplyToCommand("You are already in an LR!"); + return; + } + + if (info.ArgCount == 1) + { + MenuManager.OpenCenterHtmlMenu(plugin, executor, menuSelector.GetMenu()); + return; + } + + // Validate LR + var type = LRTypeExtensions.FromString(info.GetArg(1)); + if (type is null) + { + _messages.InvalidLastRequest(info.GetArg(1)).ToPlayerChat(executor); + return; + } + + if (info.ArgCount == 2) + { + MenuManager.OpenCenterHtmlMenu(plugin, executor, + playerSelector.CreateMenu(executor, (str) => "css_lr " + type + " #" + str)); + return; + } + + var target = info.GetArgTargetResult(2); + if (!target.Players.Any()) + { + _generic.PlayerNotFound(info.GetArg(2)); + return; + } + + if (target.Players.Count > 1) + { + _generic.PlayerFoundMultiple(info.GetArg(2)); + return; + } + + var player = target.Players.First(); + if (player.Team != CsTeam.CounterTerrorist) + { + _messages.InvalidPlayerChoice(player, "They're not on CT!"); + return; + } + + if (!player.PawnIsAlive) + { + _messages.InvalidPlayerChoice(player, "They're not alive!"); + return; + } + + if (_lrManager.IsInLR(player)) + { + _messages.InvalidPlayerChoice(player, "They're already in an LR!"); + return; + } + + if (!_lrManager.InitiateLastRequest(executor, player, (LRType)type)) + { + info.ReplyToCommand("An error occurred while initiating the last request. Please try again later."); + } + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequestConfig.cs b/mod/Jailbreak.LastRequest/LastRequestConfig.cs new file mode 100644 index 00000000..fd59e8aa --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequestConfig.cs @@ -0,0 +1,6 @@ +namespace Jailbreak.LastRequest; + +public class LastRequestConfig +{ + public int PrisonersToActiveLR { get; set; } = 2; +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequestExtension.cs b/mod/Jailbreak.LastRequest/LastRequestExtension.cs new file mode 100644 index 00000000..37bd3e7b --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequestExtension.cs @@ -0,0 +1,17 @@ +using Jailbreak.Public.Extensions; +using Jailbreak.Public.Mod.LastRequest; +using Microsoft.Extensions.DependencyInjection; + +namespace Jailbreak.LastRequest; + +public static class LastRequestExtension +{ + public static void AddJailbreakLastRequest(this IServiceCollection collection) + { + collection.AddConfig("lastrequest"); + + collection.AddPluginBehavior(); + collection.AddPluginBehavior(); + collection.AddPluginBehavior(); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequestFactory.cs b/mod/Jailbreak.LastRequest/LastRequestFactory.cs new file mode 100644 index 00000000..e7437b76 --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequestFactory.cs @@ -0,0 +1,50 @@ +using CounterStrikeSharp.API.Core; +using Jailbreak.LastRequest.LastRequests; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest; + +public class LastRequestFactory : ILastRequestFactory +{ + private BasePlugin plugin; + private ILastRequestManager manager; + + public LastRequestFactory(ILastRequestManager manager) + { + this.manager = manager; + } + + public void Start(BasePlugin parent) + { + plugin = parent; + } + + public AbstractLastRequest CreateLastRequest(CCSPlayerController prisoner, CCSPlayerController guard, LRType type) + { + return type switch + { + LRType.KnifeFight => new KnifeFight(plugin, manager, prisoner, guard), + LRType.GunToss => new GunToss(plugin, manager, prisoner, guard), + LRType.NoScope => new NoScope(plugin, manager, prisoner, guard), + LRType.RockPaperScissors => new RockPaperScissors(plugin, manager, prisoner, guard), + LRType.Coinflip => new Coinflip(plugin, manager, prisoner, guard), + // LRType.ShotForShot => new ShotForShot(plugin, manager, prisoner, guard), + // LRType.MagForMag => new MagForMag(plugin, manager, prisoner, guard), + _ => throw new ArgumentException("Invalid last request type: " + type, nameof(type)) + }; + } + + public bool IsValidType(LRType type) + { + return type switch + { + LRType.KnifeFight => true, + LRType.GunToss => true, + LRType.NoScope => true, + LRType.RockPaperScissors => true, + LRType.Coinflip => true, + _ => false + }; + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequestManager.cs b/mod/Jailbreak.LastRequest/LastRequestManager.cs new file mode 100644 index 00000000..6a2cf035 --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequestManager.cs @@ -0,0 +1,213 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; +using Jailbreak.Public.Behaviors; +using Jailbreak.Public.Extensions; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; +using Microsoft.Extensions.DependencyInjection; + +namespace Jailbreak.LastRequest; + +public class LastRequestManager : ILastRequestManager +{ + private BasePlugin _parent; + private LastRequestConfig config; + private ILastRequestMessages messages; + private ILastRequestFactory factory; + private IServiceProvider provider; + + public bool IsLREnabled { get; set; } + public IList ActiveLRs { get; } = new List(); + + public LastRequestManager(LastRequestConfig config, ILastRequestMessages messages, IServiceProvider provider) + { + this.config = config; + this.messages = messages; + this.provider = provider; + } + + public void Start(BasePlugin parent) + { + this.factory = provider.GetRequiredService(); + _parent = parent; + _parent.RegisterEventHandler(OnPlayerDeath); + VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); + } + + public void Dispose() + { + VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamage, HookMode.Pre); + } + + private HookResult OnTakeDamage(DynamicHook handle) + { + if (!IsLREnabled) + return HookResult.Continue; + CEntityInstance victim = handle.GetParam(0); + CTakeDamageInfo damage_info = handle.GetParam(1); + + CHandle dealer = damage_info.Attacker; + + if (dealer.Value == null) + { + return HookResult.Continue; + } + + // get player and attacker + CCSPlayerController? player = new CCSPlayerController(new CBaseEntity(victim.Handle).Handle); + CCSPlayerController? attacker = new CCSPlayerController(dealer.Value.Handle); + + if (!player.IsReal() || !attacker.IsReal()) + return HookResult.Continue; + + var playerLR = ((ILastRequestManager)this).GetActiveLR(player); + var attackerLR = ((ILastRequestManager)this).GetActiveLR(attacker); + + if ((playerLR == null) != (attackerLR == null)) + { + // One of them is in an LR + attacker.PrintToChat("You or they are in LR, damage blocked."); + damage_info.Damage = 0; + return HookResult.Changed; + } + + if (playerLR == null && attackerLR == null) + { + // Neither of them is in an LR + return HookResult.Continue; + } + + // Both of them are in LR + // verify they're in same LR + if (playerLR == null) + return HookResult.Continue; + + if (playerLR.prisoner.Slot == attacker.Slot || playerLR.guard.Slot == attacker.Slot) + { + // Same LR, allow damage + return HookResult.Changed; + } + + attacker.PrintToChat("You are not in the same LR as them, damage blocked."); + damage_info.Damage = 0; + return HookResult.Continue; + } + + [GameEventHandler] + public HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) + { + IsLREnabled = false; + return HookResult.Continue; + } + + [GameEventHandler] + public HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) + { + if (GetGameRules().WarmupPeriod) + return HookResult.Continue; + if (CountAlivePrisoners() > config.PrisonersToActiveLR) + return HookResult.Continue; + this.IsLREnabled = true; + messages.LastRequestEnabled().ToAllChat(); + return HookResult.Continue; + } + + [GameEventHandler(HookMode.Post)] + public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) + { + var player = @event.Userid; + if (!player.IsReal() || GetGameRules().WarmupPeriod) + return HookResult.Continue; + + if (IsLREnabled) + { + // Handle active LRs + var activeLr = ((ILastRequestManager)this).GetActiveLR(player); + if (activeLr != null && activeLr.state != LRState.Completed) + { + var isPrisoner = activeLr.prisoner.Slot == player.Slot; + EndLastRequest(activeLr, isPrisoner ? LRResult.GuardWin : LRResult.PrisonerWin); + } + + return HookResult.Continue; + } + + if (player.GetTeam() != CsTeam.Terrorist) + return HookResult.Continue; + + if (CountAlivePrisoners() - 1 > config.PrisonersToActiveLR) + return HookResult.Continue; + + IsLREnabled = true; + messages.LastRequestEnabled().ToAllChat(); + return HookResult.Continue; + } + + private int CountAlivePrisoners() + { + return Utilities.GetPlayers().Count(CountsToLR); + } + + private bool CountsToLR(CCSPlayerController player) + { + if (!player.IsReal()) + return false; + if (!player.PawnIsAlive) + return false; + return player.GetTeam() == CsTeam.Terrorist; + } + + public bool InitiateLastRequest(CCSPlayerController prisoner, CCSPlayerController guard, LRType type) + { + try + { + var lr = factory.CreateLastRequest(prisoner, guard, type); + lr.Setup(); + ActiveLRs.Add(lr); + + if (prisoner.Pawn.Value != null) + { + prisoner.Pawn.Value.Health = 100; + prisoner.PlayerPawn.Value!.ArmorValue = 0; + Utilities.SetStateChanged(prisoner.Pawn.Value, "CBaseEntity", "m_iHealth"); + } + + + if (guard.Pawn.Value != null) + { + guard.Pawn.Value.Health = 100; + guard.PlayerPawn.Value!.ArmorValue = 0; + Utilities.SetStateChanged(guard.Pawn.Value, "CBaseEntity", "m_iHealth"); + } + + messages.InformLastRequest(lr).ToPlayerChat(prisoner); + messages.InformLastRequest(lr).ToPlayerChat(guard); + return true; + } + catch (ArgumentException e) + { + Console.WriteLine(e); + return false; + } + } + + public bool EndLastRequest(AbstractLastRequest lr, LRResult result) + { + if (result is LRResult.GuardWin or LRResult.PrisonerWin) + messages.LastRequestDecided(lr, result).ToAllChat(); + lr.OnEnd(result); + ActiveLRs.Remove(lr); + return true; + } + + public static CCSGameRules GetGameRules() + { + return Utilities.FindAllEntitiesByDesignerName("cs_gamerules").First().GameRules!; + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequestMenuSelector.cs b/mod/Jailbreak.LastRequest/LastRequestMenuSelector.cs new file mode 100644 index 00000000..1a3b40ad --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequestMenuSelector.cs @@ -0,0 +1,43 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Entities; +using CounterStrikeSharp.API.Modules.Menu; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest; + +public class LastRequestMenuSelector +{ + private readonly CenterHtmlMenu menu; + private Func command; + private readonly ILastRequestFactory factory; + + public LastRequestMenuSelector(ILastRequestFactory factory) : this(factory, (lr) => "css_lr " + ((int)lr)) + { + this.factory = factory; + } + + public LastRequestMenuSelector(ILastRequestFactory factory, Func command) + { + this.factory = factory; + this.command = command; + menu = new CenterHtmlMenu("css_lr [LR] [Player]"); + foreach (LRType lr in Enum.GetValues(typeof(LRType))) + { + if (!factory.IsValidType(lr)) + continue; + menu.AddMenuOption(lr.ToFriendlyString(), (p, o) => OnSelectLR(p, lr)); + } + } + + public CenterHtmlMenu GetMenu() + { + return menu; + } + + private void OnSelectLR(CCSPlayerController player, LRType lr) + { + MenuManager.CloseActiveMenu(player); + player.ExecuteClientCommandFromServer(this.command.Invoke(lr)); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequestPlayerSelector.cs b/mod/Jailbreak.LastRequest/LastRequestPlayerSelector.cs new file mode 100644 index 00000000..36f8e191 --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequestPlayerSelector.cs @@ -0,0 +1,50 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Public.Extensions; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest; + +public class LastRequestPlayerSelector +{ + private ILastRequestManager _lrManager; + private bool debug; + + public LastRequestPlayerSelector(ILastRequestManager manager, bool debug = false) + { + _lrManager = manager; + this.debug = debug; + } + + public CenterHtmlMenu CreateMenu(CCSPlayerController player, Func command) + { + CenterHtmlMenu menu = new CenterHtmlMenu(command.Invoke("[Player]")); + + foreach (var target in Utilities.GetPlayers()) + { + if (!target.IsReal()) + continue; + if (!target.PawnIsAlive || target.Team != CsTeam.CounterTerrorist && !debug) + continue; + menu.AddMenuOption(target.PlayerName, + (selector, _) => + OnSelect(player, command, target.UserId.ToString()), + !debug && _lrManager.IsInLR(target) + ); + } + + return menu; + } + + public bool WouldHavePlayers() => Utilities.GetPlayers() + .Any(p => p.IsReal() && p is { PawnIsAlive: true, Team: CsTeam.CounterTerrorist }); + + private void OnSelect(CCSPlayerController player, Func command, string? value) + { + MenuManager.CloseActiveMenu(player); + player.ExecuteClientCommandFromServer(command.Invoke(value)); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequests/Coinflip.cs b/mod/Jailbreak.LastRequest/LastRequests/Coinflip.cs new file mode 100644 index 00000000..de87ab2f --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequests/Coinflip.cs @@ -0,0 +1,102 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Menu; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; +using Timer = CounterStrikeSharp.API.Modules.Timers.Timer; + +namespace Jailbreak.LastRequest.LastRequests; + +public class Coinflip : AbstractLastRequest +{ + private ChatMenu menu; + private Random rnd; + private Timer timeout; + + public Coinflip(BasePlugin plugin, ILastRequestManager manager, CCSPlayerController prisoner, + CCSPlayerController guard) : base(plugin, manager, prisoner, guard) + { + rnd = new Random(); + menu = new ChatMenu("Heads or Tails?"); + menu.AddMenuOption("Heads", (_, _) => Decide(true, true)); + menu.AddMenuOption("Tails", (_, _) => Decide(false, true)); + } + + public override LRType type => LRType.Coinflip; + + public override void Setup() + { + state = LRState.Pending; + menu.Title = "Heads or Tails? - " + prisoner.PlayerName + " vs " + guard.PlayerName; + Execute(); + } + + public override void Execute() + { + state = LRState.Active; + MenuManager.OpenChatMenu(guard, menu); + + timeout = plugin.AddTimer(10, () => + { + if (state != LRState.Active) + return; + MenuManager.CloseActiveMenu(guard); + bool choice = rnd.Next(2) == 1; + guard.PrintToChat($"You failed to choose in time, defaulting to {(choice ? "Heads" : "Tails")}"); + Decide(choice, true); + }); + } + + private void Decide(bool heads, bool print) + { + timeout.Kill(); + if (print) + { + MenuManager.CloseActiveMenu(guard); + PrintToParticipants($"{guard.PlayerName} chose {(heads ? "Heads" : "Tails")}... flipping..."); + state = LRState.Active; + } + plugin.AddTimer(2, () => + { + if (rnd.Next(4) == 0) + { + PrintToParticipants(events[rnd.Next(events.Length)]); + plugin.AddTimer(2, () => Decide(heads, false)); + } + else + { + var side = rnd.Next(2) == 1; + PrintToParticipants($"The coin lands on {(side ? "Heads" : "Tails")}!"); + manager.EndLastRequest(this, side == heads ? LRResult.GuardWin : LRResult.PrisonerWin); + } + }); + } + + private readonly string[] events = + { + "A glint of silver flashes through the air...", + "The coin does a 180...!", + "Gravity seems so much heavier...", + "A quiet clink is heard...", + "An arrow hits the coin!", + "The coin is shot in mid-air.", + "The answer is 42", + "And yet...", + "A sliver of copper falls off...", + "Lucky number 7...", + "The coin lands on its side!", + "A bald eagle soars above", + "There wasn't enough room for the two of ya anyways...", + "Woosh woosh woosh", + "banana rotate" + }; + + public override void OnEnd(LRResult result) + { + state = LRState.Completed; + if (result == LRResult.PrisonerWin) + guard.Pawn.Value?.CommitSuicide(false, true); + else + prisoner.Pawn.Value?.CommitSuicide(false, true); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequests/GunToss.cs b/mod/Jailbreak.LastRequest/LastRequests/GunToss.cs new file mode 100644 index 00000000..c8806af1 --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequests/GunToss.cs @@ -0,0 +1,43 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest.LastRequests; + +public class GunToss : AbstractLastRequest +{ + public GunToss(BasePlugin plugin, ILastRequestManager manager, CCSPlayerController prisoner, + CCSPlayerController guard) : base(plugin, manager, prisoner, guard) + { + } + + public override LRType type => LRType.GunToss; + + public override void Setup() + { + // Strip weapons, teleport T to CT + prisoner.RemoveWeapons(); + guard.RemoveWeapons(); + guard.Teleport(prisoner.Pawn.Value!.AbsOrigin!, prisoner.Pawn.Value.AbsRotation!, new Vector()); + state = LRState.Pending; + + plugin.AddTimer(3, Execute); + } + + public override void Execute() + { + prisoner.GiveNamedItem("weapon_knife"); + guard.GiveNamedItem("weapon_knife"); + prisoner.GiveNamedItem("weapon_deagle"); + guard.GiveNamedItem("weapon_deagle"); + state = LRState.Active; + } + + public override void OnEnd(LRResult result) + { + state = LRState.Completed; + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequests/KnifeFight.cs b/mod/Jailbreak.LastRequest/LastRequests/KnifeFight.cs new file mode 100644 index 00000000..f86a0657 --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequests/KnifeFight.cs @@ -0,0 +1,32 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest.LastRequests; + +public class KnifeFight : WeaponizedRequest +{ + public KnifeFight(BasePlugin plugin, ILastRequestManager manager, CCSPlayerController prisoner, + CCSPlayerController guard) : base(plugin, manager, + prisoner, guard) + { + } + + public override LRType type => LRType.KnifeFight; + + public override void Execute() + { + PrintToParticipants("Go!"); + prisoner.GiveNamedItem("weapon_knife"); + guard.GiveNamedItem("weapon_knife"); + this.state = LRState.Active; + } + + public override void OnEnd(LRResult result) + { + state = LRState.Completed; + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequests/MagForMag.cs b/mod/Jailbreak.LastRequest/LastRequests/MagForMag.cs new file mode 100644 index 00000000..02aba9f1 --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequests/MagForMag.cs @@ -0,0 +1,136 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Timers; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Public.Extensions; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest.LastRequests; + +public class MagForMag : WeaponizedRequest +{ + public MagForMag(BasePlugin plugin, ILastRequestManager manager, CCSPlayerController prisoner, + CCSPlayerController guard) : base(plugin, manager, prisoner, guard) + { + } + + public override LRType type => LRType.GunToss; + private CCSPlayerController whosShot; + private int bulletCount = 7; + + public override void Setup() + { + plugin.RegisterEventHandler(OnPlayerShoot); + base.Setup(); + + whosShot = new Random().Next(2) == 0 ? prisoner : guard; + PrintToParticipants(whosShot.PlayerName + " will shoot first."); + prisoner.GiveNamedItem("weapon_deagle"); + guard.GiveNamedItem("weapon_deagle"); + + var weapon = FindWeapon(prisoner, "weapon_deagle"); + if (weapon != null) + setAmmoAmount(weapon, 0, 0); + weapon = FindWeapon(guard, "weapon_deagle"); + if (weapon != null) + setAmmoAmount(weapon, 0, 0); + } + + private static CBasePlayerWeapon? FindWeapon(CCSPlayerController player, String name) + { + if (!player.IsReal()) + return null; + + var pawn = player.PlayerPawn.Value; + + if (pawn == null) + return null; + + var weapons = pawn.WeaponServices?.MyWeapons; + + return weapons?.Select(weaponOpt => weaponOpt.Value).OfType() + .FirstOrDefault(weapon => weapon.DesignerName.Contains(name)); + } + + private static void setAmmoAmount(CBasePlayerWeapon weapon, int primary, int reserve) + { + weapon.Clip1 = primary; + Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_iClip1"); + weapon.Clip2 = reserve; + Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_pReserveAmmo"); + } + + public override void Execute() + { + state = LRState.Active; + var deagle = FindWeapon(whosShot, "weapon_deagle"); + if (deagle != null) + setAmmoAmount(deagle, bulletCount, 0); + + plugin.AddTimer(30, () => + { + if (state != LRState.Active) + return; + prisoner.GiveNamedItem("weapon_knife"); + guard.GiveNamedItem("weapon_knife"); + }); + plugin.AddTimer(60, () => + { + if (state != LRState.Active) return; + PrintToParticipants("Time's Up!"); + var result = guard.Health > prisoner.Health ? LRResult.GuardWin : LRResult.PrisonerWin; + if (guard.Health == prisoner.Health) + { + PrintToParticipants("Even health, since " + whosShot.PlayerName + " had the shot last, they lose."); + result = whosShot.Slot == prisoner.Slot ? LRResult.GuardWin : LRResult.PrisonerWin; + } + else + { + PrintToParticipants("Health was the deciding factor. "); + } + + manager.EndLastRequest(this, result); + if (result == LRResult.GuardWin) + prisoner.Pawn.Value?.CommitSuicide(false, true); + else + guard.Pawn.Value?.CommitSuicide(false, true); + }, TimerFlags.STOP_ON_MAPCHANGE); + } + + public HookResult OnPlayerShoot(EventPlayerShoot @event, GameEventInfo info) + { + if (state != LRState.Active) + return HookResult.Continue; + + var player = @event.Userid; + if (!player.IsReal()) + return HookResult.Continue; + + if (player.Slot != prisoner.Slot && player.Slot != guard.Slot) + return HookResult.Continue; + + var shootersDeagle = FindWeapon(player, "weapon_deagle"); + if (shootersDeagle == null) + return HookResult.Continue; + + if (shootersDeagle.Clip1 != 0) + return HookResult.Continue; + + PrintToParticipants(player.PlayerName + " has shot."); + var opponent = player.Slot == prisoner.Slot ? guard : prisoner; + opponent.PrintToChat("Your shot"); + var deagle = FindWeapon(opponent, "weapon_deagle"); + if (deagle != null) + setAmmoAmount(deagle, 0, bulletCount); + whosShot = opponent; + return HookResult.Continue; + } + + public override void OnEnd(LRResult result) + { + plugin.RemoveListener("player_shoot", OnPlayerShoot); + state = LRState.Completed; + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequests/NoScope.cs b/mod/Jailbreak.LastRequest/LastRequests/NoScope.cs new file mode 100644 index 00000000..4c8326c4 --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequests/NoScope.cs @@ -0,0 +1,72 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Timers; +using Jailbreak.Public.Extensions; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest.LastRequests; + +public class NoScope : WeaponizedRequest +{ + public NoScope(BasePlugin plugin, ILastRequestManager manager, CCSPlayerController prisoner, + CCSPlayerController guard) : base(plugin, manager, + prisoner, guard) + { + } + + public override LRType type => LRType.NoScope; + + public override void Setup() + { + base.Setup(); + + plugin.RegisterListener(OnTick); + } + + private void OnTick() + { + if (this.state != LRState.Active) return; + + if (prisoner.PlayerPawn.Value == null || guard.PlayerPawn.Value == null) return; + DisableScope(prisoner); + DisableScope(guard); + } + + private void DisableScope(CCSPlayerController player) + { + if (!player.IsReal()) + return; + try + { + player.PlayerPawn.Value!.WeaponServices!.ActiveWeapon.Value!.NextSecondaryAttackTick = + Server.TickCount + 500; + } + catch (NullReferenceException e) + { + Console.WriteLine(e); + } + } + + public override void Execute() + { + PrintToParticipants("Go!"); + prisoner.GiveNamedItem("weapon_ssg08"); + guard.GiveNamedItem("weapon_ssg08"); + this.state = LRState.Active; + + plugin.AddTimer(30, () => + { + if (state != LRState.Active) return; + prisoner.GiveNamedItem("weapon_knife"); + guard.GiveNamedItem("weapon_knife"); + }, TimerFlags.STOP_ON_MAPCHANGE); + + plugin.AddTimer(60, () => + { + if (state != LRState.Active) return; + + manager.EndLastRequest(this, guard.Health > prisoner.Health ? LRResult.GuardWin : LRResult.PrisonerWin); + }, TimerFlags.STOP_ON_MAPCHANGE); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequests/RockPaperScissors.cs b/mod/Jailbreak.LastRequest/LastRequests/RockPaperScissors.cs new file mode 100644 index 00000000..ebc326fd --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequests/RockPaperScissors.cs @@ -0,0 +1,117 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Timers; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest.LastRequests; + +public class RockPaperScissors : AbstractLastRequest +{ + private ChatMenu chatMenu; + private int prisonerChoice = -1, guardChoice = -1; + + public RockPaperScissors(BasePlugin plugin, ILastRequestManager manager, CCSPlayerController prisoner, + CCSPlayerController guard) : base(plugin, manager, prisoner, guard) + { + chatMenu = new ChatMenu("Rock Paper Scissors"); + foreach (string option in new[] { "Rock", "Paper", "Scissors" }) + chatMenu.AddMenuOption(option, OnSelect); + } + + public override void Setup() + { + chatMenu.Title = $"Rock Paper Scissors - {prisoner.PlayerName} vs {guard.PlayerName}"; + prisonerChoice = -1; + guardChoice = -1; + plugin.AddTimer(3, Execute); + } + + private void OnSelect(CCSPlayerController player, ChatMenuOption option) + { + if (player.Slot != prisoner.Slot && player.Slot != guard.Slot) + return; + + int choice = Array.IndexOf(new[] { "Rock", "Paper", "Scissors" }, option.Text); + + if (player.Slot == prisoner.Slot) + prisonerChoice = choice; + else + guardChoice = choice; + + if (prisonerChoice == -1 || guardChoice == -1) + { + PrintToParticipants(player.PlayerName + " has made their choice..."); + return; + } + + PrintToParticipants("Both players have made their choice!"); + if (prisonerChoice == guardChoice) + { + PrintToParticipants("It's a tie!"); + Setup(); + return; + } + + if (prisonerChoice == 0 && guardChoice == 2 || prisonerChoice == 1 && guardChoice == 0 || + prisonerChoice == 2 && guardChoice == 1) + manager.EndLastRequest(this, LRResult.PrisonerWin); + else + manager.EndLastRequest(this, LRResult.GuardWin); + } + + public override LRType type => LRType.RockPaperScissors; + + public override void Execute() + { + state = LRState.Active; + MenuManager.OpenChatMenu(prisoner, chatMenu); + MenuManager.OpenChatMenu(guard, chatMenu); + + plugin.AddTimer(20, Timeout, TimerFlags.STOP_ON_MAPCHANGE); + } + + private void Timeout() + { + if (state != LRState.Active) + return; + if (prisonerChoice != -1) + { + manager.EndLastRequest(this, LRResult.PrisonerWin); + } + else if (guardChoice != -1) + { + manager.EndLastRequest(this, LRResult.GuardWin); + } + else + { + manager.EndLastRequest(this, LRResult.TimedOut); + } + } + + public override void OnEnd(LRResult result) + { + if (result == LRResult.GuardWin) + { + prisoner.Pawn.Value!.CommitSuicide(false, true); + } + else if (result == LRResult.PrisonerWin) + { + guard.Pawn.Value!.CommitSuicide(false, true); + } + + PrintToParticipants($"Prisoner chose {GetChoice(prisonerChoice)}, Guard chose {GetChoice(guardChoice)}"); + state = LRState.Completed; + } + + private string GetChoice(int choice) + { + return choice switch + { + 0 => "Rock", + 1 => "Paper", + 2 => "Scissors", + _ => "Unknown" + }; + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequests/ShotForShot.cs b/mod/Jailbreak.LastRequest/LastRequests/ShotForShot.cs new file mode 100644 index 00000000..7ec97e5c --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequests/ShotForShot.cs @@ -0,0 +1,133 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Timers; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Public.Extensions; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest.LastRequests; + +public class ShotForShot : WeaponizedRequest +{ + public ShotForShot(BasePlugin plugin, ILastRequestManager manager, CCSPlayerController prisoner, + CCSPlayerController guard) : base(plugin, manager, prisoner, guard) + { + } + + public override LRType type => LRType.ShotForShot; + private CCSPlayerController whosShot; + + public override void Setup() + { + plugin.RegisterEventHandler(OnPlayerShoot); + base.Setup(); + + whosShot = new Random().Next(2) == 0 ? prisoner : guard; + PrintToParticipants(whosShot.PlayerName + " will shoot first."); + prisoner.GiveNamedItem("weapon_deagle"); + guard.GiveNamedItem("weapon_deagle"); + + var weapon = FindWeapon(prisoner, "weapon_deagle"); + if (weapon != null) + setAmmoAmount(weapon, 0, 0); + weapon = FindWeapon(guard, "weapon_deagle"); + if (weapon != null) + setAmmoAmount(weapon, 0, 0); + } + + private static CBasePlayerWeapon? FindWeapon(CCSPlayerController player, String name) + { + if (!player.IsReal()) + return null; + + var pawn = player.PlayerPawn.Value; + + if (pawn == null) + return null; + + var weapons = pawn.WeaponServices?.MyWeapons; + + return weapons?.Select(weaponOpt => weaponOpt.Value).OfType() + .FirstOrDefault(weapon => weapon.DesignerName.Contains(name)); + } + + private static void setAmmoAmount(CBasePlayerWeapon weapon, int primary, int reserve) + { + weapon.Clip1 = primary; + Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_iClip1"); + weapon.Clip2 = reserve; + Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_pReserveAmmo"); + } + + public override void Execute() + { + state = LRState.Active; + var deagle = FindWeapon(whosShot, "weapon_deagle"); + if (deagle != null) + setAmmoAmount(deagle, 1, 0); + + plugin.AddTimer(30, () => + { + if (state != LRState.Active) + return; + prisoner.GiveNamedItem("weapon_knife"); + guard.GiveNamedItem("weapon_knife"); + }); + plugin.AddTimer(60, () => + { + if (state != LRState.Active) return; + PrintToParticipants("Time's Up!"); + var result = guard.Health > prisoner.Health ? LRResult.GuardWin : LRResult.PrisonerWin; + if (guard.Health == prisoner.Health) + { + PrintToParticipants("Even health, since " + whosShot.PlayerName + " had the shot last, they lose."); + result = whosShot.Slot == prisoner.Slot ? LRResult.GuardWin : LRResult.PrisonerWin; + } + else + { + PrintToParticipants("Health was the deciding factor. "); + } + + if (result == LRResult.GuardWin) + prisoner.Pawn.Value?.CommitSuicide(false, true); + else + guard.Pawn.Value?.CommitSuicide(false, true); + }, TimerFlags.STOP_ON_MAPCHANGE); + } + + public HookResult OnPlayerShoot(EventPlayerShoot @event, GameEventInfo info) + { + if (state != LRState.Active) + return HookResult.Continue; + + var player = @event.Userid; + if (!player.IsReal()) + return HookResult.Continue; + + if (player.Slot != prisoner.Slot && player.Slot != guard.Slot) + return HookResult.Continue; + if (player.Slot != whosShot.Slot) + { + PrintToParticipants(player.PlayerName + " cheated."); + player.Pawn.Value?.CommitSuicide(false, true); + return HookResult.Handled; + } + + PrintToParticipants(player.PlayerName + " has shot."); + var opponent = player.Slot == prisoner.Slot ? guard : prisoner; + opponent.PrintToChat("Your shot"); + var deagle = FindWeapon(opponent, "weapon_deagle"); + if (deagle != null) + setAmmoAmount(deagle, 1, 0); + whosShot = opponent; + return HookResult.Continue; + } + + public override void OnEnd(LRResult result) + { + plugin.RemoveListener("player_shoot", OnPlayerShoot); + state = LRState.Completed; + } +} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequests/WeaponizedRequest.cs b/mod/Jailbreak.LastRequest/LastRequests/WeaponizedRequest.cs new file mode 100644 index 00000000..e9dd23d1 --- /dev/null +++ b/mod/Jailbreak.LastRequest/LastRequests/WeaponizedRequest.cs @@ -0,0 +1,48 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.LastRequest.LastRequests; + +/// +/// Represents a Last Request that involves direct PvP combat. +/// +/// Automatically strips weapons, counts down, and calls Execute after 4 seconds. +/// +public abstract class WeaponizedRequest : AbstractLastRequest +{ + public WeaponizedRequest(BasePlugin plugin, ILastRequestManager manager, CCSPlayerController prisoner, + CCSPlayerController guard) : base(plugin, manager, prisoner, guard) + { + } + + public override void Setup() + { + state = LRState.Pending; + + // Strip weapons, teleport T to CT + prisoner.RemoveWeapons(); + guard.RemoveWeapons(); + guard.Teleport(prisoner.Pawn.Value!.AbsOrigin!, prisoner.Pawn.Value.AbsRotation!, new Vector()); + for (var i = 3; i >= 1; i--) + { + var copy = i; + plugin.AddTimer(3 - i, () => { PrintToParticipants($"{copy}..."); }); + } + + plugin.AddTimer(3, Execute); + } + + public override void OnEnd(LRResult result) + { + if (result == LRResult.GuardWin) + { + prisoner.Pawn.Value?.CommitSuicide(false, true); + } else if (result == LRResult.PrisonerWin) + { + guard.Pawn.Value?.CommitSuicide(false, true); + } + state = LRState.Completed; + } +} \ No newline at end of file diff --git a/mod/Jailbreak.Logs/Tags/PlayerTagHelper.cs b/mod/Jailbreak.Logs/Tags/PlayerTagHelper.cs index ce028415..da8ec5b6 100644 --- a/mod/Jailbreak.Logs/Tags/PlayerTagHelper.cs +++ b/mod/Jailbreak.Logs/Tags/PlayerTagHelper.cs @@ -33,7 +33,7 @@ public FormatObject Rich(CCSPlayerController player) if (player.GetTeam() == CsTeam.CounterTerrorist) return new StringFormatObject("(CT)", ChatColors.BlueGrey); if (_rebelService.Value.IsRebel(player)) - return new StringFormatObject("(REBEL)", ChatColors.Darkred); + return new StringFormatObject("(REBEL)", ChatColors.DarkRed); return new StringFormatObject("(T)", ChatColors.Yellow); } diff --git a/mod/Jailbreak.Rebel/RebelListener.cs b/mod/Jailbreak.Rebel/RebelListener.cs index da14056c..967b06be 100644 --- a/mod/Jailbreak.Rebel/RebelListener.cs +++ b/mod/Jailbreak.Rebel/RebelListener.cs @@ -1,7 +1,9 @@ using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; using CounterStrikeSharp.API.Modules.Utils; using Jailbreak.Public.Behaviors; using Jailbreak.Public.Extensions; +using Jailbreak.Public.Mod.LastRequest; using Jailbreak.Public.Mod.Rebel; namespace Jailbreak.Rebel; @@ -9,17 +11,15 @@ namespace Jailbreak.Rebel; public class RebelListener : IPluginBehavior { private readonly IRebelService _rebelService; + private readonly ILastRequestManager _lastRequestManager; - public RebelListener(IRebelService rebelService) + public RebelListener(IRebelService rebelService, ILastRequestManager lastRequestManager) { _rebelService = rebelService; + _lastRequestManager = lastRequestManager; } - public void Start(BasePlugin parent) - { - parent.RegisterEventHandler(OnPlayerHurt); - } - + [GameEventHandler] private HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) { var player = @event.Userid; @@ -35,6 +35,9 @@ private HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) if (attacker.GetTeam() != CsTeam.Terrorist) return HookResult.Continue; + if (_lastRequestManager.IsInLR(attacker)) + return HookResult.Continue; + _rebelService.MarkRebel(attacker); return HookResult.Continue; } diff --git a/mod/Jailbreak.Rebel/RebelManager.cs b/mod/Jailbreak.Rebel/RebelManager.cs index c655ee18..22d53275 100644 --- a/mod/Jailbreak.Rebel/RebelManager.cs +++ b/mod/Jailbreak.Rebel/RebelManager.cs @@ -13,7 +13,6 @@ namespace Jailbreak.Rebel; public class RebelManager : IPluginBehavior, IRebelService { - private IRebelNotifications notifs; private readonly IRichLogService _logs; private readonly IRebelNotifications _notifs; private readonly Dictionary _rebelTimes = new(); @@ -121,7 +120,7 @@ public bool MarkRebel(CCSPlayerController player, long time = 120) public void UnmarkRebel(CCSPlayerController player) { - notifs.NO_LONGER_REBEL.ToPlayerChat(player); + _notifs.NO_LONGER_REBEL.ToPlayerChat(player); _logs.Append(_logs.Player(player), "is no longer a rebel."); _rebelTimes.Remove(player); diff --git a/mod/Jailbreak.Teams/Queue/QueueBehavior.cs b/mod/Jailbreak.Teams/Queue/QueueBehavior.cs index 85d37331..d3993637 100644 --- a/mod/Jailbreak.Teams/Queue/QueueBehavior.cs +++ b/mod/Jailbreak.Teams/Queue/QueueBehavior.cs @@ -1,4 +1,4 @@ -using CounterStrikeSharp.API; +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Attributes.Registration; using CounterStrikeSharp.API.Modules.Admin; @@ -194,6 +194,16 @@ public HookResult OnRequestToJoinTeam(CCSPlayerController? invoked, CommandInfo return HookResult.Stop; } + // Prisoner attempted to use auto-select, cancel the action. + if ((CsTeam)team == CsTeam.None && invoked.GetTeam() == CsTeam.Terrorist) + { + _notifications.ATTEMPT_TO_JOIN_FROM_TEAM_MENU + .ToPlayerChat(invoked) + .ToPlayerCenter(invoked); + + return HookResult.Stop; + } + // All else: A-OK. return HookResult.Continue; } diff --git a/mod/Jailbreak.Warden/Commands/SpecialTreatmentCommandsBehavior.cs b/mod/Jailbreak.Warden/Commands/SpecialTreatmentCommandsBehavior.cs new file mode 100644 index 00000000..f14f3f90 --- /dev/null +++ b/mod/Jailbreak.Warden/Commands/SpecialTreatmentCommandsBehavior.cs @@ -0,0 +1,78 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Utils; + +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; +using Jailbreak.Public.Behaviors; +using Jailbreak.Public.Mod.Warden; + +namespace Jailbreak.Warden.Commands; + +public class SpecialTreatmentCommandsBehavior : IPluginBehavior +{ + + private IWardenService _warden; + private ISpecialTreatmentService _specialTreatment; + + private IGenericCommandNotifications _generic; + private ISpecialTreatmentNotifications _notifications; + + public SpecialTreatmentCommandsBehavior(IWardenService warden, ISpecialTreatmentService specialTreatment, IGenericCommandNotifications generic, ISpecialTreatmentNotifications notifications) + { + _warden = warden; + _specialTreatment = specialTreatment; + _generic = generic; + _notifications = notifications; + } + + [ConsoleCommand("css_treat", "Grant or revoke special treatment from a player")] + [ConsoleCommand("css_st", "Grant or revoke special treatment from a player")] + [CommandHelper(1, "[target]", CommandUsage.CLIENT_ONLY)] + public void Command_Toggle(CCSPlayerController? player, CommandInfo command) + { + if (player == null) + return; + + if (!_warden.IsWarden(player)) + // You're not that warden, blud + return; + + // Since we have min_args, don't need to check for validity here. + // just only get targets that are T's. + var targets = command.GetArgTargetResult(1); + var eligible = targets + .Where(player => player.Team == CsTeam.Terrorist) + .ToList(); + + if (eligible.Count == 0) + { + _generic.PlayerNotFound(command.GetArg(1)) + .ToPlayerChat(player) + .ToPlayerConsole(player); + return; + } + else if (eligible.Count != 1) + { + _generic.PlayerFoundMultiple(command.GetArg(1)) + .ToPlayerChat(player) + .ToPlayerConsole(player); + return; + } + + // One target, mark as ST. + var special = eligible.First(); + + if (_specialTreatment.IsSpecialTreatment(special)) + { + // Revoke + _specialTreatment.Revoke(special); + } + else + { + // Player does not have ST, grant + _specialTreatment.Grant(special); + } + } +} diff --git a/mod/Jailbreak.Warden/Global/WardenBehavior.cs b/mod/Jailbreak.Warden/Global/WardenBehavior.cs index a97654f7..f063cec4 100644 --- a/mod/Jailbreak.Warden/Global/WardenBehavior.cs +++ b/mod/Jailbreak.Warden/Global/WardenBehavior.cs @@ -8,6 +8,7 @@ using Jailbreak.Public.Behaviors; using Jailbreak.Public.Extensions; using Jailbreak.Public.Mod.Logs; +using Jailbreak.Public.Mod.Rebel; using Jailbreak.Public.Mod.Warden; using Microsoft.Extensions.Logging; @@ -17,17 +18,28 @@ public class WardenBehavior : IPluginBehavior, IWardenService { private ILogger _logger; private IRichLogService _logs; - private IWardenNotifications _notifications; + private ISpecialTreatmentService _specialTreatment; + private IRebelService _rebels; + private ISet _bluePrisoners = new HashSet(); + private BasePlugin _parent; private bool _hasWarden; private CCSPlayerController? _warden; - public WardenBehavior(ILogger logger, IWardenNotifications notifications, IRichLogService logs) + public WardenBehavior(ILogger logger, IWardenNotifications notifications, IRichLogService logs, + ISpecialTreatmentService specialTreatment, IRebelService rebels) { _logger = logger; _notifications = notifications; _logs = logs; + _specialTreatment = specialTreatment; + _rebels = rebels; + } + + public void Start(BasePlugin parent) + { + _parent = parent; } /// @@ -57,7 +69,7 @@ public bool TrySetWarden(CCSPlayerController controller) if (_warden.Pawn.Value != null) { _warden.Pawn.Value.RenderMode = RenderMode_t.kRenderTransColor; - _warden.Pawn.Value.Render = Color.Blue; + _warden.Pawn.Value.Render = Color.FromArgb(254, 0, 0, 255); Utilities.SetStateChanged(_warden.Pawn.Value, "CBaseModelEntity", "m_clrRender"); } @@ -66,6 +78,8 @@ public bool TrySetWarden(CCSPlayerController controller) .ToAllCenter(); _logs.Append( _logs.Player(_warden), "is now the warden."); + + _parent.AddTimer(3, UnmarkPrisonersBlue); return true; } @@ -121,6 +135,53 @@ private void ProcessWardenDeath() .ToAllCenter(); _notifications.BECOME_NEXT_WARDEN.ToAllChat(); + + MarkPrisonersBlue(); + } + + private void UnmarkPrisonersBlue() + { + foreach (var player in _bluePrisoners) + { + var pawn = player.Pawn.Value; + if (pawn == null) + continue; + if(IgnoreColor(player)) + continue; + pawn.RenderMode = RenderMode_t.kRenderNormal; + pawn.Render = Color.FromArgb(254, 255, 255, 255); + Utilities.SetStateChanged(pawn, "CBaseModelEntity", "m_clrRender"); + } + _bluePrisoners.Clear(); + } + + private void MarkPrisonersBlue() + { + foreach(CCSPlayerController player in Utilities.GetPlayers()) + { + if(!player.IsReal() || player.Team != CsTeam.Terrorist) + continue; + if(IgnoreColor(player)) + continue; + + var pawn = player.Pawn.Value; + if(pawn == null) + continue; + pawn.RenderMode = RenderMode_t.kRenderTransColor; + pawn.Render = Color.FromArgb(254, 0, 0, 255); + Utilities.SetStateChanged(pawn, "CBaseModelEntity", "m_clrRender"); + + _bluePrisoners.Add(player); + } + } + + private bool IgnoreColor(CCSPlayerController player) + { + if (_specialTreatment.IsSpecialTreatment(player)) + return true; + if (_rebels.IsRebel(player)) + return true; + return false; } [GameEventHandler] diff --git a/mod/Jailbreak.Warden/SpecialTreatment/SpecialTreatmentBehavior.cs b/mod/Jailbreak.Warden/SpecialTreatment/SpecialTreatmentBehavior.cs new file mode 100644 index 00000000..e5cb7da0 --- /dev/null +++ b/mod/Jailbreak.Warden/SpecialTreatment/SpecialTreatmentBehavior.cs @@ -0,0 +1,90 @@ +using System.Drawing; + +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; + +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; +using Jailbreak.Public.Behaviors; +using Jailbreak.Public.Generic; +using Jailbreak.Public.Mod.Rebel; +using Jailbreak.Public.Mod.Warden; + +namespace Jailbreak.Warden.SpecialTreatment; + +public class SpecialTreatmentBehavior : IPluginBehavior, ISpecialTreatmentService +{ + private IPlayerState _sts; + private IRebelService _rebel; + private ISpecialTreatmentNotifications _notifications; + + public SpecialTreatmentBehavior(IPlayerStateFactory factory, IRebelService rebel, ISpecialTreatmentNotifications notifications) + { + _sts = factory.Round(); + + _rebel = rebel; + _notifications = notifications; + } + + private class SpecialTreatmentState + { + public bool HasSpecialTreatment { get; set; } = false; + } + + public bool IsSpecialTreatment(CCSPlayerController player) + { + return _sts.Get(player) + .HasSpecialTreatment; + } + + public void Grant(CCSPlayerController player) + { + // Player is already granted ST + if (IsSpecialTreatment(player)) + return; + + _sts.Get(player).HasSpecialTreatment = true; + + _rebel.UnmarkRebel(player); + this.SetPlayerColor(player, /* hasSt */ true); + + _notifications.GRANTED + .ToPlayerChat(player) + .ToPlayerCenter(player); + + _notifications.GRANTED_TO(player) + .ToAllChat(); + } + + public void Revoke(CCSPlayerController player) + { + // Player is already revoked + if (!IsSpecialTreatment(player)) + return; + + _sts.Get(player).HasSpecialTreatment = false; + + this.SetPlayerColor(player, /* hasSt */ false); + + _notifications.REVOKED + .ToPlayerChat(player) + .ToPlayerCenter(player); + + _notifications.REVOKED_FROM(player) + .ToAllChat(); + } + + private void SetPlayerColor(CCSPlayerController player, bool hasSt) + { + if (!player.IsValid || player.Pawn.Value == null) + return; + + var color = hasSt + ? Color.FromArgb(254, 150, 255, 150) + : Color.FromArgb(254, 255, 255, 255); + + player.Pawn.Value.RenderMode = RenderMode_t.kRenderTransColor; + player.Pawn.Value.Render = color; + Utilities.SetStateChanged(player.Pawn.Value, "CBaseModelEntity", "m_clrRender"); + } +} diff --git a/mod/Jailbreak.Warden/WardenServiceExtension.cs b/mod/Jailbreak.Warden/WardenServiceExtension.cs index 9f7a0fc5..c9ecda85 100644 --- a/mod/Jailbreak.Warden/WardenServiceExtension.cs +++ b/mod/Jailbreak.Warden/WardenServiceExtension.cs @@ -5,6 +5,8 @@ using Jailbreak.Warden.Markers; using Jailbreak.Warden.Paint; using Jailbreak.Warden.Selection; +using Jailbreak.Warden.SpecialTreatment; + using Microsoft.Extensions.DependencyInjection; namespace Jailbreak.Warden; @@ -15,9 +17,12 @@ public static void AddJailbreakWarden(this IServiceCollection serviceCollection) { serviceCollection.AddPluginBehavior(); serviceCollection.AddPluginBehavior(); + serviceCollection.AddPluginBehavior(); + serviceCollection.AddPluginBehavior(); serviceCollection.AddPluginBehavior(); + serviceCollection.AddPluginBehavior(); serviceCollection.AddPluginBehavior(); } -} \ No newline at end of file +} diff --git a/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs b/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs index 43a22a42..5e4fe0eb 100644 --- a/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs +++ b/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs @@ -34,4 +34,12 @@ public void WithRebel() public void WithLogging() where TLogging : class, ILanguage, ILogMessages => _collection.AddSingleton(); + + public void WithLastRequest() + where TLastRequest : class, ILanguage, ILastRequestMessages + => _collection.AddSingleton(); + + public void WithSpecialTreatment() + where TSpecialTreatment : class, ILanguage, ISpecialTreatmentNotifications + => _collection.AddSingleton(); } diff --git a/public/Jailbreak.Formatting/Views/ILastRequestMessages.cs b/public/Jailbreak.Formatting/Views/ILastRequestMessages.cs new file mode 100644 index 00000000..ec542c01 --- /dev/null +++ b/public/Jailbreak.Formatting/Views/ILastRequestMessages.cs @@ -0,0 +1,18 @@ +using CounterStrikeSharp.API.Core; +using Jailbreak.Formatting.Base; +using Jailbreak.Public.Mod.LastRequest; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.Formatting.Views; + +public interface ILastRequestMessages +{ + public IView LastRequestEnabled(); + public IView LastRequestDisabled(); + public IView LastRequestNotEnabled(); + public IView InvalidLastRequest(string query); + public IView InvalidPlayerChoice(CCSPlayerController player, string reason); + public IView InformLastRequest(AbstractLastRequest lr); + public IView AnnounceLastRequest(AbstractLastRequest lr); + public IView LastRequestDecided(AbstractLastRequest lr, LRResult result); +} \ No newline at end of file diff --git a/public/Jailbreak.Formatting/Views/ISpecialTreatmentNotifications.cs b/public/Jailbreak.Formatting/Views/ISpecialTreatmentNotifications.cs new file mode 100644 index 00000000..43f08600 --- /dev/null +++ b/public/Jailbreak.Formatting/Views/ISpecialTreatmentNotifications.cs @@ -0,0 +1,17 @@ +using CounterStrikeSharp.API.Core; + +using Jailbreak.Formatting.Base; + +namespace Jailbreak.Formatting.Views; + +public interface ISpecialTreatmentNotifications +{ + public IView GRANTED { get; } + + public IView REVOKED { get; } + + public IView GRANTED_TO(CCSPlayerController player); + + public IView REVOKED_FROM(CCSPlayerController player); + +} diff --git a/public/Jailbreak.Public/Extensions/PlayerExtensions.cs b/public/Jailbreak.Public/Extensions/PlayerExtensions.cs index 1837f5eb..131c6201 100644 --- a/public/Jailbreak.Public/Extensions/PlayerExtensions.cs +++ b/public/Jailbreak.Public/Extensions/PlayerExtensions.cs @@ -10,10 +10,12 @@ public static CsTeam GetTeam(this CCSPlayerController controller) return (CsTeam)controller.TeamNum; } - public static bool IsReal(this CCSPlayerController player) + public static bool IsReal(this CCSPlayerController? player) { // Do nothing else before this: // Verifies the handle points to an entity within the global entity list. + if (player == null) + return false; if (!player.IsValid) return false; diff --git a/public/Jailbreak.Public/Jailbreak.Public.csproj b/public/Jailbreak.Public/Jailbreak.Public.csproj index 83079e55..70f7a9a2 100644 --- a/public/Jailbreak.Public/Jailbreak.Public.csproj +++ b/public/Jailbreak.Public/Jailbreak.Public.csproj @@ -7,7 +7,7 @@ - + diff --git a/public/Jailbreak.Public/Mod/LastRequest/AbstractLastRequest.cs b/public/Jailbreak.Public/Mod/LastRequest/AbstractLastRequest.cs new file mode 100644 index 00000000..903c509e --- /dev/null +++ b/public/Jailbreak.Public/Mod/LastRequest/AbstractLastRequest.cs @@ -0,0 +1,33 @@ +using CounterStrikeSharp.API.Core; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.Public.Mod.LastRequest; + +public abstract class AbstractLastRequest +{ + public CCSPlayerController prisoner { get; protected set; } + public CCSPlayerController guard { get; protected set; } + public abstract LRType type { get; } + + public LRState state { get; protected set; } + protected BasePlugin plugin; + protected ILastRequestManager manager; + + protected AbstractLastRequest(BasePlugin plugin, ILastRequestManager manager, CCSPlayerController prisoner, CCSPlayerController guard) + { + this.manager = manager; + this.plugin = plugin; + this.prisoner = prisoner; + this.guard = guard; + } + + public void PrintToParticipants(string message) + { + prisoner.PrintToChat(message); + guard.PrintToChat(message); + } + + public abstract void Setup(); + public abstract void Execute(); + public abstract void OnEnd(LRResult result); +} \ No newline at end of file diff --git a/public/Jailbreak.Public/Mod/LastRequest/Enums/LRResult.cs b/public/Jailbreak.Public/Mod/LastRequest/Enums/LRResult.cs new file mode 100644 index 00000000..3621ce28 --- /dev/null +++ b/public/Jailbreak.Public/Mod/LastRequest/Enums/LRResult.cs @@ -0,0 +1,9 @@ +namespace Jailbreak.Public.Mod.LastRequest.Enums; + +public enum LRResult +{ + PrisonerWin, + GuardWin, + TimedOut, + Interrupted +} \ No newline at end of file diff --git a/public/Jailbreak.Public/Mod/LastRequest/Enums/LRState.cs b/public/Jailbreak.Public/Mod/LastRequest/Enums/LRState.cs new file mode 100644 index 00000000..2c75f3c3 --- /dev/null +++ b/public/Jailbreak.Public/Mod/LastRequest/Enums/LRState.cs @@ -0,0 +1,9 @@ +namespace Jailbreak.Public.Mod.LastRequest.Enums; + +public enum LRState +{ + Pending, + Active, + Completed, + Cancelled +} \ No newline at end of file diff --git a/public/Jailbreak.Public/Mod/LastRequest/Enums/LRType.cs b/public/Jailbreak.Public/Mod/LastRequest/Enums/LRType.cs new file mode 100644 index 00000000..79916b8d --- /dev/null +++ b/public/Jailbreak.Public/Mod/LastRequest/Enums/LRType.cs @@ -0,0 +1,68 @@ +using CounterStrikeSharp.API.Core; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Jailbreak.Public.Mod.LastRequest.Enums; + +public enum LRType +{ + GunToss, + RockPaperScissors, + KnifeFight, + NoScope, + Coinflip, + ShotForShot, + MagForMag, + Race +} + +public static class LRTypeExtensions +{ + public static string ToFriendlyString(this LRType type) + { + return type switch + { + LRType.GunToss => "Gun Toss", + LRType.RockPaperScissors => "Rock Paper Scissors", + LRType.KnifeFight => "Knife Fight", + LRType.NoScope => "No Scope", + LRType.Coinflip => "Coinflip", + LRType.ShotForShot => "Shot For Shot", + LRType.MagForMag => "Mag For Mag", + LRType.Race => "Race", + _ => "Unknown" + }; + } + + public static LRType FromIndex(int index) + { + return (LRType)index; + } + + public static LRType? FromString(string type) + { + if (Enum.TryParse(type, true, out var result)) + return result; + type = type.ToLower().Replace(" ", ""); + switch (type) + { + case "rps": + return LRType.RockPaperScissors; + case "s4s": + case "sfs": + return LRType.ShotForShot; + case "m4m": + case "mfm": + return LRType.MagForMag; + } + + if (type.Contains("knife")) + return LRType.KnifeFight; + if (type.Contains("scope")) + return LRType.NoScope; + if (type.Contains("gun")) + return LRType.GunToss; + if (type.Contains("coin") || type.Contains("fifty")) + return LRType.Coinflip; + return null; + } +} \ No newline at end of file diff --git a/public/Jailbreak.Public/Mod/LastRequest/ILastRequestFactory.cs b/public/Jailbreak.Public/Mod/LastRequest/ILastRequestFactory.cs new file mode 100644 index 00000000..eaa285b8 --- /dev/null +++ b/public/Jailbreak.Public/Mod/LastRequest/ILastRequestFactory.cs @@ -0,0 +1,11 @@ +using CounterStrikeSharp.API.Core; +using Jailbreak.Public.Behaviors; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.Public.Mod.LastRequest; + +public interface ILastRequestFactory : IPluginBehavior +{ + AbstractLastRequest CreateLastRequest(CCSPlayerController prisoner, CCSPlayerController guard, LRType type); + bool IsValidType(LRType type); +} \ No newline at end of file diff --git a/public/Jailbreak.Public/Mod/LastRequest/ILastRequestManager.cs b/public/Jailbreak.Public/Mod/LastRequest/ILastRequestManager.cs new file mode 100644 index 00000000..caf33a93 --- /dev/null +++ b/public/Jailbreak.Public/Mod/LastRequest/ILastRequestManager.cs @@ -0,0 +1,24 @@ +using CounterStrikeSharp.API.Core; +using Jailbreak.Public.Behaviors; +using Jailbreak.Public.Mod.LastRequest.Enums; + +namespace Jailbreak.Public.Mod.LastRequest; + +public interface ILastRequestManager : IPluginBehavior +{ + public bool IsLREnabled { get; set; } + public IList ActiveLRs { get; } + + bool InitiateLastRequest(CCSPlayerController prisoner, CCSPlayerController guard, LRType lrType); + bool EndLastRequest(AbstractLastRequest lr, LRResult result); + + public bool IsInLR(CCSPlayerController player) + { + return GetActiveLR(player) != null; + } + + public AbstractLastRequest? GetActiveLR(CCSPlayerController player) + { + return ActiveLRs.FirstOrDefault(lr => lr.guard.Slot == player.Slot || lr.prisoner.Slot == player.Slot); + } +} \ No newline at end of file diff --git a/public/Jailbreak.Public/Mod/Warden/ISpecialTreatmentService.cs b/public/Jailbreak.Public/Mod/Warden/ISpecialTreatmentService.cs new file mode 100644 index 00000000..ee4bc6ce --- /dev/null +++ b/public/Jailbreak.Public/Mod/Warden/ISpecialTreatmentService.cs @@ -0,0 +1,21 @@ +using CounterStrikeSharp.API.Core; + +namespace Jailbreak.Public.Mod.Warden; + +public interface ISpecialTreatmentService +{ + public bool IsSpecialTreatment(CCSPlayerController player); + + /// + /// Give this player ST for the rest of the round + /// + /// + public void Grant(CCSPlayerController player); + + /// + /// Revoke the player's special treatment for the current round + /// Does nothing if not ST. + /// + /// + public void Revoke(CCSPlayerController player); +} diff --git a/src/Jailbreak/Jailbreak.csproj b/src/Jailbreak/Jailbreak.csproj index 945c2eeb..58f4520d 100644 --- a/src/Jailbreak/Jailbreak.csproj +++ b/src/Jailbreak/Jailbreak.csproj @@ -58,6 +58,7 @@ + diff --git a/src/Jailbreak/JailbreakServiceCollection.cs b/src/Jailbreak/JailbreakServiceCollection.cs index 733d0dc8..3081a93c 100644 --- a/src/Jailbreak/JailbreakServiceCollection.cs +++ b/src/Jailbreak/JailbreakServiceCollection.cs @@ -4,12 +4,14 @@ using Jailbreak.Config; using Jailbreak.Debug; using Jailbreak.English.Generic; +using Jailbreak.English.LastRequest; using Jailbreak.English.Logs; using Jailbreak.English.Rebel; using Jailbreak.English.Teams; using Jailbreak.English.Warden; using Jailbreak.Formatting.Logistics; using Jailbreak.Generic; +using Jailbreak.LastRequest; using Jailbreak.Logs; using Jailbreak.Public.Configuration; using Jailbreak.Rebel; @@ -33,10 +35,11 @@ public void ConfigureServices(IServiceCollection serviceCollection) serviceCollection.AddJailbreakGeneric(); serviceCollection.AddJailbreakLogs(); + serviceCollection.AddJailbreakRebel(); serviceCollection.AddJailbreakWarden(); serviceCollection.AddJailbreakTeams(); - serviceCollection.AddJailbreakRebel(); serviceCollection.AddJailbreakDebug(); + serviceCollection.AddJailbreakLastRequest(); // Add in english localization serviceCollection.AddLanguage(config => @@ -46,6 +49,8 @@ public void ConfigureServices(IServiceCollection serviceCollection) config.WithWarden(); config.WithRebel(); config.WithLogging(); + config.WithLastRequest(); + config.WithSpecialTreatment(); }); } }