From 9710049643fad8544543630692e3e686649a8527 Mon Sep 17 00:00:00 2001 From: Isaac Date: Tue, 27 Aug 2024 17:57:20 -0700 Subject: [PATCH] Cleaup/aug (#290) * Reformat * Add cvar config for HNS * Add more HNS customization support * Add customizations to noscope * Remove unused class var * More tidying up * Remove config infra * Add configurability to C4 * Add contributing, add config explanation in readme --- CONTRIBUTING.md | 20 ++ README.md | 45 ++--- .../Generic/GenericCmdLocale.cs | 9 +- .../LastRequest/CoinflipLocale.cs | 4 +- .../LastRequest/LastRequestLocale.cs | 55 ++---- .../LastRequest/RPSLocale.cs | 10 +- .../LastRequest/RaceLocale.cs | 12 +- .../Mute/WardenPeaceLocale.cs | 23 ++- lang/Jailbreak.English/Rebel/RebelLocale.cs | 2 +- .../SpecialDay/GunDayLocale.cs | 9 +- .../SpecialDay/HNSDayLocale.cs | 9 +- .../SpecialDay/InfectionDayLocale.cs | 4 +- lang/Jailbreak.English/SpecialDay/SDLocale.cs | 17 +- .../SpecialDay/SpeedrunDayLocale.cs | 8 +- .../Warden/WardenCmdOpenLocale.cs | 4 +- mod/Jailbreak.Debug/PlayerZoneCreator.cs | 2 +- mod/Jailbreak.LastGuard/LastGuard.cs | 71 ++++---- mod/Jailbreak.LastGuard/LastGuardConfig.cs | 7 - .../LastRequestManager.cs | 20 +- .../LastRequests/BulletForBullet.cs | 3 +- mod/Jailbreak.Rebel/C4Bomb/C4Behavior.cs | 36 +++- mod/Jailbreak.Rebel/RebelManager.cs | 14 +- mod/Jailbreak.SpecialDay/SpecialDayCommand.cs | 28 ++- .../SpecialDays/AbstractZoneRestrictedDay.cs | 2 +- .../SpecialDays/FFADay.cs | 1 - .../SpecialDays/HideAndSeekDay.cs | 171 ++++++++++++++---- .../SpecialDays/InfectionDay.cs | 22 +-- .../SpecialDays/NoScopeDay.cs | 44 ++++- .../SpecialDays/OneInTheChamberDay.cs | 47 +++-- .../SpecialDays/SpeedrunDay.cs | 155 ++++++++-------- .../Commands/WardenCommandsBehavior.cs | 7 +- .../Commands/WardenOpenCommandsBehavior.cs | 11 +- mod/Jailbreak.Warden/Global/WardenBehavior.cs | 79 ++++---- .../Markers/WardenMarkerBehavior.cs | 16 +- mod/Jailbreak.Warden/WardenConfig.cs | 8 - .../WardenServiceExtension.cs | 4 +- mod/Jailbreak.Zones/SqlZoneManager.cs | 16 +- .../Views/Warden/IWardenCmdOpenLocale.cs | 11 +- .../Configuration/IConfigService.cs | 14 -- .../Extensions/CollectionExtensions.cs | 4 +- .../Extensions/ServiceCollectionExtensions.cs | 21 --- .../Mod/SpecialDay/AbstractSpecialDay.cs | 1 + public/Jailbreak.Public/Utils/TeamUtil.cs | 19 ++ public/Jailbreak.Validator/ItemValidator.cs | 70 +++++++ .../NonZeroRangeValidator.cs | 21 +++ public/Jailbreak.Validator/TeamValidator.cs | 25 +++ public/Jailbreak.Validator/WeaponValidator.cs | 56 ------ src/Jailbreak/Config/ConfigService.cs | 63 ------- src/Jailbreak/JailbreakServiceCollection.cs | 3 - 49 files changed, 737 insertions(+), 566 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 mod/Jailbreak.LastGuard/LastGuardConfig.cs delete mode 100644 mod/Jailbreak.Warden/WardenConfig.cs delete mode 100644 public/Jailbreak.Public/Configuration/IConfigService.cs create mode 100644 public/Jailbreak.Public/Utils/TeamUtil.cs create mode 100644 public/Jailbreak.Validator/ItemValidator.cs create mode 100644 public/Jailbreak.Validator/NonZeroRangeValidator.cs create mode 100644 public/Jailbreak.Validator/TeamValidator.cs delete mode 100644 public/Jailbreak.Validator/WeaponValidator.cs delete mode 100644 src/Jailbreak/Config/ConfigService.cs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..7d1e045 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,20 @@ +## Contributing + +The jail plugin is currently in heavy development and all contributions are welcome! +Please make sure all contributions use the dependency injection system, or ask to have your contribution +ported if you don't know how. + +> [!TIP] +> Microsoft has some good documentation on dependency injection here: +> [Overview](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection), +> [Using Dependency Injection](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-usage), +> [Dependency Injection Guidelines](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines). + +All event handlers should derive from `IPluginBehavior` and be registered using +`IServiceCollection.AddPluginBehavior`. If your behavior also acts as a service, +make sure to use `IServiceCollection.AddPluginBehavior`. All `IPluginBehavior` objects +have their event handlers automatically registered. + +Code style should follow .NET conventions and use the formatting settings specified +in [Jailbreak.sln.DotSettings](./Jailbreak.sln.DotSettings) +(if you need help, make sure to check "enable edits from maintainers" and ask for a format) diff --git a/README.md b/README.md index d1d7978..7e187d9 100644 --- a/README.md +++ b/README.md @@ -9,17 +9,20 @@ The classic Jail gamemode, ported to Counter-Strike 2. [![Release](https://img.shields.io/badge/Release-mediumseagreen?style=for-the-badge&logo=onlyoffice )](https://github.com/edgegamers/Jailbreak/releases/)⠀⠀ -[![Stable](https://img.shields.io/badge/Stable-orangered?style=for-the-badge&logo=onlyoffice)](https://nightly.link/edgegamers/Jailbreak/workflows/nightly/main/jailbreak-nightly)⠀⠀ +[![Stable](https://img.shields.io/badge/Stable-orangered?style=for-the-badge&logo=onlyoffice)](https://nightly.link/edgegamers/Jailbreak/workflows/nightly/main/jailbreak-nightly) +⠀⠀ [![Dev](https://img.shields.io/badge/Nightly-slateblue?style=for-the-badge&logo=onlyoffice )](https://nightly.link/edgegamers/Jailbreak/workflows/nightly/dev/jailbreak-nightly) **Release** builds are our full releases. We try to keep these high-quality and bug-free, when we can. -Our **Stable** builds run on EdgeGamers' own Jailbreak servers. +Our **Stable** builds run on EdgeGamers' own Jailbreak servers. Our **Nightly** builds are used exclusively for development and staging, and are likely to have problems. ## Versioning + Our release tags starting from 'v2.0.0' follow the [Semantic Versioning 2.0.0](https://semver.org/) standard, where `MAJOR.MINOR.PATCH` are incremented based on the following: + - `MAJOR` when we make incompatible API changes, - `MINOR` when we add functionality in a backwards-compatible manner. - `PATCH` when we make backwards-compatible bug fixes. @@ -27,46 +30,29 @@ where `MAJOR.MINOR.PATCH` are incremented based on the following: ## Status - **⚙️ Server** - - [ ] Stats/Analytics Sinks - - [ ] Error reporting - - [x] Configuration system - - Note: Passable, but in a terrible state. Needs TLC. + - [x] Stats/Analytics Sinks + - [x] Error reporting - [x] Logging + - [x] Zones - **👮 Guards** - [x] Warden Selection - [x] Warden Laser and Paint - - [ ] Special Days - - [x] Ratio Enforcement - - [ ] Bans/Punishments + - [x] Special Days - **🎃 Prisoners** - [x] Last Request - [x] Rebel System - **🛕 Maps** + - [x] Automagic Cell Opening - [ ] Custom Entities - [ ] Custom I/O - [ ] Warden/Guard/Prisoner Filters -## Contributing +## Configuration -The jail plugin is currently in heavy development and all contributions are welcome! -Please make sure all contributions use the dependency injection system, or ask to have your contribution -ported if you don't know how. +Configuration is done through CS#'s [FakeConVars](https://docs.cssharp.dev/examples/WithFakeConvars.html?q=fakeconvar). -Ports to DI containers that have more verbose scoping systems for round-based or game-based scoping are welcome. - -> [!TIP] -> Microsoft has some good documentation on dependency injection here: -> [Overview](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection), -> [Using Dependency Injection](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-usage), -> [Dependency Injection Guidelines](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines). - -All event handlers should derive from `IPluginBehavior` and be registered using -`IServiceCollection.AddPluginBehavior`. If your behavior also acts as a service, -make sure to use `IServiceCollection.AddPluginBehavior`. All `IPluginBehavior` objects -have their event handlers automatically registered. - -Code style should follow .NET conventions -(if you need help, make sure to check "enable edits from maintainers" and ask for a format) +You can search for the list of configurable +convars [like so](https://github.com/search?q=repo%3Aedgegamers%2FJailbreak%20fakeconvar&type=code). ## Modding @@ -97,7 +83,8 @@ foreach (IPluginBehavior extension in _extensions) ## Building -The jailbreak plugin automatically builds to `build/Jailbreak` when using `dotnet publish src/Jailbreak/Jailbreak.csproj`. +The jailbreak plugin automatically builds to `build/Jailbreak` when +using `dotnet publish src/Jailbreak/Jailbreak.csproj`. Please use [SDK 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) or higher. Note that only the `src/Jailbreak` project is intended to be built directly. diff --git a/lang/Jailbreak.English/Generic/GenericCmdLocale.cs b/lang/Jailbreak.English/Generic/GenericCmdLocale.cs index 2722924..c60c541 100644 --- a/lang/Jailbreak.English/Generic/GenericCmdLocale.cs +++ b/lang/Jailbreak.English/Generic/GenericCmdLocale.cs @@ -4,6 +4,7 @@ using Jailbreak.Formatting.Core; using Jailbreak.Formatting.Logistics; using Jailbreak.Formatting.Objects; using Jailbreak.Formatting.Views; +using Jailbreak.Public.Extensions; namespace Jailbreak.English.Generic; @@ -36,21 +37,23 @@ public class GenericCmdLocale : IGenericCmdLocale, PREFIX, $"{ChatColors.Grey}Command is on cooldown for", seconds, - $"{ChatColors.Grey}seconds!" + $"{ChatColors.Grey}second" + (seconds == 1 ? "" : "s") + "." }; } public IView InvalidParameter(string parameter, string expected) { return new SimpleView { PREFIX, - $"{ChatColors.Red}Invalid parameter '{ChatColors.LightBlue}{parameter}{ChatColors.Red}', expected a(n) {ChatColors.White}{expected}{ChatColors.Red}." + $"{ChatColors.Red}Invalid parameter '{ChatColors.LightBlue}{parameter}{ChatColors.Red}',", + "expected a" + (expected[0].IsVowel() ? "n" : ""), + $"{ChatColors.White}{expected}{ChatColors.Red}." }; } public IView NoPermissionMessage(string permission) { return new SimpleView { PREFIX, - $"{ChatColors.Red}This command requires the {ChatColors.White}{permission}{ChatColors.Red} permission." + $"{ChatColors.DarkRed}This requires the {ChatColors.White}{permission}{ChatColors.Red} permission." }; } diff --git a/lang/Jailbreak.English/LastRequest/CoinflipLocale.cs b/lang/Jailbreak.English/LastRequest/CoinflipLocale.cs index 1658bea..1617bc3 100644 --- a/lang/Jailbreak.English/LastRequest/CoinflipLocale.cs +++ b/lang/Jailbreak.English/LastRequest/CoinflipLocale.cs @@ -26,7 +26,9 @@ public class CoinflipLocale : LastRequestLocale, ILRCFLocale { public IView CoinLandsOn(bool heads) { return new SimpleView { - PREFIX, "The coin lands on" + ChatColors.Green, heads ? "Heads" : "Tails" + PREFIX, + "The coin landed on" + ChatColors.Green, + heads ? "Heads" : "Tails" + ChatColors.White + "." }; } } \ No newline at end of file diff --git a/lang/Jailbreak.English/LastRequest/LastRequestLocale.cs b/lang/Jailbreak.English/LastRequest/LastRequestLocale.cs index 209f79b..84d2db9 100644 --- a/lang/Jailbreak.English/LastRequest/LastRequestLocale.cs +++ b/lang/Jailbreak.English/LastRequest/LastRequestLocale.cs @@ -15,7 +15,7 @@ public class LastRequestLocale : ILRLocale, ILanguage { public static readonly FormatObject PREFIX = new HiddenFormatObject( - $" {ChatColors.DarkRed}[{ChatColors.LightRed}LR{ChatColors.DarkRed}]") { + $" {ChatColors.Green}[{ChatColors.Lime}LR{ChatColors.Green}]") { // Hide in panorama and center text Plain = false, Panorama = false, Chat = true }; @@ -24,7 +24,7 @@ public class LastRequestLocale : ILRLocale, return new SimpleView { { PREFIX, - $"Last Request has been enabled. {ChatColors.Grey}Type {ChatColors.LightBlue}!lr{ChatColors.Grey} to start a last request." + $"Last Request activated. {ChatColors.Grey}Type {ChatColors.LightBlue}!lr{ChatColors.Grey} to start a last request." } }; } @@ -33,7 +33,7 @@ public class LastRequestLocale : ILRLocale, return new SimpleView { { PREFIX, - $"{ChatColors.Grey}Last Request has been {ChatColors.Red}disabled{ChatColors.Grey}." + $"{ChatColors.Grey}Last Request {ChatColors.Red}disabled{ChatColors.Grey}." } }; } @@ -52,9 +52,9 @@ public class LastRequestLocale : ILRLocale, return new SimpleView { PREFIX, lr.Prisoner, - ChatColors.Grey + "is preparing a", + ChatColors.Grey + "is starting a", ChatColors.White + lr.Type.ToFriendlyString(), - ChatColors.Grey + "Last Request against", + ChatColors.Grey + "LR against", lr.Guard }; } @@ -74,36 +74,29 @@ public class LastRequestLocale : ILRLocale, var tNull = !lr.Prisoner.IsReal(); var gNull = !lr.Guard.IsReal(); if (tNull && gNull) - return new SimpleView { PREFIX, "Last Request has been decided." }; + return new SimpleView { PREFIX, "Last Request decided." }; if (tNull && result == LRResult.PRISONER_WIN) return new SimpleView { - PREFIX, lr.Guard, "lost the LR, but the prisoner left the game." + PREFIX, lr.Guard, "lost the LR, but the prisoner left the game?" }; if (gNull && result == LRResult.GUARD_WIN) return new SimpleView { - PREFIX, lr.Prisoner, "lost the LR, but the guard left the game." + PREFIX, lr.Prisoner, "lost the LR, but the guard left the game?" }; - switch (result) { - case LRResult.TIMED_OUT: - return new SimpleView { - PREFIX, ChatColors.Grey.ToString(), "Last Request has timed out." - }; - case LRResult.INTERRUPTED: - return new SimpleView { - PREFIX, - ChatColors.Grey.ToString(), - "Last Request has been interrupted." - }; - default: - return new SimpleView { - PREFIX, - result == LRResult.PRISONER_WIN ? lr.Prisoner : lr.Guard, - "won the LR." - }; - } + return result switch { + LRResult.TIMED_OUT => new SimpleView { + PREFIX, ChatColors.Grey.ToString(), "Last Request timed out." + }, + LRResult.INTERRUPTED => new SimpleView { + PREFIX, ChatColors.Grey.ToString(), "Last Request interrupted." + }, + _ => new SimpleView { + PREFIX, result == LRResult.PRISONER_WIN ? lr.Prisoner : lr.Guard, "won." + } + }; } public IView CannotLR(string reason) { @@ -149,14 +142,4 @@ public class LastRequestLocale : ILRLocale, => new SimpleView { PREFIX, "You are not in the same LR as them, damage blocked." }; - - public IView InvalidPlayerChoice(CCSPlayerController player, string reason) { - return new SimpleView { - PREFIX, - "Invalid player choice: ", - player, - " Reason: ", - reason - }; - } } \ No newline at end of file diff --git a/lang/Jailbreak.English/LastRequest/RPSLocale.cs b/lang/Jailbreak.English/LastRequest/RPSLocale.cs index ad3b676..0d6aa4a 100644 --- a/lang/Jailbreak.English/LastRequest/RPSLocale.cs +++ b/lang/Jailbreak.English/LastRequest/RPSLocale.cs @@ -11,7 +11,7 @@ public class RPSLocale : LastRequestLocale, ILRRPSLocale { public IView BothPlayersMadeChoice() { return new SimpleView { - PREFIX, "Both players have rocked, papered, and scissored! (ew)" + PREFIX, "Both players rocked, papered, and scissored! (ew)" }; } @@ -23,13 +23,13 @@ public class RPSLocale : LastRequestLocale, ILRRPSLocale { int guardPick, int prisonerPick) { return new SimpleView { PREFIX, - "Results: ", + "Results:", guard, - " picked ", + "picked", toRPS(guardPick), - " and ", + "and", prisoner, - " picked ", + "picked", toRPS(prisonerPick) }; } diff --git a/lang/Jailbreak.English/LastRequest/RaceLocale.cs b/lang/Jailbreak.English/LastRequest/RaceLocale.cs index 1ea9220..c008db9 100644 --- a/lang/Jailbreak.English/LastRequest/RaceLocale.cs +++ b/lang/Jailbreak.English/LastRequest/RaceLocale.cs @@ -20,15 +20,14 @@ public class RaceLocale : LastRequestLocale, ILRRaceLocale { SimpleView.NEWLINE, { PREFIX, $"Type {ChatColors.Blue}!endrace{ChatColors.White} to set the end point!" - }, - SimpleView.NEWLINE + } }; public IView RaceStartingMessage(CCSPlayerController prisoner) { return new SimpleView { { PREFIX, prisoner, - " is starting a race. Pay attention to where they set the end point!" + "is racing you. Pay attention to where they set the end point!" } }; } @@ -37,14 +36,17 @@ public class RaceLocale : LastRequestLocale, ILRRaceLocale { return new SimpleView { { PREFIX, - $"You must be in a race {ChatColors.Blue + "!lr" + ChatColors.White} to use this command" + $"{ChatColors.Red}You must be in a race {ChatColors.Blue + "!lr" + ChatColors.Red} to use this." } }; } public IView NotInPendingState() { return new SimpleView { - { PREFIX, "You must be in the pending state to use this command." } + { + PREFIX, + ChatColors.Red + "You must be in the pending state to use this command." + } }; } } \ No newline at end of file diff --git a/lang/Jailbreak.English/Mute/WardenPeaceLocale.cs b/lang/Jailbreak.English/Mute/WardenPeaceLocale.cs index bb5e911..da428ae 100644 --- a/lang/Jailbreak.English/Mute/WardenPeaceLocale.cs +++ b/lang/Jailbreak.English/Mute/WardenPeaceLocale.cs @@ -4,6 +4,7 @@ using Jailbreak.Formatting.Core; using Jailbreak.Formatting.Logistics; using Jailbreak.Formatting.Objects; using Jailbreak.Formatting.Views.Warden; +using Microsoft.Extensions.Primitives; namespace Jailbreak.English.Mute; @@ -17,32 +18,40 @@ public class WardenPeaceLocale : IWardenPeaceLocale, public IView PeaceEnactedByAdmin(int seconds) { return new SimpleView { - PREFIX, "An admin enacted peace for", seconds, "seconds." + PREFIX, + $"{ChatColors.Red}An admin {ChatColors.White}enacted peace for", + seconds, + "second" + (seconds == 1 ? "" : "s") + "." }; } public IView WardenEnactedPeace(int seconds) { return new SimpleView { - PREFIX, "Warden enacted peace for", seconds, "seconds." + PREFIX, + $"{ChatColors.Blue}The warden {ChatColors.White}enacted peace for", + seconds, + "seconds." }; } public IView GeneralPeaceEnacted(int seconds) { return new SimpleView { - PREFIX, "Peace has been enacted for", seconds, "seconds." + PREFIX, + "Peace was enacted for", + seconds, + "second" + (seconds == 1 ? "" : "s") + "." }; } public IView UnmutedGuards => new SimpleView { - { PREFIX, $"{ChatColors.Blue}Guards {ChatColors.Grey}have been unmuted." } + { PREFIX, $"{ChatColors.Blue}Guards {ChatColors.Grey}were unmuted." } }; public IView UnmutedPrisoners => new SimpleView { { - PREFIX, - $"{ChatColors.LightRed}Prisoners {ChatColors.Grey}have been unmuted." + PREFIX, $"{ChatColors.LightRed}Prisoners {ChatColors.Grey}were unmuted." } }; @@ -61,7 +70,7 @@ public class WardenPeaceLocale : IWardenPeaceLocale, public IView DeadReminder => new SimpleView { - { PREFIX, $"{ChatColors.Red}You are dead and cannot speak!" } + { PREFIX, $"{ChatColors.Red}You are dead and cannot speak." } }; public IView AdminDeadReminder diff --git a/lang/Jailbreak.English/Rebel/RebelLocale.cs b/lang/Jailbreak.English/Rebel/RebelLocale.cs index 017ecca..acc08f8 100644 --- a/lang/Jailbreak.English/Rebel/RebelLocale.cs +++ b/lang/Jailbreak.English/Rebel/RebelLocale.cs @@ -17,5 +17,5 @@ public class RebelLocale : IRebelLocale, }; public IView NoLongerRebel - => new SimpleView { PREFIX, "You are no longer a rebel." }; + => new SimpleView { PREFIX, "You are no longer red." }; } \ No newline at end of file diff --git a/lang/Jailbreak.English/SpecialDay/GunDayLocale.cs b/lang/Jailbreak.English/SpecialDay/GunDayLocale.cs index 73bb473..79784d6 100644 --- a/lang/Jailbreak.English/SpecialDay/GunDayLocale.cs +++ b/lang/Jailbreak.English/SpecialDay/GunDayLocale.cs @@ -19,15 +19,12 @@ public class GunDayLocale() : SoloDayLocale("Gun Game", public IView PromotedTo(string weapon, int weaponsLeft) { if (weaponsLeft == 1) return new SimpleView { - PREFIX, - "You were promoted to", - weapon + ".", - ChatColors.Green + "LAST WEAPON!" + PREFIX, "Promoted to", weapon + ".", ChatColors.Green + "LAST WEAPON!" }; return new SimpleView { PREFIX, - "You were promoted to", + "Promoted to", weapon + ".", weaponsLeft, "weapons left." @@ -38,7 +35,7 @@ public class GunDayLocale() : SoloDayLocale("Gun Game", return new SimpleView { PREFIX, player, - "is on their last weapon!", + "is on the last weapon!", ChatColors.LightRed + "Watch out!" }; } diff --git a/lang/Jailbreak.English/SpecialDay/HNSDayLocale.cs b/lang/Jailbreak.English/SpecialDay/HNSDayLocale.cs index 1cbe00a..4f0bf57 100644 --- a/lang/Jailbreak.English/SpecialDay/HNSDayLocale.cs +++ b/lang/Jailbreak.English/SpecialDay/HNSDayLocale.cs @@ -3,7 +3,7 @@ namespace Jailbreak.English.SpecialDay; public class HNSDayLocale() : TeamDayLocale("Hide and Seek", - "CTs must hide while the Ts seek!", "Ts have 250 HP!") { + "CTs must hide while the Ts seek!", "Ts have increased HP!") { public IView StayInArmory => new SimpleView { PREFIX, "Today is", Name, ", stay in the armory!" }; @@ -15,13 +15,16 @@ public class HNSDayLocale() : TeamDayLocale("Hide and Seek", Name, "begins in", seconds, - "seconds." + "second" + (seconds == 1 ? "" : "s") + "." }; } public IView DamageWarning(int seconds) { return new SimpleView { - PREFIX, "You will be vulnerable to damage in", seconds, "seconds." + PREFIX, + "You will be vulnerable to damage in", + seconds, + "second" + (seconds == 1 ? "" : "s") + "." }; } } \ No newline at end of file diff --git a/lang/Jailbreak.English/SpecialDay/InfectionDayLocale.cs b/lang/Jailbreak.English/SpecialDay/InfectionDayLocale.cs index 7f70b52..787e7d0 100644 --- a/lang/Jailbreak.English/SpecialDay/InfectionDayLocale.cs +++ b/lang/Jailbreak.English/SpecialDay/InfectionDayLocale.cs @@ -25,13 +25,13 @@ public class InfectionDayLocale() : TeamDayLocale("Infection", return player == null || !player.IsValid ? new SimpleView { PREFIX, - $"{ChatColors.Red}You were {ChatColors.DarkRed}infected{ChatColors.Red}! You are now a zombie!" + $"{ChatColors.Red}You were {ChatColors.DarkRed}infected{ChatColors.Red}!" } : new SimpleView { PREFIX, $"{ChatColors.Red}You were {ChatColors.DarkRed}infected{ChatColors.Red} by", player, - "! You are now a zombie!" + "!" }; } diff --git a/lang/Jailbreak.English/SpecialDay/SDLocale.cs b/lang/Jailbreak.English/SpecialDay/SDLocale.cs index b6c8820..09c9910 100644 --- a/lang/Jailbreak.English/SpecialDay/SDLocale.cs +++ b/lang/Jailbreak.English/SpecialDay/SDLocale.cs @@ -16,11 +16,19 @@ public class SDLocale : ISDLocale, ILanguage { }; public IView SpecialDayRunning(string name) { - return new SimpleView { PREFIX, name, "is currently running!" }; + return new SimpleView { + PREFIX, + ChatColors.DarkRed + name, + ChatColors.Red + "is currently running." + }; } public IView InvalidSpecialDay(string name) { - return new SimpleView { PREFIX, name, "is not a valid special day!" }; + return new SimpleView { + PREFIX, + ChatColors.DarkRed + name, + ChatColors.Red + "is not a valid special day." + }; } public IView SpecialDayCooldown(int rounds) { @@ -28,7 +36,8 @@ public class SDLocale : ISDLocale, ILanguage { PREFIX, "You must wait", rounds, - "more rounds before starting a special day." + "more round" + (rounds == 1 ? "" : "s") + + " before starting a special day." }; } @@ -37,7 +46,7 @@ public class SDLocale : ISDLocale, ILanguage { PREFIX, "You must start a special day within", maxTime, - "seconds of the round start." + "second" + (maxTime == 1 ? "" : "s") + " of the round start." }; } } \ No newline at end of file diff --git a/lang/Jailbreak.English/SpecialDay/SpeedrunDayLocale.cs b/lang/Jailbreak.English/SpecialDay/SpeedrunDayLocale.cs index c5ff049..e5e0a87 100644 --- a/lang/Jailbreak.English/SpecialDay/SpeedrunDayLocale.cs +++ b/lang/Jailbreak.English/SpecialDay/SpeedrunDayLocale.cs @@ -39,7 +39,7 @@ public class SpeedrunDayLocale() : SoloDayLocale("Speedrunners", return new SimpleView { { PREFIX, - $"Round #{ChatColors.Yellow}{round}{ChatColors.Default} begins! The slowest", + $"Round {ChatColors.Yellow}#{round}{ChatColors.Default} begins! The slowest", "player to reach the goal will be eliminated!" }, SimpleView.NEWLINE, @@ -74,7 +74,7 @@ public class SpeedrunDayLocale() : SoloDayLocale("Speedrunners", PREFIX, "The original speedrunner left, so", player, - "is now the speedrunner!" + "is now the speedrunner." }; } @@ -83,7 +83,7 @@ public class SpeedrunDayLocale() : SoloDayLocale("Speedrunners", PREFIX, "The original speedrunner isn't moving, so", player, - "is now the speedrunner!" + "is now the speedrunner." }; } @@ -145,7 +145,7 @@ public class SpeedrunDayLocale() : SoloDayLocale("Speedrunners", "reached the goal. Eliminating one player on each time." }, SimpleView.NEWLINE, - { PREFIX, "Randomly selected the path from ", player, "." } + { PREFIX, "Randomly selected the path from", player, "." } }; } } \ No newline at end of file diff --git a/lang/Jailbreak.English/Warden/WardenCmdOpenLocale.cs b/lang/Jailbreak.English/Warden/WardenCmdOpenLocale.cs index af0a222..0c22071 100644 --- a/lang/Jailbreak.English/Warden/WardenCmdOpenLocale.cs +++ b/lang/Jailbreak.English/Warden/WardenCmdOpenLocale.cs @@ -30,7 +30,9 @@ public class WardenCmdOpenLocale : IWardenCmdOpenLocale, } public IView CellsOpened - => new SimpleView { WardenLocale.PREFIX, "Cells were auto-opened." }; + => new SimpleView { + WardenLocale.PREFIX, ChatColors.Grey + "Cells were auto-opened." + }; public IView OpeningFailed => new SimpleView { WardenLocale.PREFIX, "Failed to open the cells." }; diff --git a/mod/Jailbreak.Debug/PlayerZoneCreator.cs b/mod/Jailbreak.Debug/PlayerZoneCreator.cs index c7934e4..7c32b72 100644 --- a/mod/Jailbreak.Debug/PlayerZoneCreator.cs +++ b/mod/Jailbreak.Debug/PlayerZoneCreator.cs @@ -48,7 +48,7 @@ public class PlayerZoneCreator : BasicZoneCreator, ITypedZoneCreator { } var pawn = player.PlayerPawn.Value; - if (pawn == null) { + if (pawn == null || !pawn.IsValid) { timer?.Kill(); return; } diff --git a/mod/Jailbreak.LastGuard/LastGuard.cs b/mod/Jailbreak.LastGuard/LastGuard.cs index f9d45ad..b0e0c1f 100644 --- a/mod/Jailbreak.LastGuard/LastGuard.cs +++ b/mod/Jailbreak.LastGuard/LastGuard.cs @@ -18,43 +18,46 @@ namespace Jailbreak.LastGuard; public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager) : ILastGuardService, IPluginBehavior { - public readonly FakeConVar CvAlwaysOverrideCt = new( + public static readonly FakeConVar CV_ALWAYS_OVERRIDE_CT = new( "css_jb_lg_apply_lower_hp", "If true, the LG will be forced lower health if calculated"); - public readonly FakeConVar CvGuardHealthRatio = new( + public static readonly FakeConVar CV_GUARD_HEALTH_RATIO = new( "css_jb_lg_ct_hp_ratio", "Ratio of CT : T Health", 0.6, ConVarFlags.FCVAR_NONE, new RangeValidator(0.00001, 10)); - public readonly FakeConVar CvLGBaseRoundTime = new("css_jb_lg_time_base", - "Round time to set when LG is activated, 0 to disable", 60); + public static readonly FakeConVar CV_LG_BASE_ROUND_TIME = + new("css_jb_lg_time_base", + "Round time to set when LG is activated, 0 to disable", 60); - public readonly FakeConVar CvLGKillBonusTime = + public static readonly FakeConVar CV_LG_KILL_BONUS_TIME = new("css_jb_lg_time_per_kill", "Additional round time to add per prisoner kill", 10); - public readonly FakeConVar CvLGMaxTime = new("css_jb_lg_time_max", - "Max round time to give the LG regardless of bonuses", 120); + public static readonly FakeConVar CV_LG_MAX_TIME = + new("css_jb_lg_time_max", + "Max round time to give the LG regardless of bonuses", 120); - public readonly FakeConVar CvLGPerPrisonerTime = + public static readonly FakeConVar CV_LG_PER_PRISONER_TIME = new("css_jb_lg_time_per_prisoner", "Additional round time to add per prisoner", 10); - public readonly FakeConVar CvLGWeapon = new("css_jb_lg_t_weapon", - "Weapon to give remaining prisoners once LG activates", "", - ConVarFlags.FCVAR_NONE, new WeaponValidator()); + public static readonly FakeConVar CV_LG_WEAPON = + new("css_jb_lg_t_weapon", + "Weapon to give remaining prisoners once LG activates", "", + ConVarFlags.FCVAR_NONE, new ItemValidator()); - public readonly FakeConVar CvMaxCtHealth = new("css_jb_lg_max_hp", - "Max HP that the LG can have otherwise", 125, ConVarFlags.FCVAR_NONE, - new RangeValidator(1, 1000)); + public static readonly FakeConVar CV_MAX_CT_HEALTH = + new("css_jb_lg_max_hp", "Max HP that the LG can have otherwise", 125, + ConVarFlags.FCVAR_NONE, new RangeValidator(1, 1000)); - public readonly FakeConVar CvMaxTHealthContribution = new( + public static readonly FakeConVar CV_MAX_T_HEALTH_CONTRIBUTION = new( "css_jb_lg_t_max_hp", "Max HP to contribute per T to LG", 200, ConVarFlags.FCVAR_NONE, new RangeValidator(1, 1000)); - public readonly FakeConVar CvMinimumCts = new("css_jb_lg_min_cts", - "Minimum number of CTs to start last guard", 2, ConVarFlags.FCVAR_NONE, - new RangeValidator(1, 32)); + public static readonly FakeConVar CV_MINIMUM_CTS = + new("css_jb_lg_min_cts", "Minimum number of CTs to start last guard", 2, + ConVarFlags.FCVAR_NONE, new RangeValidator(1, 32)); private readonly Random rng = new(); private bool canStart; @@ -71,11 +74,11 @@ public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager) API.Stats?.PushStat(new ServerStat("JB_LASTGUARD", lastGuard.SteamID.ToString())); - var calculated = CalculateHealth(); + var calculated = calculateHealth(); - if (calculated < guardPlayerPawn.Health && !CvAlwaysOverrideCt.Value) { - if (guardPlayerPawn.Health > CvMaxCtHealth.Value) - guardPlayerPawn.Health = CvMaxCtHealth.Value; + if (calculated < guardPlayerPawn.Health && !CV_ALWAYS_OVERRIDE_CT.Value) { + if (guardPlayerPawn.Health > CV_MAX_CT_HEALTH.Value) + guardPlayerPawn.Health = CV_MAX_CT_HEALTH.Value; } else { guardPlayerPawn.Health = calculated; } Utilities.SetStateChanged(guardPlayerPawn, "CBaseEntity", "m_iHealth"); @@ -87,11 +90,11 @@ public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager) .Where(p => p is { PawnIsAlive: true, Team: CsTeam.Terrorist }) .ToList(); - if (CvLGBaseRoundTime.Value != 0) - RoundUtil.SetTimeRemaining(Math.Min(CvLGBaseRoundTime.Value, - CvLGMaxTime.Value)); - addRoundTimeCapped(CvLGPerPrisonerTime.Value * lastGuardPrisoners.Count, - CvLGMaxTime.Value); + if (CV_LG_BASE_ROUND_TIME.Value != 0) + RoundUtil.SetTimeRemaining(Math.Min(CV_LG_BASE_ROUND_TIME.Value, + CV_LG_MAX_TIME.Value)); + addRoundTimeCapped(CV_LG_PER_PRISONER_TIME.Value * lastGuardPrisoners.Count, + CV_LG_MAX_TIME.Value); var prisonerHp = lastGuardPrisoners.Sum(prisoner @@ -101,15 +104,15 @@ public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager) .ToAllCenter() .ToAllChat(); - if (string.IsNullOrEmpty(CvLGWeapon.Value)) return; + if (string.IsNullOrEmpty(CV_LG_WEAPON.Value)) return; foreach (var player in lastGuardPrisoners) - player.GiveNamedItem(CvLGWeapon.Value); + player.GiveNamedItem(CV_LG_WEAPON.Value); } public void DisableLastGuardForRound() { canStart = false; } - public int CalculateHealth() { + private int calculateHealth() { var aliveTerrorists = Utilities.GetPlayers() .Where(plr => plr is { PawnIsAlive: true, Team: CsTeam.Terrorist }) .ToList(); @@ -117,8 +120,8 @@ public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager) return (int)Math.Floor(aliveTerrorists .Select(player => player.PlayerPawn.Value?.Health ?? 0) .Select(playerHealth - => Math.Min(playerHealth, CvMaxTHealthContribution.Value)) - .Sum() * CvGuardHealthRatio.Value); + => Math.Min(playerHealth, CV_MAX_T_HEALTH_CONTRIBUTION.Value)) + .Sum() * CV_GUARD_HEALTH_RATIO.Value); } [GameEventHandler] @@ -132,7 +135,7 @@ public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager) if (player.Team != CsTeam.Terrorist) return HookResult.Continue; - addRoundTimeCapped(CvLGKillBonusTime.Value, CvLGMaxTime.Value); + addRoundTimeCapped(CV_LG_KILL_BONUS_TIME.Value, CV_LG_MAX_TIME.Value); giveGun(player); return HookResult.Continue; @@ -200,7 +203,7 @@ public class LastGuard(ILGLocale notifications, ILastRequestManager lrManager) canStart = Utilities.GetPlayers() .Count(plr => plr is { PawnIsAlive: true, Team: CsTeam.CounterTerrorist }) - >= CvMinimumCts.Value; + >= CV_MINIMUM_CTS.Value; return HookResult.Continue; } diff --git a/mod/Jailbreak.LastGuard/LastGuardConfig.cs b/mod/Jailbreak.LastGuard/LastGuardConfig.cs deleted file mode 100644 index 73e460f..0000000 --- a/mod/Jailbreak.LastGuard/LastGuardConfig.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Jailbreak.LastGuard; - -[Obsolete("No longer used, use FakeConvars")] -public class LastGuardConfig { - public string? LastGuardWeapon { get; } = ""; - public int MinimumCTs { get; } = 4; -} \ No newline at end of file diff --git a/mod/Jailbreak.LastRequest/LastRequestManager.cs b/mod/Jailbreak.LastRequest/LastRequestManager.cs index fd66438..f2dfb25 100644 --- a/mod/Jailbreak.LastRequest/LastRequestManager.cs +++ b/mod/Jailbreak.LastRequest/LastRequestManager.cs @@ -20,16 +20,16 @@ namespace Jailbreak.LastRequest; public class LastRequestManager(ILRLocale messages, IServiceProvider provider) : ILastRequestManager, IDamageBlocker { - public readonly FakeConVar CvLRBaseTime = new("css_jb_lr_time_base", + public static readonly FakeConVar CV_LR_BASE_TIME = new("css_jb_lr_time_base", "Round time to set when LR is activated, 0 to disable", 60); - public readonly FakeConVar CvLRBonusTime = new("css_jb_lr_time_per_lr", + public static readonly FakeConVar CV_LR_BONUS_TIME = new("css_jb_lr_time_per_lr", "Additional round time to add per LR completion", 30); - public readonly FakeConVar CvLRGuardTime = + public static readonly FakeConVar CV_LR_GUARD_TIME = new("css_jb_lr_time_per_guard", "Additional round time to add per guard"); - public readonly FakeConVar CvPrisonerToLR = + public static readonly FakeConVar CV_PRISONER_TO_LR = new("css_jb_lr_activate_lr_at", "Number of prisoners to activate LR at", 2, ConVarFlags.FCVAR_NONE, new RangeValidator(1, 32)); @@ -92,12 +92,12 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider) var cts = Utilities.GetPlayers() .Count(p => p is { Team: CsTeam.CounterTerrorist, PawnIsAlive: true }); - if (CvLRBaseTime.Value != 0) RoundUtil.SetTimeRemaining(CvLRBaseTime.Value); + if (CV_LR_BASE_TIME.Value != 0) RoundUtil.SetTimeRemaining(CV_LR_BASE_TIME.Value); - RoundUtil.AddTimeRemaining(CvLRGuardTime.Value * cts); + RoundUtil.AddTimeRemaining(CV_LR_GUARD_TIME.Value * cts); foreach (var player in Utilities.GetPlayers()) { - player.ExecuteClientCommand($"play sounds/lr"); + player.ExecuteClientCommand("play sounds/lr"); if (player.Team != CsTeam.Terrorist || !player.PawnIsAlive) continue; if (died != null && player.SteamID == died.SteamID) continue; player.ExecuteClientCommandFromServer("css_lr"); @@ -132,7 +132,7 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider) public bool EndLastRequest(AbstractLastRequest lr, LRResult result) { if (result is LRResult.GUARD_WIN or LRResult.PRISONER_WIN) { - RoundUtil.AddTimeRemaining(CvLRBonusTime.Value); + RoundUtil.AddTimeRemaining(CV_LR_BONUS_TIME.Value); messages.LastRequestDecided(lr, result).ToAllChat(); } @@ -189,7 +189,7 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider) if (player.Team != CsTeam.Terrorist) return HookResult.Continue; - if (countAlivePrisoners() - 1 > CvPrisonerToLR.Value) + if (countAlivePrisoners() - 1 > CV_PRISONER_TO_LR.Value) return HookResult.Continue; if (Utilities.GetPlayers().All(p => p.Team != CsTeam.CounterTerrorist)) @@ -222,7 +222,7 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider) if (!IsLREnabledForRound) return HookResult.Continue; if (player.Team != CsTeam.Terrorist) return HookResult.Continue; - if (countAlivePrisoners() > CvPrisonerToLR.Value) + if (countAlivePrisoners() > CV_PRISONER_TO_LR.Value) return HookResult.Continue; EnableLR(); diff --git a/mod/Jailbreak.LastRequest/LastRequests/BulletForBullet.cs b/mod/Jailbreak.LastRequest/LastRequests/BulletForBullet.cs index d6c6888..06e9b3a 100644 --- a/mod/Jailbreak.LastRequest/LastRequests/BulletForBullet.cs +++ b/mod/Jailbreak.LastRequest/LastRequests/BulletForBullet.cs @@ -45,7 +45,8 @@ public class BulletForBullet : TeleportingRequest { designerName = designer; MenuManager.CloseActiveMenu(player); - msg.WeaponSelected(player, designerName).ToChat(Prisoner, Guard); + msg.WeaponSelected(player, designerName.GetFriendlyWeaponName()) + .ToChat(Prisoner, Guard); State = LRState.ACTIVE; diff --git a/mod/Jailbreak.Rebel/C4Bomb/C4Behavior.cs b/mod/Jailbreak.Rebel/C4Bomb/C4Behavior.cs index fc3a3a3..19e74d3 100644 --- a/mod/Jailbreak.Rebel/C4Bomb/C4Behavior.cs +++ b/mod/Jailbreak.Rebel/C4Bomb/C4Behavior.cs @@ -1,6 +1,8 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Cvars; +using CounterStrikeSharp.API.Modules.Cvars.Validators; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Utils; using Jailbreak.Formatting.Extensions; @@ -25,11 +27,27 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService) private BasePlugin? plugin; + public static readonly FakeConVar CV_GIVE_BOMB = new("css_jb_c4_give", + "Whether to give a random prisoner a bomb at the beginning of the round.", + true); + + public static readonly FakeConVar CV_C4_DELAY = new("css_jb_c4_delay", + "Time in seconds that the bomb takes to explode", .75f, + ConVarFlags.FCVAR_NONE, new RangeValidator(0, 2)); + + public static readonly FakeConVar CV_C4_RADIUS = + new("css_jb_c4_radius", "Bomb explosion radius", 350, + ConVarFlags.FCVAR_NONE, new RangeValidator(0, 10000)); + + public static readonly FakeConVar CV_C4_BASE_DAMAGE = + new("css_jb_c4_damage", "Base damage to apply", 340, ConVarFlags.FCVAR_NONE, + new RangeValidator(0, 10000)); + public void ClearActiveC4s() { bombs.Clear(); } public void TryGiveC4ToPlayer(CCSPlayerController player) { var bombEntity = new CC4(player.GiveNamedItem("weapon_c4")); - bombs.Add(bombEntity, new C4Metadata(0.75f, false)); + bombs.Add(bombEntity, new C4Metadata(false)); ic4Locale.JihadC4Received.ToChat(player); ic4Locale.JihadC4Usage1.ToChat(player); @@ -45,7 +63,6 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService) tryEmitSound(player, "jb.jihad", 1, 1f, 0f); - bombs[bombEntity].Delay = delay; bombs[bombEntity].IsDetonating = true; rebelService.MarkRebel(player); @@ -95,14 +112,15 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService) || activeWeapon.Handle != bomb.Handle) continue; - StartDetonationAttempt(bombCarrier, meta.Delay, bomb); + StartDetonationAttempt(bombCarrier, CV_C4_DELAY.Value, bomb); } } [GameEventHandler] public HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) { ClearActiveC4s(); - TryGiveC4ToRandomTerrorist(); + + if (CV_GIVE_BOMB.Value) TryGiveC4ToRandomTerrorist(); return HookResult.Continue; } @@ -154,11 +172,10 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService) var distanceFromBomb = ct.PlayerPawn.Value!.AbsOrigin!.Distance(player.PlayerPawn.Value .AbsOrigin!); - if (distanceFromBomb > 350f) continue; + if (distanceFromBomb > CV_C4_RADIUS.Value) continue; - // 350f = "bombRadius" - var damage = 340f; - damage *= (350f - distanceFromBomb) / 350f; + var damage = CV_C4_BASE_DAMAGE.Value; + damage *= (CV_C4_RADIUS.Value - distanceFromBomb) / CV_C4_RADIUS.Value; float healthRef = ct.PlayerPawn.Value.Health; if (healthRef <= damage) { ct.CommitSuicide(true, true); @@ -183,8 +200,7 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService) volume, delay); } - private class C4Metadata(float delay, bool isDetonating) { - public float Delay { get; set; } = delay; + private class C4Metadata(bool isDetonating) { public bool IsDetonating { get; set; } = isDetonating; } } \ No newline at end of file diff --git a/mod/Jailbreak.Rebel/RebelManager.cs b/mod/Jailbreak.Rebel/RebelManager.cs index 24998c8..1fd76c3 100644 --- a/mod/Jailbreak.Rebel/RebelManager.cs +++ b/mod/Jailbreak.Rebel/RebelManager.cs @@ -20,9 +20,9 @@ public class RebelManager(IRebelLocale notifs, IRichLogService logs) [Obsolete("No longer used, use FakeConvar")] public static readonly int MAX_REBEL_TIME = 45; - public readonly FakeConVar CvRebelTime = new("css_jb_rebel_time", - "Time to mark a rebel for", 30, ConVarFlags.FCVAR_NONE, - new RangeValidator(0, 500)); + public static readonly FakeConVar CV_REBEL_TIME = + new("css_jb_rebel_time", "Time to mark a rebel for", 45, + ConVarFlags.FCVAR_NONE, new RangeValidator(0, 500)); private readonly Dictionary rebelTimes = new(); private bool enabled = true; @@ -71,7 +71,7 @@ public class RebelManager(IRebelLocale notifs, IRichLogService logs) API.Stats?.PushStat(new ServerStat("JB_REBEL_STARTED", $"{player.SteamID} {pos.X:F2} {pos.Y:F2} {pos.Z:F2}")); - if (time == -1) time = CvRebelTime.Value; + if (time == -1) time = CV_REBEL_TIME.Value; rebelTimes[player] = DateTimeOffset.Now.ToUnixTimeSeconds() + time; applyRebelColor(player); @@ -128,10 +128,10 @@ public class RebelManager(IRebelLocale notifs, IRichLogService logs) // https://www.desmos.com/calculator/g2v6vvg7ax private float getRebelTimePercentage(CCSPlayerController player) { var x = GetRebelTimeLeft(player); - if (x > CvRebelTime.Value) return 1; + if (x > CV_REBEL_TIME.Value) return 1; if (x <= 0) return 0; - return (float)(100 - (CvRebelTime.Value - x) - * Math.Sqrt(CvRebelTime.Value - x) / 3.8f) / 100; + return (float)(100 - (CV_REBEL_TIME.Value - x) + * Math.Sqrt(CV_REBEL_TIME.Value - x) / 3.8f) / 100; } private Color getRebelColor(CCSPlayerController player) { diff --git a/mod/Jailbreak.SpecialDay/SpecialDayCommand.cs b/mod/Jailbreak.SpecialDay/SpecialDayCommand.cs index 69b299d..416c666 100644 --- a/mod/Jailbreak.SpecialDay/SpecialDayCommand.cs +++ b/mod/Jailbreak.SpecialDay/SpecialDayCommand.cs @@ -20,15 +20,15 @@ namespace Jailbreak.SpecialDay; public class SpecialDayCommand(IWardenService warden, ISpecialDayFactory factory, IWardenLocale wardenMsg, ISDLocale sdMsg, ISpecialDayManager sd) : IPluginBehavior { - public static FakeConVar CvRoundsBetweenSD = new( + public static readonly FakeConVar CV_ROUNDS_BETWEEN_SD = new( "css_jb_sd_round_cooldown", "Rounds between special days", 4); - public static FakeConVar CvMaxElapsedTime = new( + public static readonly FakeConVar CV_MAX_ELAPSED_TIME = new( "css_jb_sd_max_elapsed_time", "Max time elapsed in a round to be able to call a special day", 30); - private SpecialDayMenuSelector? menuSelector; - private BasePlugin? plugin; + private SpecialDayMenuSelector menuSelector = null!; + private BasePlugin plugin = null!; // css_lr public void Start(BasePlugin basePlugin) { @@ -41,6 +41,17 @@ public class SpecialDayCommand(IWardenService warden, [ConsoleCommand("css_startday", "Start a special day as the warden")] public void Command_SpecialDay(CCSPlayerController? executor, CommandInfo info) { + if (executor != null && sd.IsSDRunning && info.ArgCount == 1) { + // SD is already running + if (sd.CurrentSD is ISpecialDayMessageProvider messaged) + sdMsg.SpecialDayRunning(messaged.Locale.Name).ToChat(executor); + else + sdMsg.SpecialDayRunning(sd.CurrentSD?.Type.ToString() ?? "Unknown") + .ToChat(executor); + + return; + } + if (executor != null && !AdminManager.PlayerHasPermissions(executor, "@css/rcon")) { if (!warden.IsWarden(executor) || RoundUtil.IsWarmup()) { @@ -59,14 +70,14 @@ public class SpecialDayCommand(IWardenService warden, return; } - var roundsToNext = sd.RoundsSinceLastSD - CvRoundsBetweenSD.Value; + var roundsToNext = sd.RoundsSinceLastSD - CV_ROUNDS_BETWEEN_SD.Value; if (roundsToNext < 0) { sdMsg.SpecialDayCooldown(Math.Abs(roundsToNext)).ToChat(executor); return; } - if (RoundUtil.GetTimeElapsed() > CvMaxElapsedTime.Value) { - sdMsg.TooLateForSpecialDay(CvMaxElapsedTime.Value); + if (RoundUtil.GetTimeElapsed() > CV_MAX_ELAPSED_TIME.Value) { + sdMsg.TooLateForSpecialDay(CV_MAX_ELAPSED_TIME.Value); return; } } @@ -77,8 +88,7 @@ public class SpecialDayCommand(IWardenService warden, return; } - MenuManager.OpenCenterHtmlMenu(plugin!, executor, - menuSelector!.GetMenu()); + MenuManager.OpenCenterHtmlMenu(plugin, executor, menuSelector.GetMenu()); return; } diff --git a/mod/Jailbreak.SpecialDay/SpecialDays/AbstractZoneRestrictedDay.cs b/mod/Jailbreak.SpecialDay/SpecialDays/AbstractZoneRestrictedDay.cs index 0b11d32..57d7ef0 100644 --- a/mod/Jailbreak.SpecialDay/SpecialDays/AbstractZoneRestrictedDay.cs +++ b/mod/Jailbreak.SpecialDay/SpecialDays/AbstractZoneRestrictedDay.cs @@ -11,7 +11,7 @@ using Jailbreak.Zones; namespace Jailbreak.SpecialDay.SpecialDays; public abstract class AbstractZoneRestrictedDay : AbstractSpecialDay { - protected readonly CsTeam RestrictedTeam; + protected CsTeam RestrictedTeam; protected readonly IList Restrictors = new List(); diff --git a/mod/Jailbreak.SpecialDay/SpecialDays/FFADay.cs b/mod/Jailbreak.SpecialDay/SpecialDays/FFADay.cs index 06135f7..e7e64cd 100644 --- a/mod/Jailbreak.SpecialDay/SpecialDays/FFADay.cs +++ b/mod/Jailbreak.SpecialDay/SpecialDays/FFADay.cs @@ -23,7 +23,6 @@ public class FFADay(BasePlugin plugin, IServiceProvider provider) base.Setup(); } - public override void Execute() { base.Execute(); Locale.BeginsIn(0).ToAllChat(); diff --git a/mod/Jailbreak.SpecialDay/SpecialDays/HideAndSeekDay.cs b/mod/Jailbreak.SpecialDay/SpecialDays/HideAndSeekDay.cs index 08f63d4..19f914f 100644 --- a/mod/Jailbreak.SpecialDay/SpecialDays/HideAndSeekDay.cs +++ b/mod/Jailbreak.SpecialDay/SpecialDays/HideAndSeekDay.cs @@ -1,4 +1,7 @@ -using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Cvars; +using CounterStrikeSharp.API.Modules.Cvars.Validators; using CounterStrikeSharp.API.Modules.Utils; using Jailbreak.English.SpecialDay; using Jailbreak.Formatting.Base; @@ -8,6 +11,7 @@ using Jailbreak.Public.Extensions; using Jailbreak.Public.Mod.SpecialDay; using Jailbreak.Public.Mod.SpecialDay.Enums; using Jailbreak.Public.Utils; +using Jailbreak.Validator; namespace Jailbreak.SpecialDay.SpecialDays; @@ -15,68 +19,161 @@ public class HideAndSeekDay(BasePlugin plugin, IServiceProvider provider) : AbstractArmoryRestrictedDay(plugin, provider), ISpecialDayMessageProvider { public override SDType Type => SDType.HNS; - private HNSDayLocale msg => (HNSDayLocale)Locale; - - public override SpecialDaySettings Settings => new HNSSettings(); - - public override IView ArmoryReminder => msg.StayInArmory; - + private HNSDayLocale Msg => (HNSDayLocale)Locale; + public override SpecialDaySettings Settings => new HnsSettings(); + public override IView ArmoryReminder => Msg.StayInArmory; public ISDInstanceLocale Locale => new HNSDayLocale(); + // Set to -1 to not modify values + public static readonly FakeConVar CV_PRISONER_PRE_HEALTH = new( + "jb_sd_hns_hide_hp_t", "Health to give to prisoners during HNS hide time", + 300, ConVarFlags.FCVAR_NONE, new NonZeroRangeValidator(-1, 1000)); + + public static readonly FakeConVar CV_GUARD_PRE_HEALTH = + new("jb_sd_hns_hide_hp_ct", "Health to give to guards during HNS hide time", + 150, ConVarFlags.FCVAR_NONE, new RangeValidator(-1, 1000)); + + public static readonly FakeConVar CV_PRISONER_PRE_ARMOR = new( + "jb_sd_hns_hide_armor_t", "Armor to give to prisoners during HNS hide time", + 200, ConVarFlags.FCVAR_NONE, new RangeValidator(-1, 1000)); + + public static readonly FakeConVar CV_GUARD_PRE_ARMOR = + new("jb_sd_hns_hide_armor_ct", + "Armor to give to guards during HNS hide time", 300, + ConVarFlags.FCVAR_NONE, new RangeValidator(-1, 1000)); + + public static readonly FakeConVar CV_PRISONER_POST_HEALTH = new( + "jb_sd_hns_seek_hp_t", "Health to give to prisoners during HNS seek time", + 300, ConVarFlags.FCVAR_NONE, new NonZeroRangeValidator(1, 1000)); + + public static readonly FakeConVar CV_GUARD_POST_HEALTH = new( + "jb_sd_hns_seek_hp_ct", "Health to give to guards during HNS seek time", 25, + ConVarFlags.FCVAR_NONE, new NonZeroRangeValidator(1, 1000)); + + public static readonly FakeConVar CV_PRISONER_POST_ARMOR = new( + "jb_sd_hns_seek_armor_t", "Armor to give to prisoners during HNS seek time", + 500, ConVarFlags.FCVAR_NONE, new RangeValidator(-1, 1000)); + + public static readonly FakeConVar CV_GUARD_POST_ARMOR = new( + "jb_sd_hns_seek_armor_ct", "Armor to give to guards during HNS seek time", + -1, ConVarFlags.FCVAR_NONE, new RangeValidator(-1, 1000)); + + public static readonly FakeConVar CV_GUARD_WEAPONS = new( + "jb_sd_hns_weapons_ct", + "List of weapons/items CTs may use, empty for no restrictions", + string.Join(",", Tag.PISTOLS.Union(Tag.UTILITY)), ConVarFlags.FCVAR_NONE, + new ItemValidator(allowMultiple: true)); + + public static readonly FakeConVar CV_PRISONER_WEAPONS = new( + "jb_sd_hns_weapons_t", + "List of weapons/items Ts may use, empty for no restrictions", "", + ConVarFlags.FCVAR_NONE, new ItemValidator(allowMultiple: true)); + + public static readonly FakeConVar CV_SEEKER_TEAM = + new("jb_sd_hns_seekers", "Team to assign as seekers and restrict to armory", + "t", ConVarFlags.FCVAR_NONE, new TeamValidator(false)); + + public static readonly FakeConVar CV_SEEK_TIME = + new("jb_sd_hns_seektime", + "Duration in seconds to give the hiders time to hide", 45, + ConVarFlags.FCVAR_NONE, new RangeValidator(5, 120)); + + private CsTeam? SeekerTeam => TeamUtil.FromString(CV_SEEKER_TEAM.Value); + + private CsTeam? HiderTeam + => (SeekerTeam ?? CsTeam.Terrorist) == CsTeam.Terrorist ? + CsTeam.CounterTerrorist : + CsTeam.Terrorist; + public override void Setup() { - Timers[10] += () => { - foreach (var ct in PlayerUtil.FromTeam(CsTeam.CounterTerrorist)) - ct.SetSpeed(1.5f); + if (SeekerTeam == null || HiderTeam == null) return; + RestrictedTeam = SeekerTeam.Value; - msg.DamageWarning(15).ToTeamChat(CsTeam.CounterTerrorist); + if (CV_SEEK_TIME.Value >= 10) + Timers[10] += () => { + foreach (var ct in PlayerUtil.FromTeam(SeekerTeam.Value)) + ct.SetSpeed(1.5f); - Locale.BeginsIn(35).ToAllChat(); - }; - Timers[25] += () => { - foreach (var ct in PlayerUtil.FromTeam(CsTeam.CounterTerrorist)) { - ct.SetSpeed(1.25f); - EnableDamage(ct); - } - }; - Timers[30] += () => { - foreach (var ct in PlayerUtil.FromTeam(CsTeam.CounterTerrorist)) - ct.SetSpeed(1.1f); - Locale.BeginsIn(15).ToAllChat(); - }; - Timers[45] += Execute; + Msg.DamageWarning(15).ToTeamChat(SeekerTeam.Value); + }; + if (CV_SEEK_TIME.Value >= 25) + Timers[25] += () => { + foreach (var player in PlayerUtil.FromTeam(SeekerTeam.Value)) { + player.SetSpeed(1.25f); + EnableDamage(player); + } + }; + + if (CV_SEEK_TIME.Value >= 30) + Timers[30] += () => { + foreach (var ct in PlayerUtil.FromTeam(SeekerTeam.Value)) + ct.SetSpeed(1.1f); + }; + + for (var offset = 15; offset < CV_SEEK_TIME.Value; offset += 15) { + var beginsIn = CV_SEEK_TIME.Value - offset; + Timers[CV_SEEK_TIME.Value - offset] += + () => Locale.BeginsIn(beginsIn).ToAllChat(); + } + + Timers[CV_SEEK_TIME.Value] += Execute; base.Setup(); - foreach (var ct in PlayerUtil.FromTeam(CsTeam.CounterTerrorist)) - ct.SetSpeed(2f); + foreach (var player in PlayerUtil.FromTeam(SeekerTeam.Value)) + player.SetSpeed(2f); } public override void Execute() { + if (SeekerTeam == null || HiderTeam == null) return; base.Execute(); - foreach (var t in PlayerUtil.FromTeam(CsTeam.Terrorist)) t.SetArmor(100); - foreach (var ct in PlayerUtil.FromTeam(CsTeam.CounterTerrorist)) - ct.SetSpeed(1); + foreach (var player in PlayerUtil.GetAlive()) { + var hp = (player.Team == CsTeam.Terrorist ? + CV_PRISONER_POST_HEALTH : + CV_GUARD_POST_HEALTH).Value; + + var armor = (player.Team == CsTeam.Terrorist ? + CV_PRISONER_POST_ARMOR : + CV_GUARD_POST_ARMOR).Value; + + if (hp != -1) player.SetHealth(hp); + if (armor != -1) player.SetArmor(armor); + } + + foreach (var ct in PlayerUtil.FromTeam(SeekerTeam.Value)) ct.SetSpeed(1); } - public class HNSSettings : SpecialDaySettings { - public HNSSettings() { + public class HnsSettings : SpecialDaySettings { + private readonly ISet? cachedGuardWeapons, cachedPrisonerWeapons; + + public HnsSettings() { AllowLastRequests = true; TTeleport = TeleportType.ARMORY; CtTeleport = TeleportType.ARMORY; + + cachedGuardWeapons = CV_GUARD_WEAPONS.Value.Split(",").ToHashSet(); + cachedPrisonerWeapons = CV_PRISONER_WEAPONS.Value.Split(",").ToHashSet(); + + if (cachedGuardWeapons.Count == 0) cachedGuardWeapons = null; + if (cachedPrisonerWeapons.Count == 0) cachedPrisonerWeapons = null; } public override int InitialHealth(CCSPlayerController player) { - return player.Team == CsTeam.Terrorist ? 250 : 50; + return player.Team == CsTeam.Terrorist ? + CV_PRISONER_PRE_HEALTH.Value : + CV_GUARD_PRE_HEALTH.Value; } public override int InitialArmor(CCSPlayerController player) { - if (player.Team != CsTeam.Terrorist) return -1; - return 500; + return player.Team == CsTeam.Terrorist ? + CV_PRISONER_PRE_ARMOR.Value : + CV_GUARD_PRE_ARMOR.Value; } public override ISet? AllowedWeapons(CCSPlayerController player) { - if (player.Team != CsTeam.CounterTerrorist) return null; - return Tag.PISTOLS.Union(Tag.UTILITY).ToHashSet(); + return player.Team == CsTeam.Terrorist ? + cachedPrisonerWeapons : + cachedGuardWeapons; } } } \ No newline at end of file diff --git a/mod/Jailbreak.SpecialDay/SpecialDays/InfectionDay.cs b/mod/Jailbreak.SpecialDay/SpecialDays/InfectionDay.cs index 6571445..9b5e567 100644 --- a/mod/Jailbreak.SpecialDay/SpecialDays/InfectionDay.cs +++ b/mod/Jailbreak.SpecialDay/SpecialDays/InfectionDay.cs @@ -12,13 +12,11 @@ using Jailbreak.Public.Utils; namespace Jailbreak.SpecialDay.SpecialDays; -public class InfectionDay : AbstractArmoryRestrictedDay, - ISpecialDayMessageProvider { +public class InfectionDay(BasePlugin plugin, IServiceProvider provider) + : AbstractArmoryRestrictedDay(plugin, provider, CsTeam.CounterTerrorist), + ISpecialDayMessageProvider { private readonly ICollection swappedPrisoners = new HashSet(); - public InfectionDay(BasePlugin Plugin, IServiceProvider provider) : base( - Plugin, provider, CsTeam.CounterTerrorist) { } - public override SDType Type => SDType.INFECTION; public override SpecialDaySettings Settings => new InfectionSettings(); @@ -40,12 +38,12 @@ public class InfectionDay : AbstractArmoryRestrictedDay, foreach (var ct in PlayerUtil.FromTeam(CsTeam.CounterTerrorist)) ct.SetColor(Color.LimeGreen); - Plugin.RegisterEventHandler(OnPlayerDeath); - Plugin.RegisterEventHandler(OnRespawn); + Plugin.RegisterEventHandler(onPlayerDeath); + Plugin.RegisterEventHandler(onRespawn); } private HookResult - OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) { + onPlayerDeath(EventPlayerDeath @event, GameEventInfo info) { var player = @event.Userid; if (player == null || !player.IsValid) return HookResult.Continue; if (player.Team != CsTeam.Terrorist) return HookResult.Continue; @@ -101,7 +99,7 @@ public class InfectionDay : AbstractArmoryRestrictedDay, return HookResult.Continue; } - public HookResult OnRespawn(EventPlayerSpawn @event, GameEventInfo info) { + private HookResult onRespawn(EventPlayerSpawn @event, GameEventInfo info) { var player = @event.Userid; if (player == null || !player.IsValid) return HookResult.Continue; if (player.Team != CsTeam.CounterTerrorist) return HookResult.Continue; @@ -119,13 +117,13 @@ public class InfectionDay : AbstractArmoryRestrictedDay, override protected HookResult OnEnd(EventRoundEnd @event, GameEventInfo info) { var result = base.OnEnd(@event, info); - Plugin.DeregisterEventHandler(OnPlayerDeath); - Plugin.DeregisterEventHandler(OnRespawn); + Plugin.DeregisterEventHandler(onPlayerDeath); + Plugin.DeregisterEventHandler(onRespawn); Plugin.AddTimer(0.1f, () => { foreach (var index in swappedPrisoners) { var player = Utilities.GetPlayerFromSlot(index); - if (player == null) continue; + if (player == null || !player.IsValid) continue; player.SwitchTeam(CsTeam.Terrorist); } }); diff --git a/mod/Jailbreak.SpecialDay/SpecialDays/NoScopeDay.cs b/mod/Jailbreak.SpecialDay/SpecialDays/NoScopeDay.cs index 484290e..0f1f34d 100644 --- a/mod/Jailbreak.SpecialDay/SpecialDays/NoScopeDay.cs +++ b/mod/Jailbreak.SpecialDay/SpecialDays/NoScopeDay.cs @@ -1,11 +1,14 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Cvars; +using CounterStrikeSharp.API.Modules.Cvars.Validators; using Jailbreak.English.SpecialDay; using Jailbreak.Formatting.Views.SpecialDay; using Jailbreak.Public.Extensions; using Jailbreak.Public.Mod.SpecialDay; using Jailbreak.Public.Mod.SpecialDay.Enums; using Jailbreak.Public.Utils; +using Jailbreak.Validator; namespace Jailbreak.SpecialDay.SpecialDays; @@ -19,18 +22,42 @@ public class NoScopeDay(BasePlugin plugin, IServiceProvider provider) public override SpecialDaySettings Settings => new NoScopeSettings(); + public static readonly FakeConVar CV_WEAPON = new( + "jb_sd_noscope_weapon", + "Weapon to give to all players, recommended it be a weapon with a scope (duh)", + "weapon_ssg08", ConVarFlags.FCVAR_NONE, + new ItemValidator(allowMultiple: true)); + + public static readonly FakeConVar CV_WEAPON_WHITELIST = new( + "jb_sd_noscope_allowedweapons", + "Weapons to allow players to use, empty for no restrictions", + string.Join(",", + Tag.UTILITY.Union(new[] { "weapon_ssg08", "weapon_knife" }.ToHashSet())), + ConVarFlags.FCVAR_NONE, new ItemValidator(allowMultiple: true)); + + public static readonly FakeConVar CV_KNIFE_DELAY = new( + "jb_sd_noscope_knife_delay", + "Time delay in seconds to give knives at, 0 to disable", 120, + ConVarFlags.FCVAR_NONE, new RangeValidator(0, 500)); + + public static readonly FakeConVar CV_GRAVITY = + new("jb_sd_noscope_gravity", + "Gravity to set during the special day, default is 800", 200f); + public override void Setup() { - Timers[120] += () => { - foreach (var player in PlayerUtil.GetAlive()) - player.GiveNamedItem("weapon_knife"); - }; + if (CV_KNIFE_DELAY.Value > 0) + Timers[CV_KNIFE_DELAY.Value] += () => { + foreach (var player in PlayerUtil.GetAlive()) + player.GiveNamedItem("weapon_knife"); + }; base.Setup(); } public override void Execute() { foreach (var player in PlayerUtil.GetAlive()) { player.RemoveWeapons(); - player.GiveNamedItem("weapon_ssg08"); + foreach (var weapon in CV_WEAPON.Value.Split(",")) + player.GiveNamedItem(weapon); } base.Execute(); @@ -50,8 +77,9 @@ public class NoScopeDay(BasePlugin plugin, IServiceProvider provider) if (activeWeapon == null || !activeWeapon.IsValid) return; activeWeapon.NextSecondaryAttackTick = Server.TickCount + 500; - if (activeWeapon.DesignerName is "weapon_ssg08" or "weapon_knife") return; - if (Tag.UTILITY.Contains(activeWeapon.DesignerName)) return; + if (CV_WEAPON_WHITELIST.Value.Contains(activeWeapon.DesignerName, + StringComparison.CurrentCultureIgnoreCase)) + return; activeWeapon.NextPrimaryAttackTick = Server.TickCount + 500; } @@ -61,7 +89,7 @@ public class NoScopeDay(BasePlugin plugin, IServiceProvider provider) TTeleport = TeleportType.RANDOM; RestrictWeapons = true; - ConVarValues["sv_gravity"] = (float)200; + ConVarValues["sv_gravity"] = CV_GRAVITY.Value; ConVarValues["sv_infinite_ammo"] = 2; } diff --git a/mod/Jailbreak.SpecialDay/SpecialDays/OneInTheChamberDay.cs b/mod/Jailbreak.SpecialDay/SpecialDays/OneInTheChamberDay.cs index 897a6a6..682ef3a 100644 --- a/mod/Jailbreak.SpecialDay/SpecialDays/OneInTheChamberDay.cs +++ b/mod/Jailbreak.SpecialDay/SpecialDays/OneInTheChamberDay.cs @@ -1,10 +1,13 @@ +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Cvars; using Jailbreak.English.SpecialDay; using Jailbreak.Formatting.Views.SpecialDay; using Jailbreak.Public.Extensions; using Jailbreak.Public.Mod.SpecialDay; using Jailbreak.Public.Mod.SpecialDay.Enums; using Jailbreak.Public.Utils; +using Jailbreak.Validator; namespace Jailbreak.SpecialDay.SpecialDays; @@ -18,6 +21,15 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider) public override SpecialDaySettings Settings => new OitcSettings(); + public static readonly FakeConVar CV_WEAPON = new("jb_sd_oitc_weapon", + "Weapon to give to players for the day", "weapon_deagle", + ConVarFlags.FCVAR_NONE, new ItemValidator(ItemValidator.WeaponType.GUNS)); + + public static readonly FakeConVar CV_ADDITIONAL_WEAPON = new( + "jb_sd_oitc_additionalweapon", + "Additional (non-ammo restricted) weapons to give for the day", + "weapon_knife", ConVarFlags.FCVAR_NONE, new ItemValidator()); + public override void Setup() { base.Setup(); Plugin.RegisterEventHandler(OnPlayerDamage); @@ -29,9 +41,12 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider) foreach (var player in PlayerUtil.GetAlive()) { player.RemoveWeapons(); - player.GiveNamedItem("weapon_knife"); - player.GiveNamedItem("weapon_deagle"); - player.GetWeaponBase("weapon_deagle")?.SetAmmo(1, 0); + if (CV_ADDITIONAL_WEAPON.Value.Length > 0) + player.GiveNamedItem(CV_ADDITIONAL_WEAPON.Value); + if (CV_WEAPON.Value.Length > 0) { + player.GiveNamedItem(CV_WEAPON.Value); + player.GetWeaponBase(CV_WEAPON.Value)?.SetAmmo(1, 0); + } } } @@ -46,7 +61,7 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider) private HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) { if (@event.Attacker == null) return HookResult.Continue; - @event.Attacker.GetWeaponBase("weapon_deagle")?.AddBulletsToMagazine(1); + @event.Attacker.GetWeaponBase(CV_WEAPON.Value)?.AddBulletsToMagazine(1); return HookResult.Continue; } @@ -56,19 +71,21 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider) Plugin.DeregisterEventHandler(OnPlayerDeath); return base.OnEnd(@event, info); } -} -public class OitcSettings : SpecialDaySettings { - public OitcSettings() { - CtTeleport = TeleportType.RANDOM; - TTeleport = TeleportType.RANDOM; - RestrictWeapons = true; - WithFriendlyFire(); + public class OitcSettings : SpecialDaySettings { + public OitcSettings() { + CtTeleport = TeleportType.RANDOM; + TTeleport = TeleportType.RANDOM; + RestrictWeapons = true; + WithFriendlyFire(); - ConVarValues["mp_death_drop_gun"] = 0; - } + ConVarValues["mp_death_drop_gun"] = 0; + } - public override ISet AllowedWeapons(CCSPlayerController player) { - return new HashSet { "weapon_deagle", "weapon_knife" }; + public override ISet AllowedWeapons(CCSPlayerController player) { + return new HashSet { + CV_WEAPON.Value, CV_ADDITIONAL_WEAPON.Value + }; + } } } \ No newline at end of file diff --git a/mod/Jailbreak.SpecialDay/SpecialDays/SpeedrunDay.cs b/mod/Jailbreak.SpecialDay/SpecialDays/SpeedrunDay.cs index 8afa173..fc77de8 100644 --- a/mod/Jailbreak.SpecialDay/SpecialDays/SpeedrunDay.cs +++ b/mod/Jailbreak.SpecialDay/SpecialDays/SpeedrunDay.cs @@ -26,56 +26,56 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) : AbstractSpecialDay(plugin, provider), ISpecialDayMessageProvider { private const int MAX_POINTS = 500; - public static readonly FakeConVar CvInitialSpeedrunTime = + public static readonly FakeConVar CV_INITIAL_SPEEDRUN_TIME = new("css_jb_speedrun_initial_time", "Duration in seconds to grant the speedrunner", 40); - public static readonly FakeConVar CvFirstRoundFreeze = + public static readonly FakeConVar CV_FIRST_ROUND_FREEZE = new("css_jb_speedrun_first_round_freeze", "Duration in seconds to give players time to read the rules of speedrun", 6); - public static readonly FakeConVar CvFreezeTime = + public static readonly FakeConVar CV_FREEZE_TIME = new("css_jb_speedrun_freeze_time", "Duration in seconds to freeze players before the speedrun starts", 2); - public static readonly FakeConVar CvWinTimeBase = + public static readonly FakeConVar CV_WIN_TIME_BASE = new("css_jb_speedrun_win_time_base", "Base duration in seconds to give the winner to kill other competitors", 25); - public static readonly FakeConVar CvWinTimeBonus = + public static readonly FakeConVar CV_WIN_TIME_BONUS = new("css_jb_speedrun_win_time_bonus", "Bonus duration in seconds to give the winner for every competitor", 5); - public static readonly FakeConVar CvWinTimeMax = + public static readonly FakeConVar CV_WIN_TIME_MAX = new("css_jb_speedrun_win_max", "Max time to give the winner regardless of bonus", 60); - public static readonly FakeConVar CvWinWeapon = new( + public static readonly FakeConVar CV_WIN_WEAPONS = new( "css_jb_speedrun_win_weapons", "Weapon(s) to give to the winner to kill other competitors", "weapon_knife,weapon_negev", - customValidators: new WeaponValidator(allowMultiple: true)); + customValidators: new ItemValidator(allowMultiple: true)); - public static readonly FakeConVar CvLosersWeapon = new( + public static readonly FakeConVar CV_LOSERS_WEAPONS = new( "css_jb_speedrun_loser_weapons", "Weapon(s) to give to the losers to use against the winner", "", - customValidators: new WeaponValidator(allowMultiple: true)); + customValidators: new ItemValidator(allowMultiple: true)); - public static readonly FakeConVar CvWinnerDamageable = new( + public static readonly FakeConVar CV_WINNER_DAMAGEABLE = new( "css_jb_speedrun_winner_damageable", "Whether the winner can be damaged"); - public static readonly FakeConVar CvLoserDamageable = new( + public static readonly FakeConVar CV_LOSER_DAMAGEABLE = new( "css_jb_speedrun_loser_damageable", "Whether the losers can be damaged", true); - public static readonly FakeConVar CvTeleportType = + public static readonly FakeConVar CV_TELEPORT_TYPE = new("css_jb_speedrun_teleport_type", "0 = Dont teleport at end, 1 = Teleport losers to winner, 2 = Teleport winner to loser(s)", 2); - public static readonly FakeConVar CvMaxPlayersToFinish = new( + public static readonly FakeConVar CV_MAX_PLAYERS_TO_FINISH = new( "css_jb_speedrun_finish_at", "Number of players required to declare a winner", 2, customValidators: new RangeValidator(2, 10)); @@ -88,7 +88,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) /// Positive values represent players who are still alive, and the value /// being the distance they are from the target. /// - private readonly HashSet finishedPlayers = new(); + private readonly HashSet finishedPlayers = []; private readonly Random rng = new(); private float? bestTime; @@ -96,7 +96,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) private AbstractTrail? bestTrail; - private LinkedList<(int, float)> finishTimestampList = new(); + private LinkedList<(int, float)> finishTimestampList = []; private IGenericCmdLocale generics = null!; private int round, playersAliveAtStart; @@ -107,9 +107,9 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) private Vector? start; private Vector? target; private BeamCircle? targetCircle; - private ISpeedDayLocale msg => (ISpeedDayLocale)Locale; + private ISpeedDayLocale Msg => (ISpeedDayLocale)Locale; - private bool isRoundActive + private bool IsRoundActive => Provider.GetRequiredService().CurrentSD == this; public override SDType Type => SDType.SPEEDRUN; @@ -144,7 +144,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) player.SetColor(Color.FromArgb(100, 255, 255, 255)); } }; - Timers[CvFirstRoundFreeze.Value - 4] += () => { + Timers[CV_FIRST_ROUND_FREEZE.Value - 4] += () => { if (!speedrunner.IsValid || speedrunner.Connected != PlayerConnectedState.PlayerConnected) speedrunner = getRunner(); @@ -153,11 +153,11 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) return; } - msg.RunnerAssigned(speedrunner).ToAllChat(); + Msg.RunnerAssigned(speedrunner).ToAllChat(); speedrunner.SetColor(Color.DodgerBlue); - msg.YouAreRunner(CvInitialSpeedrunTime.Value).ToChat(speedrunner); + Msg.YouAreRunner(CV_INITIAL_SPEEDRUN_TIME.Value).ToChat(speedrunner); }; - Timers[CvFirstRoundFreeze.Value] += () => { + Timers[CV_FIRST_ROUND_FREEZE.Value] += () => { if (!speedrunner.IsValid || speedrunner.Connected != PlayerConnectedState.PlayerConnected) { speedrunner = getRunner(); @@ -168,8 +168,8 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) } speedrunner.SetColor(Color.DodgerBlue); - msg.RunnerLeftAndReassigned(speedrunner).ToAllChat(); - msg.YouAreRunner(CvInitialSpeedrunTime.Value).ToChat(speedrunner); + Msg.RunnerLeftAndReassigned(speedrunner).ToAllChat(); + Msg.YouAreRunner(CV_INITIAL_SPEEDRUN_TIME.Value).ToChat(speedrunner); } start = speedrunner.PlayerPawn.Value!.AbsOrigin!.Clone(); @@ -177,8 +177,9 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) bestTrail = createFirstTrail(speedrunner); }; - if (CvInitialSpeedrunTime.Value > 30) - Timers[CvInitialSpeedrunTime.Value + CvFirstRoundFreeze.Value - 30] += () + if (CV_INITIAL_SPEEDRUN_TIME.Value > 30) + Timers[ + CV_INITIAL_SPEEDRUN_TIME.Value + CV_FIRST_ROUND_FREEZE.Value - 30] += () => { if (target != null) return; if (!speedrunner.IsValid || speedrunner.Connected @@ -190,15 +191,16 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) return; } - msg.RuntimeLeft(RoundUtil.GetTimeRemaining()).ToChat(speedrunner); + Msg.RuntimeLeft(RoundUtil.GetTimeRemaining()).ToChat(speedrunner); }; - Timers[CvInitialSpeedrunTime.Value + CvFirstRoundFreeze.Value - 10] += () - => { - if (target != null) return; - msg.RuntimeLeft(RoundUtil.GetTimeRemaining()).ToChat(speedrunner); - }; - Timers[CvInitialSpeedrunTime.Value + CvFirstRoundFreeze.Value] += Execute; + Timers[CV_INITIAL_SPEEDRUN_TIME.Value + CV_FIRST_ROUND_FREEZE.Value - 10] += + () => { + if (target != null) return; + Msg.RuntimeLeft(RoundUtil.GetTimeRemaining()).ToChat(speedrunner); + }; + Timers[CV_INITIAL_SPEEDRUN_TIME.Value + CV_FIRST_ROUND_FREEZE.Value] += + Execute; base.Setup(); } @@ -234,7 +236,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) bestTime = timeSpent; - var minTime = CvInitialSpeedrunTime.Value * 0.5; + var minTime = CV_INITIAL_SPEEDRUN_TIME.Value * 0.5; startRound((int)Math.Ceiling(Math.Max(timeSpent * 1.1, minTime))); @@ -290,8 +292,8 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) furthest.Pawn.Value?.Teleport(end); furthest.SetColor(Color.DodgerBlue); - msg.RunnerAFKAndReassigned(furthest).ToAllChat(); - msg.YouAreRunner(RoundUtil.GetTimeRemaining()).ToChat(furthest); + Msg.RunnerAFKAndReassigned(furthest).ToAllChat(); + Msg.YouAreRunner(RoundUtil.GetTimeRemaining()).ToChat(furthest); trail.StartTracking(furthest); trail.DidntMoveTicks = 0; return; @@ -299,7 +301,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) if (trail.DidntMoveTicks < thresholdTicks) return; if (trail.DidntMoveTicks == thresholdTicks) - msg.StayStillToSpeedup.ToChat(trail.Player); + Msg.StayStillToSpeedup.ToChat(trail.Player); if (didntMoveSeconds % 2 == 0) RoundUtil.AddTimeRemaining(-1); if (RoundUtil.GetTimeRemaining() <= 0) Execute(); }; @@ -327,8 +329,8 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) speedrunner = nearest; nearest.Pawn.Value?.Teleport(end); nearest.SetColor(Color.DodgerBlue); - msg.RunnerLeftAndReassigned(nearest).ToAllChat(); - msg.YouAreRunner(RoundUtil.GetTimeRemaining()).ToChat(nearest); + Msg.RunnerLeftAndReassigned(nearest).ToAllChat(); + Msg.YouAreRunner(RoundUtil.GetTimeRemaining()).ToChat(nearest); trail.StartTracking(nearest); }; return trail; @@ -344,17 +346,17 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) private void startRound(int seconds) { roundStartTime = null; - if (!isRoundActive) { + if (!IsRoundActive) { panic("Round is not active but we are in startRound"); return; } var alive = PlayerUtil.GetAlive().ToArray(); playersAliveAtStart = PlayerUtil.GetAlive().Count(); - msg.BeginRound(++round, getEliminations(playersAliveAtStart), seconds) + Msg.BeginRound(++round, getEliminations(playersAliveAtStart), seconds) .ToAllChat(); - RoundUtil.SetTimeRemaining(seconds + CvFreezeTime.Value); + RoundUtil.SetTimeRemaining(seconds + CV_FREEZE_TIME.Value); foreach (var player in alive) { var pawn = player.PlayerPawn.Value; @@ -367,19 +369,19 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) finishedPlayers.Clear(); finishTimestampList.Clear(); - Plugin.AddTimer(CvFreezeTime.Value, () => { - if (!isRoundActive) return; + Plugin.AddTimer(CV_FREEZE_TIME.Value, () => { + if (!IsRoundActive) return; foreach (var player in PlayerUtil.GetAlive()) player.UnFreeze(); roundStartTime = Server.CurrentTime; }, TimerFlags.STOP_ON_MAPCHANGE); - roundEndTimer = Plugin.AddTimer(seconds + CvFreezeTime.Value, endRound, + roundEndTimer = Plugin.AddTimer(seconds + CV_FREEZE_TIME.Value, endRound, TimerFlags.STOP_ON_MAPCHANGE); } private void checkFinishers() { if (target == null || roundStartTime == null) return; - if (!isRoundActive) { + if (!IsRoundActive) { panic("Round is not active but we are in checkFinishers"); return; } @@ -432,9 +434,9 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) foreach (var (slot, dist) in unfinished) finishTimestampList.AddLast((slot, dist)); - const int TOTAL_LINES = 8; - var pos = 1; - var current = finishTimestampList.First; + const int totalLines = 8; + var pos = 1; + var current = finishTimestampList.First; string? top = null; while (current != null) { @@ -451,14 +453,14 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) var playerLine = current; var d = 0; - while (playerLine != null && (display < TOTAL_LINES / 2 - || pos - d > finishTimestampList.Count - TOTAL_LINES - && display < TOTAL_LINES)) { + while (playerLine != null && (display < totalLines / 2 + || pos - d > finishTimestampList.Count - totalLines + && display < totalLines)) { var (slot, dist) = playerLine.Value; playerLine = playerLine.Previous; var p = Utilities.GetPlayerFromSlot(slot); if (p == null) continue; - lines = generateHTMLLine(p, pos - d++, dist) + (d == 1 ? "" : "
") + lines = generateHtmlLine(p, pos - d++, dist) + (d == 1 ? "" : "
") + lines; display++; } @@ -467,12 +469,12 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) playerLine = current; d = 0; - while (playerLine != null && display < TOTAL_LINES) { + while (playerLine != null && display < totalLines) { var (slot, dist) = playerLine.Value; playerLine = playerLine.Next; var p = Utilities.GetPlayerFromSlot(slot); if (p == null) continue; - lines += "
" + generateHTMLLine(p, pos + ++d, dist); + lines += "
" + generateHtmlLine(p, pos + ++d, dist); display++; } @@ -488,7 +490,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) finishTimestampList = originalCompletions; } - private string generateHTMLLine(CCSPlayerController player, int position, + private string generateHtmlLine(CCSPlayerController player, int position, float distance) { string color; var eliminations = getEliminations(playersAliveAtStart); @@ -541,10 +543,10 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) if (bestTime == null || time < bestTime) { bestTime = time; bestTimePlayerSlot = player.Slot; - msg.BestTime(player, time).ToAllChat(); + Msg.BestTime(player, time).ToAllChat(); player.SetColor(Color.FromArgb(255, Color.Gold)); } else { - msg.PlayerTime(player, finishedPlayers.Count + 1, -time).ToAllChat(); + Msg.PlayerTime(player, finishedPlayers.Count + 1, -time).ToAllChat(); } finishTimestampList.AddLast((player.Slot, -Server.CurrentTime)); @@ -605,7 +607,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) return; } - if (!isRoundActive) { + if (!IsRoundActive) { panic("Round is not active but we are in endRound"); return; } @@ -642,7 +644,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) if (random != null && activeTrails.TryGetValue(random.Slot, out var randomTrail)) { - msg.ImpossibleLocation( + Msg.ImpossibleLocation( ctMade ? CsTeam.Terrorist : CsTeam.CounterTerrorist, random); bestTrail?.Kill(); @@ -657,7 +659,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) announceTimes(); - if (aliveCount <= CvMaxPlayersToFinish.Value) { + if (aliveCount <= CV_MAX_PLAYERS_TO_FINISH.Value) { if (finishTimestampList.Count == 0) { generics.Error("No slowest times found").ToAllChat(); return; @@ -678,29 +680,30 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) .Where(p => p.Slot != winner.Slot) .ToList(); - var timeToSet = CvWinTimeBase.Value + CvWinTimeBonus.Value * losers.Count; + var timeToSet = CV_WIN_TIME_BASE.Value + + CV_WIN_TIME_BONUS.Value * losers.Count; - msg.PlayerWon(winner).ToAllChat(); + Msg.PlayerWon(winner).ToAllChat(); foreach (var loser in losers) { loser.SetColor(Color.FromArgb(254, Color.White)); - if (CvTeleportType.Value == 1) + if (CV_TELEPORT_TYPE.Value == 1) loser.Teleport(winner); - else if (CvTeleportType.Value == 2) winner.Teleport(loser); - if (CvLoserDamageable.Value) EnableDamage(loser); + else if (CV_TELEPORT_TYPE.Value == 2) winner.Teleport(loser); + if (CV_LOSER_DAMAGEABLE.Value) EnableDamage(loser); } - if (CvWinnerDamageable.Value) EnableDamage(winner); + if (CV_WINNER_DAMAGEABLE.Value) EnableDamage(winner); - foreach (var weapon in CvLosersWeapon.Value.Split(',')) + foreach (var weapon in CV_LOSERS_WEAPONS.Value.Split(',')) foreach (var loser in losers) loser.GiveNamedItem(weapon); - foreach (var weapon in CvWinWeapon.Value.Split(',')) + foreach (var weapon in CV_WIN_WEAPONS.Value.Split(',')) winner.GiveNamedItem(weapon); Plugin.RemoveListener(checkFinishers); - RoundUtil.SetTimeRemaining(Math.Min(timeToSet, CvWinTimeMax.Value)); + RoundUtil.SetTimeRemaining(Math.Min(timeToSet, CV_WIN_TIME_MAX.Value)); Server.ExecuteCommand("mp_ignore_round_win_conditions 0"); return; } @@ -709,7 +712,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) var nextRoundTime = (int)Math.Ceiling((bestTime ?? 20) + 10 - round * 1.5); if (toEliminate <= 0) { - msg.NoneEliminated.ToAllChat(); + Msg.NoneEliminated.ToAllChat(); Plugin.AddTimer(3f, () => { startRound(nextRoundTime); }, TimerFlags.STOP_ON_MAPCHANGE); return; @@ -750,7 +753,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) if (player == null || !player.IsValid) continue; EnableDamage(player); player.CommitSuicide(false, true); - msg.PlayerEliminated(player).ToAllChat(); + Msg.PlayerEliminated(player).ToAllChat(); } Plugin.AddTimer(3f, () => { startRound(nextRoundTime); }, @@ -760,7 +763,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) private void eliminatePlayer(CCSPlayerController player) { EnableDamage(player); player.CommitSuicide(false, true); - msg.PlayerEliminated(player).ToAllChat(); + Msg.PlayerEliminated(player).ToAllChat(); } private void panic(string reason) { @@ -794,7 +797,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) var player = Utilities.GetPlayerFromSlot(slot); slowest = slowest.Previous; if (player == null) continue; - msg.PlayerTime(player, position--, dist).ToChat(player); + Msg.PlayerTime(player, position--, dist).ToChat(player); } } @@ -825,7 +828,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) } public override Func RoundTime - => () => CvInitialSpeedrunTime.Value + CvFirstRoundFreeze.Value; + => () => CV_INITIAL_SPEEDRUN_TIME.Value + CV_FIRST_ROUND_FREEZE.Value; public override ISet AllowedWeapons(CCSPlayerController player) { // Return empty set to allow no weapons @@ -833,7 +836,7 @@ public class SpeedrunDay(BasePlugin plugin, IServiceProvider provider) } public override float FreezeTime(CCSPlayerController player) { - return CvFirstRoundFreeze.Value; + return CV_FIRST_ROUND_FREEZE.Value; } } } \ No newline at end of file diff --git a/mod/Jailbreak.Warden/Commands/WardenCommandsBehavior.cs b/mod/Jailbreak.Warden/Commands/WardenCommandsBehavior.cs index b0abd2d..e3cc2be 100644 --- a/mod/Jailbreak.Warden/Commands/WardenCommandsBehavior.cs +++ b/mod/Jailbreak.Warden/Commands/WardenCommandsBehavior.cs @@ -10,12 +10,13 @@ using Jailbreak.Formatting.Views.Warden; using Jailbreak.Public.Behaviors; using Jailbreak.Public.Mod.Warden; using Jailbreak.Public.Utils; +using Jailbreak.Warden.Global; namespace Jailbreak.Warden.Commands; public class WardenCommandsBehavior(IWardenLocale locale, IWardenSelectionService queue, IWardenService warden, - IGenericCmdLocale generics, WardenConfig config) : IPluginBehavior { + IGenericCmdLocale generics) : IPluginBehavior { private readonly Dictionary lastPassCommand = new(); @@ -39,7 +40,7 @@ public class WardenCommandsBehavior(IWardenLocale locale, // GetPlayers() returns valid players, no need to error check here. foreach (var clients in Utilities.GetPlayers()) clients.ExecuteClientCommand( - $"play sounds/{config.WardenPassedSoundName}"); + $"play sounds/{WardenBehavior.CV_WARDEN_SOUND_PASSED.Value}"); locale.BecomeNextWarden.ToAllChat(); @@ -71,7 +72,7 @@ public class WardenCommandsBehavior(IWardenLocale locale, locale.FireWarden(warden.Warden).ToChat(client); client.ExecuteClientCommand( - $"play sounds/{config.WardenPassedSoundName}"); + $"play sounds/{WardenBehavior.CV_WARDEN_SOUND_PASSED.Value}"); } locale.BecomeNextWarden.ToAllChat(); diff --git a/mod/Jailbreak.Warden/Commands/WardenOpenCommandsBehavior.cs b/mod/Jailbreak.Warden/Commands/WardenOpenCommandsBehavior.cs index 5d9b050..b7d815f 100644 --- a/mod/Jailbreak.Warden/Commands/WardenOpenCommandsBehavior.cs +++ b/mod/Jailbreak.Warden/Commands/WardenOpenCommandsBehavior.cs @@ -17,7 +17,7 @@ namespace Jailbreak.Warden.Commands; public class WardenOpenCommandsBehavior(IWardenService warden, IWardenLocale msg, IWardenCmdOpenLocale wardenCmdOpenMsg, IZoneManager zoneManager) : IPluginBehavior, IWardenOpenCommand { - public static readonly FakeConVar CvOpenCommandCooldown = new( + public static readonly FakeConVar CV_OPEN_COMMAND_COOLDOWN = new( "css_jb_warden_open_cooldown", "Minimum seconds warden must wait before being able to open the cells.", 30, customValidators: new RangeValidator(0, 300)); @@ -40,8 +40,8 @@ public class WardenOpenCommandsBehavior(IWardenService warden, return; } - if (RoundUtil.GetTimeElapsed() < CvOpenCommandCooldown.Value) { - wardenCmdOpenMsg.CannotOpenYet(CvOpenCommandCooldown.Value) + if (RoundUtil.GetTimeElapsed() < CV_OPEN_COMMAND_COOLDOWN.Value) { + wardenCmdOpenMsg.CannotOpenYet(CV_OPEN_COMMAND_COOLDOWN.Value) .ToChat(executor); return; } @@ -56,9 +56,10 @@ public class WardenOpenCommandsBehavior(IWardenService warden, var result = MapUtil.OpenCells(zoneManager); IView message; if (result) { - if (executor != null && !warden.IsWarden(executor)) { + if (executor != null && !warden.IsWarden(executor)) message = wardenCmdOpenMsg.CellsOpenedBy(executor); - } else { message = wardenCmdOpenMsg.CellsOpenedBy(null); } + else + message = wardenCmdOpenMsg.CellsOpenedBy(null); } else { message = wardenCmdOpenMsg.OpeningFailed; } message.ToAllChat(); diff --git a/mod/Jailbreak.Warden/Global/WardenBehavior.cs b/mod/Jailbreak.Warden/Global/WardenBehavior.cs index bc19e38..2b3b3a7 100644 --- a/mod/Jailbreak.Warden/Global/WardenBehavior.cs +++ b/mod/Jailbreak.Warden/Global/WardenBehavior.cs @@ -36,39 +36,54 @@ public struct PreWardenStats(int armorValue, int health, int maxHealth, public class WardenBehavior(ILogger logger, IWardenLocale locale, IRichLogService logs, ISpecialTreatmentService specialTreatment, IRebelService rebels, - WardenConfig config, IMuteService mute, IServiceProvider provider) + IMuteService mute, IServiceProvider provider) : IPluginBehavior, IWardenService { private readonly ISet bluePrisoners = new HashSet(); - public readonly FakeConVar CvArmorEqual = new("css_jb_hp_outnumbered", - "Health points for CTs have equal balance", 50, ConVarFlags.FCVAR_NONE, - new RangeValidator(1, 200)); + public static readonly FakeConVar CV_ARMOR_EQUAL = + new("css_jb_hp_outnumbered", "Health points for CTs have equal balance", 50, + ConVarFlags.FCVAR_NONE, new RangeValidator(1, 200)); - public readonly FakeConVar CvArmorOutnumber = new("css_jb_hp_outnumber", - "HP for CTs when outnumbering Ts", 25, ConVarFlags.FCVAR_NONE, - new RangeValidator(1, 200)); + public static readonly FakeConVar CV_ARMOR_OUTNUMBER = + new("css_jb_hp_outnumber", "HP for CTs when outnumbering Ts", 25, + ConVarFlags.FCVAR_NONE, new RangeValidator(1, 200)); - public readonly FakeConVar CvArmorOutnumbered = + public static readonly FakeConVar CV_ARMOR_OUTNUMBERED = new("css_jb_hp_outnumbered", "Health points for CTs when outnumbered by Ts", 100, ConVarFlags.FCVAR_NONE, new RangeValidator(1, 200)); - public readonly FakeConVar CvWardenArmor = new("css_jb_warden_armor", - "Armor for the warden", 125, ConVarFlags.FCVAR_NONE, - new RangeValidator(1, 200)); + public static readonly FakeConVar CV_WARDEN_ARMOR = + new("css_jb_warden_armor", "Armor for the warden", 125, + ConVarFlags.FCVAR_NONE, new RangeValidator(1, 200)); - public readonly FakeConVar CvWardenHealth = new("css_jb_warden_hp", - "HP for the warden", 125, ConVarFlags.FCVAR_NONE, - new RangeValidator(1, 200)); - - public readonly FakeConVar CvWardenMaxHealth = new("css_jb_warden_maxhp", - "Max HP for the warden", 100, ConVarFlags.FCVAR_NONE, - new RangeValidator(1, 200)); - - public readonly FakeConVar CvWardenAutoOpenCells = + public static readonly FakeConVar CV_WARDEN_AUTO_OPEN_CELLS = new("css_jb_warden_opencells_delay", "Delay in seconds to auto-open cells at, -1 to disable", 60); + public static readonly FakeConVar CV_WARDEN_HEALTH = + new("css_jb_warden_hp", "HP for the warden", 125, ConVarFlags.FCVAR_NONE, + new RangeValidator(1, 200)); + + public static readonly FakeConVar CV_WARDEN_MAX_HEALTH = + new("css_jb_warden_maxhp", "Max HP for the warden", 100, + ConVarFlags.FCVAR_NONE, new RangeValidator(1, 200)); + + public static readonly FakeConVar CV_WARDEN_SOUND_KILLED = + new("css_jb_warden_sound_killed", "Sound to play when the warden is killed", + "wardenKilled"); + + public static readonly FakeConVar CV_WARDEN_SOUND_PASSED = + new("css_jb_warden_sound_killed", "Sound to play when the warden passes", + "wardenPassed"); + + public static readonly FakeConVar CV_WARDEN_SOUND_NEW = + new("css_jb_warden_sound_killed", + "Sound to play when the warden is assigned", "wardenNew"); + + public static readonly FakeConVar CV_WARDEN_TERRORIST_RATIO = + new("css_jb_warden_t_ratio", "Ratio of T:CT to use for HP adjustments", 3); + private bool firstWarden; private string? oldTag; private char? oldTagColor; @@ -133,7 +148,7 @@ public class WardenBehavior(ILogger logger, } foreach (var player in Utilities.GetPlayers()) - player.ExecuteClientCommand($"play sounds/{config.WardenNewSoundName}"); + player.ExecuteClientCommand($"play sounds/{CV_WARDEN_SOUND_NEW.Value}"); logs.Append(logs.Player(Warden), "is now the warden."); @@ -157,10 +172,10 @@ public class WardenBehavior(ILogger logger, if (!hasHelmet) Warden.GiveNamedItem("item_assaultsuit"); var ctArmorValue = getBalance() switch { - 0 => CvArmorEqual.Value, // Balanced teams - 1 => CvArmorOutnumbered.Value, // Ts outnumber CTs - -1 => CvArmorOutnumber.Value, // CTs outnumber Ts - _ => CvArmorEqual.Value // default (should never happen) + 0 => CV_ARMOR_EQUAL.Value, // Balanced teams + 1 => CV_ARMOR_OUTNUMBERED.Value, // Ts outnumber CTs + -1 => CV_ARMOR_OUTNUMBER.Value, // CTs outnumber Ts + _ => CV_ARMOR_EQUAL.Value // default (should never happen) }; /* Round start CT buff */ @@ -173,8 +188,8 @@ public class WardenBehavior(ILogger logger, Utilities.SetStateChanged(guardPawn, "CCSPlayerPawn", "m_ArmorValue"); } - setWardenStats(wardenPawn, CvWardenArmor.Value, CvWardenHealth.Value, - CvWardenMaxHealth.Value); + setWardenStats(wardenPawn, CV_WARDEN_ARMOR.Value, CV_WARDEN_HEALTH.Value, + CV_WARDEN_MAX_HEALTH.Value); if (!hasHealthshot) Warden.GiveNamedItem("weapon_healthshot"); } else { preWardenStats = null; } @@ -282,7 +297,7 @@ public class WardenBehavior(ILogger logger, foreach (var player in Utilities.GetPlayers()) { if (!player.IsReal()) continue; player.ExecuteClientCommand( - $"play sounds/{config.WardenKilledSoundName}"); + $"play sounds/{CV_WARDEN_SOUND_KILLED.Value}"); } locale.BecomeNextWarden.ToAllChat(); @@ -333,7 +348,7 @@ public class WardenBehavior(ILogger logger, var tCount = Utilities.GetPlayers().Count(p => p.Team == CsTeam.Terrorist); // Casting to a float ensures if we're diving by zero, we get infinity instead of an error. - var ratio = (float)tCount / config.TerroristRatio - ctCount; + var ratio = (float)tCount / CV_WARDEN_TERRORIST_RATIO.Value - ctCount; return ratio switch { > 0 => 1, @@ -403,14 +418,14 @@ public class WardenBehavior(ILogger logger, firstWarden = true; preWardenStats = null; - if (CvWardenAutoOpenCells.Value < 0 || RoundUtil.IsWarmup()) + if (CV_WARDEN_AUTO_OPEN_CELLS.Value < 0 || RoundUtil.IsWarmup()) return HookResult.Continue; var openCmd = provider.GetService(); if (openCmd == null) return HookResult.Continue; var cmdLocale = provider.GetRequiredService(); openCellsTimer?.Kill(); - openCellsTimer = parent.AddTimer(CvWardenAutoOpenCells.Value, () => { + openCellsTimer = parent.AddTimer(CV_WARDEN_AUTO_OPEN_CELLS.Value, () => { if (openCmd.OpenedCells) return; var zone = provider.GetService(); if (zone != null) @@ -436,7 +451,7 @@ public class WardenBehavior(ILogger logger, foreach (var player in Utilities.GetPlayers()) player.ExecuteClientCommand( - $"play sounds/{config.WardenPassedSoundName}"); + $"play sounds/{CV_WARDEN_SOUND_PASSED.Value}"); locale.BecomeNextWarden.ToAllChat(); return HookResult.Continue; diff --git a/mod/Jailbreak.Warden/Markers/WardenMarkerBehavior.cs b/mod/Jailbreak.Warden/Markers/WardenMarkerBehavior.cs index 2f46dda..7bc03ce 100644 --- a/mod/Jailbreak.Warden/Markers/WardenMarkerBehavior.cs +++ b/mod/Jailbreak.Warden/Markers/WardenMarkerBehavior.cs @@ -13,13 +13,13 @@ using MStatsShared; namespace Jailbreak.Warden.Markers; public class WardenMarkerBehavior(IWardenService warden) : IPluginBehavior { - public readonly FakeConVar CvMaxRadius = new( + public static readonly FakeConVar CV_MAX_RADIUS = new( "css_jb_warden_marker_max_radius", "Maximum radius for warden marker", 360); - public readonly FakeConVar CvMinRadius = new( + public static readonly FakeConVar CV_MIN_RADIUS = new( "css_jb_warden_marker_min_radius", "Minimum radius for warden marker", 60); - public readonly FakeConVar CvResizeTime = new( + public static readonly FakeConVar CV_RESIZE_TIME = new( "css_jb_warden_resize_time", "Milliseconds to wait for resizing marker", 800); @@ -30,7 +30,7 @@ public class WardenMarkerBehavior(IWardenService warden) : IPluginBehavior { private float radius; public void Start(BasePlugin basePlugin) { - marker = new BeamCircle(basePlugin, new Vector(), CvMinRadius.Value, + marker = new BeamCircle(basePlugin, new Vector(), CV_MIN_RADIUS.Value, (int)Math.PI * 15); basePlugin.AddCommandListener("player_ping", CommandListener_PlayerPing); } @@ -46,9 +46,9 @@ public class WardenMarkerBehavior(IWardenService warden) : IPluginBehavior { var distance = currentPos.Distance(vec); var timeElapsed = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - placementTime; - if (timeElapsed < CvResizeTime.Value) { - if (distance <= CvMaxRadius.Value * 1.3) { - distance = Math.Clamp(distance, CvMinRadius.Value, CvMaxRadius.Value); + if (timeElapsed < CV_RESIZE_TIME.Value) { + if (distance <= CV_MAX_RADIUS.Value * 1.3) { + distance = Math.Clamp(distance, CV_MIN_RADIUS.Value, CV_MAX_RADIUS.Value); marker?.SetRadius(distance); marker?.Update(); radius = distance; @@ -60,7 +60,7 @@ public class WardenMarkerBehavior(IWardenService warden) : IPluginBehavior { } } - radius = CvMinRadius.Value; + radius = CV_MIN_RADIUS.Value; currentPos = vec; placementTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); diff --git a/mod/Jailbreak.Warden/WardenConfig.cs b/mod/Jailbreak.Warden/WardenConfig.cs deleted file mode 100644 index ee680fd..0000000 --- a/mod/Jailbreak.Warden/WardenConfig.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Jailbreak.Warden; - -public class WardenConfig { - public string WardenKilledSoundName { get; } = "wardenKilled"; - public string WardenPassedSoundName { get; } = "wardenPassed"; - public string WardenNewSoundName { get; } = "wardenNew"; - public int TerroristRatio { get; } = 3; -} \ No newline at end of file diff --git a/mod/Jailbreak.Warden/WardenServiceExtension.cs b/mod/Jailbreak.Warden/WardenServiceExtension.cs index 5f6fb1f..07390ef 100644 --- a/mod/Jailbreak.Warden/WardenServiceExtension.cs +++ b/mod/Jailbreak.Warden/WardenServiceExtension.cs @@ -13,13 +13,13 @@ namespace Jailbreak.Warden; public static class WardenServiceExtension { public static void AddJailbreakWarden( this IServiceCollection serviceCollection) { - serviceCollection.AddConfig("warden"); serviceCollection.AddPluginBehavior(); serviceCollection .AddPluginBehavior(); serviceCollection .AddPluginBehavior(); - serviceCollection.AddPluginBehavior(); + serviceCollection + .AddPluginBehavior(); serviceCollection.AddPluginBehavior(); serviceCollection.AddPluginBehavior(); diff --git a/mod/Jailbreak.Zones/SqlZoneManager.cs b/mod/Jailbreak.Zones/SqlZoneManager.cs index 0815cfe..21fbddc 100644 --- a/mod/Jailbreak.Zones/SqlZoneManager.cs +++ b/mod/Jailbreak.Zones/SqlZoneManager.cs @@ -8,10 +8,10 @@ using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; namespace Jailbreak.Zones; public class SqlZoneManager(IZoneFactory factory) : IZoneManager { - public static readonly FakeConVar CvSqlTable = new("css_jb_zonetable", + public static readonly FakeConVar CV_SQL_TABLE = new("css_jb_zonetable", "The table name for the zones", "cs2_jb_zones"); - public static readonly FakeConVar CvSqlConnectionString = + public static readonly FakeConVar CV_SQL_CONNECTION_STRING = new("css_jb_sqlconnection", "The connection string for the database", "", ConVarFlags.FCVAR_PROTECTED); @@ -22,7 +22,7 @@ public class SqlZoneManager(IZoneFactory factory) : IZoneManager { public void Start(BasePlugin basePlugin) { plugin = basePlugin; - CvSqlConnectionString.ValueChanged += async (_, _) => { + CV_SQL_CONNECTION_STRING.ValueChanged += async (_, _) => { await LoadZones(Server.MapName); }; @@ -56,7 +56,7 @@ public class SqlZoneManager(IZoneFactory factory) : IZoneManager { await conn.OpenAsync(); await using var cmd = conn.CreateCommand(); cmd.CommandText = $""" - DELETE FROM {CvSqlTable.Value.Trim('"')} + DELETE FROM {CV_SQL_TABLE.Value.Trim('"')} WHERE zoneid = @zoneid AND map = @map """; @@ -91,7 +91,7 @@ public class SqlZoneManager(IZoneFactory factory) : IZoneManager { await conn.OpenAsync(); var insertPointCommand = $""" - INSERT INTO {CvSqlTable.Value.Trim('"')} (map, type, zoneid, pointid, X, Y, Z) + INSERT INTO {CV_SQL_TABLE.Value.Trim('"')} (map, type, zoneid, pointid, X, Y, Z) VALUES (@map, @type, @zoneid, @pointid, @X, @Y, @Z) """; var pointId = 0; @@ -160,7 +160,7 @@ public class SqlZoneManager(IZoneFactory factory) : IZoneManager { await conn.OpenAsync(); var cmdText = $""" - CREATE TABLE IF NOT EXISTS {CvSqlTable.Value.Trim('"')}( + CREATE TABLE IF NOT EXISTS {CV_SQL_TABLE.Value.Trim('"')}( zoneid INT NOT NULL, pointid INT NOT NULL, map VARCHAR(64) NOT NULL, @@ -188,7 +188,7 @@ public class SqlZoneManager(IZoneFactory factory) : IZoneManager { private MySqlCommand queryAllZones(MySqlConnection conn, string map, ZoneType type) { var cmdText = $""" - SELECT * FROM {CvSqlTable.Value.Trim('"')} + SELECT * FROM {CV_SQL_TABLE.Value.Trim('"')} WHERE map = '{map}' AND type = '{type}' ORDER BY zoneid, pointid DESC """; @@ -260,7 +260,7 @@ public class SqlZoneManager(IZoneFactory factory) : IZoneManager { } private MySqlConnection? createConnection() { - var str = CvSqlConnectionString.Value.Trim('"'); + var str = CV_SQL_CONNECTION_STRING.Value.Trim('"'); return string.IsNullOrWhiteSpace(str) ? null : new MySqlConnection(str); } } \ No newline at end of file diff --git a/public/Jailbreak.Formatting/Views/Warden/IWardenCmdOpenLocale.cs b/public/Jailbreak.Formatting/Views/Warden/IWardenCmdOpenLocale.cs index 07ff0a6..daf76bc 100644 --- a/public/Jailbreak.Formatting/Views/Warden/IWardenCmdOpenLocale.cs +++ b/public/Jailbreak.Formatting/Views/Warden/IWardenCmdOpenLocale.cs @@ -5,19 +5,20 @@ namespace Jailbreak.Formatting.Views.Warden; public interface IWardenCmdOpenLocale { /// - /// The cells were auto-opened. + /// The cells were auto-opened. /// public IView CellsOpened { get; } + public IView OpeningFailed { get; } + public IView AlreadyOpened { get; } + /// - /// The cells were opened by the specified player. - /// If the player is null, the cells were opened by the warden. + /// The cells were opened by the specified player. + /// If the player is null, the cells were opened by the warden. /// /// /// public IView CellsOpenedBy(CCSPlayerController? player); - public IView OpeningFailed { get; } - public IView AlreadyOpened { get; } public IView CannotOpenYet(int seconds); } \ No newline at end of file diff --git a/public/Jailbreak.Public/Configuration/IConfigService.cs b/public/Jailbreak.Public/Configuration/IConfigService.cs deleted file mode 100644 index 9d1bca5..0000000 --- a/public/Jailbreak.Public/Configuration/IConfigService.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Jailbreak.Public.Configuration; - -public interface IConfigService { - public const string CONFIG_PATH = "jailbreak.json"; - - /// - /// Get the configuration object with the provided name - /// - /// - /// If the configuration service would return the default value, fail instead. Loudly. - /// - /// - T Get(string path, bool failOnDefault = false) where T : class, new(); -} \ No newline at end of file diff --git a/public/Jailbreak.Public/Extensions/CollectionExtensions.cs b/public/Jailbreak.Public/Extensions/CollectionExtensions.cs index 5b78e4b..2559396 100644 --- a/public/Jailbreak.Public/Extensions/CollectionExtensions.cs +++ b/public/Jailbreak.Public/Extensions/CollectionExtensions.cs @@ -1,13 +1,13 @@ namespace Jailbreak.Public.Extensions; public static class CollectionExtensions { - private static readonly Random Random = new(); + private static readonly Random RANDOM = new(); public static void Shuffle(this IList list) { var n = list.Count; while (n > 1) { n--; - var k = Random.Next(n + 1); + var k = RANDOM.Next(n + 1); (list[k], list[n]) = (list[n], list[k]); } } diff --git a/public/Jailbreak.Public/Extensions/ServiceCollectionExtensions.cs b/public/Jailbreak.Public/Extensions/ServiceCollectionExtensions.cs index 9fbd14c..a22c30c 100644 --- a/public/Jailbreak.Public/Extensions/ServiceCollectionExtensions.cs +++ b/public/Jailbreak.Public/Extensions/ServiceCollectionExtensions.cs @@ -1,5 +1,4 @@ using Jailbreak.Public.Behaviors; -using Jailbreak.Public.Configuration; using Microsoft.Extensions.DependencyInjection; namespace Jailbreak.Public.Extensions; @@ -44,24 +43,4 @@ public static class ServiceCollectionExtensions { collection.AddTransient(provider => provider.GetRequiredService()); } - - /// - /// Add an object to be loaded from the configuration file - /// - /// - /// The section where the configuration object will be loaded from - /// The configuration object. Must auto-fill all default values! - [Obsolete( - "Conguration is up to each module, and should ideally be done through CVars")] - public static void AddConfig(this IServiceCollection collection, - string sectionName) where TConfig : class, new() { - // Get the object by resolving IConfigService - // and use the Get() method. - - // Not *really* important... but do we want to fail here or return default if section - // isn't available? - collection.AddTransient(provider => provider - .GetRequiredService() - .Get(sectionName)); - } } \ No newline at end of file diff --git a/public/Jailbreak.Public/Mod/SpecialDay/AbstractSpecialDay.cs b/public/Jailbreak.Public/Mod/SpecialDay/AbstractSpecialDay.cs index 18dcb51..49926d8 100644 --- a/public/Jailbreak.Public/Mod/SpecialDay/AbstractSpecialDay.cs +++ b/public/Jailbreak.Public/Mod/SpecialDay/AbstractSpecialDay.cs @@ -48,6 +48,7 @@ public abstract class AbstractSpecialDay(BasePlugin plugin, /// know why you are not calling it. /// public virtual void Setup() { + Plugin.RegisterFakeConVars(this); Plugin.RegisterEventHandler(OnEnd); foreach (var entry in Settings.ConVarValues) { diff --git a/public/Jailbreak.Public/Utils/TeamUtil.cs b/public/Jailbreak.Public/Utils/TeamUtil.cs new file mode 100644 index 0000000..7c72e66 --- /dev/null +++ b/public/Jailbreak.Public/Utils/TeamUtil.cs @@ -0,0 +1,19 @@ +using CounterStrikeSharp.API.Modules.Utils; + +namespace Jailbreak.Public.Utils; + +public static class TeamUtil { + public static CsTeam? FromString(string team) { + return team.ToLower() switch { + "0" or "n" or "none" => CsTeam.None, + "1" or "s" or "spec" or "spectator" or "spectators" or "specs" => CsTeam + .Spectator, + "2" or "t" or "ts" or "terror" or "terrorist" or "terrorists" + or "prisoner" or "prisoners" => CsTeam.Terrorist, + "3" or "ct" or "cts" or "counter" or "counterterrorist" + or "counterterrorists" or "guard" + or "guards" => CsTeam.CounterTerrorist, + _ => null + }; + } +} \ No newline at end of file diff --git a/public/Jailbreak.Validator/ItemValidator.cs b/public/Jailbreak.Validator/ItemValidator.cs new file mode 100644 index 0000000..e6a73da --- /dev/null +++ b/public/Jailbreak.Validator/ItemValidator.cs @@ -0,0 +1,70 @@ +using CounterStrikeSharp.API.Modules.Cvars.Validators; + +namespace Jailbreak.Validator; + +public class ItemValidator( + ItemValidator.WeaponType type = ItemValidator.WeaponType.WEAPON + | ItemValidator.WeaponType.UTILITY, bool allowEmpty = true, + bool allowMultiple = false) : IValidator { + [Flags] + public enum WeaponType { + GRENADE, + UTILITY, + WEAPON, + SNIPERS, + RIFLES, + PISTOLS, + SHOTGUNS, + SMGS, + HEAVY, + GUNS + } + + public bool Validate(string value, out string? errorMessage) { + if (value.Contains(',') && !allowMultiple) { + errorMessage = "Value cannot contain multiple values"; + return false; + } + + if (string.IsNullOrWhiteSpace(value)) { + errorMessage = allowEmpty ? null : "weapon cannot be empty"; + return allowEmpty; + } + + foreach (var weapon in value.Split(',')) { + if (string.IsNullOrWhiteSpace(weapon)) { + if (!allowEmpty) { + errorMessage = allowEmpty ? null : "weapon cannot be empty"; + return allowEmpty; + } + + continue; + } + + errorMessage = $"invalid {nameof(type).ToLower()}: {weapon}"; + return Enum.GetValues() + .Where(t => (t & type) == type) + .Any(t => validateType(t, weapon)); + } + + errorMessage = null; + return true; + } + + private bool validateType(WeaponType current, string weapon) { + var result = current switch { + WeaponType.GRENADE => Tag.GRENADES.Contains(weapon), + WeaponType.UTILITY => Tag.UTILITY.Contains(weapon), + WeaponType.WEAPON => Tag.WEAPONS.Contains(weapon), + WeaponType.SNIPERS => Tag.SNIPERS.Contains(weapon), + WeaponType.RIFLES => Tag.RIFLES.Contains(weapon), + WeaponType.PISTOLS => Tag.PISTOLS.Contains(weapon), + WeaponType.SHOTGUNS => Tag.SHOTGUNS.Contains(weapon), + WeaponType.SMGS => Tag.SMGS.Contains(weapon), + WeaponType.HEAVY => Tag.HEAVY.Contains(weapon), + WeaponType.GUNS => Tag.GUNS.Contains(weapon), + _ => throw new ArgumentOutOfRangeException(nameof(weapon)) + }; + return result; + } +} \ No newline at end of file diff --git a/public/Jailbreak.Validator/NonZeroRangeValidator.cs b/public/Jailbreak.Validator/NonZeroRangeValidator.cs new file mode 100644 index 0000000..9b0d069 --- /dev/null +++ b/public/Jailbreak.Validator/NonZeroRangeValidator.cs @@ -0,0 +1,21 @@ +using CounterStrikeSharp.API.Modules.Cvars.Validators; + +namespace Jailbreak.Validator; + +public class NonZeroRangeValidator(T min, T max) + : IValidator where T : IComparable { + public bool Validate(T value, out string? errorMessage) { + if (value.Equals(default(T))) { + errorMessage = $"Value must be non-zero between {min} and {max}"; + return false; + } + + if (value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0) { + errorMessage = null; + return true; + } + + errorMessage = $"Value must be between {min} and {max}"; + return false; + } +} \ No newline at end of file diff --git a/public/Jailbreak.Validator/TeamValidator.cs b/public/Jailbreak.Validator/TeamValidator.cs new file mode 100644 index 0000000..1de152a --- /dev/null +++ b/public/Jailbreak.Validator/TeamValidator.cs @@ -0,0 +1,25 @@ +using CounterStrikeSharp.API.Modules.Cvars.Validators; +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Public.Utils; + +namespace Jailbreak.Validator; + +public class TeamValidator(bool allowSpecs = true) : IValidator { + public bool Validate(string value, out string? errorMessage) { + errorMessage = null; + + var team = TeamUtil.FromString(value); + + if (team == null) { + errorMessage = $"Unknown team: \"{value}\""; + return false; + } + + if (team is CsTeam.None or CsTeam.Spectator && !allowSpecs) { + errorMessage = "Team must be CT or T"; + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/public/Jailbreak.Validator/WeaponValidator.cs b/public/Jailbreak.Validator/WeaponValidator.cs deleted file mode 100644 index edaf151..0000000 --- a/public/Jailbreak.Validator/WeaponValidator.cs +++ /dev/null @@ -1,56 +0,0 @@ -using CounterStrikeSharp.API.Modules.Cvars.Validators; - -namespace Jailbreak.Validator; - -public class WeaponValidator( - WeaponValidator.WeaponType type = WeaponValidator.WeaponType.WEAPON, - bool allowEmpty = true, bool allowMultiple = false) : IValidator { - public enum WeaponType { - GRENADE, - UTILITY, - WEAPON, - SNIPERS, - RIFLES, - PISTOLS, - SHOTGUNS, - SMGS, - HEAVY - } - - public bool Validate(string value, out string? errorMessage) { - if (value.Contains(',') && !allowMultiple) { - errorMessage = "Value cannot contain multiple values"; - return false; - } - - if (string.IsNullOrWhiteSpace(value)) { - errorMessage = allowEmpty ? null : "weapon cannot be empty"; - return allowEmpty; - } - - foreach (var weapon in value.Split(',')) { - if (string.IsNullOrWhiteSpace(weapon)) { - errorMessage = allowEmpty ? null : "weapon cannot be empty"; - return allowEmpty; - } - - errorMessage = $"invalid {nameof(type).ToLower()}: {weapon}"; - var result = type switch { - WeaponType.GRENADE => Tag.GRENADES.Contains(weapon), - WeaponType.UTILITY => Tag.UTILITY.Contains(weapon), - WeaponType.WEAPON => Tag.WEAPONS.Contains(weapon), - WeaponType.SNIPERS => Tag.SNIPERS.Contains(weapon), - WeaponType.RIFLES => Tag.RIFLES.Contains(weapon), - WeaponType.PISTOLS => Tag.PISTOLS.Contains(weapon), - WeaponType.SHOTGUNS => Tag.SHOTGUNS.Contains(weapon), - WeaponType.SMGS => Tag.SMGS.Contains(weapon), - WeaponType.HEAVY => Tag.HEAVY.Contains(weapon), - _ => throw new ArgumentOutOfRangeException(nameof(weapon)) - }; - if (!result) return false; - } - - errorMessage = null; - return true; - } -} \ No newline at end of file diff --git a/src/Jailbreak/Config/ConfigService.cs b/src/Jailbreak/Config/ConfigService.cs deleted file mode 100644 index 60b572a..0000000 --- a/src/Jailbreak/Config/ConfigService.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Nodes; -using CounterStrikeSharp.API; -using Jailbreak.Public.Configuration; -using Microsoft.Extensions.Logging; - -namespace Jailbreak.Config; - -/// -/// A service to load and parse configuration files. -/// -public class ConfigService : IConfigService { - private readonly ILogger logger; - - /// - /// Constructor - /// - /// - public ConfigService(ILogger logger) { this.logger = logger; } - - /// - /// - /// - /// - /// - /// - public T Get(string path, bool fail = false) where T : class, new() { - var jsonPath = - Path.Combine(Server.GameDirectory, IConfigService.CONFIG_PATH); - - if (!File.Exists(jsonPath)) - return fail(fail, "Config file does not exist"); - - var jsonText = File.ReadAllText(jsonPath); - - var jsonObject = JsonNode.Parse(jsonText); - if (jsonObject == null) - return fail(fail, $"Unable to parse configuration file at {jsonPath}"); - - var configObject = jsonObject[path]; - if (configObject == null) - return fail(fail, $"Unable to navigate to config section {path}"); - - var config = configObject.Deserialize(); - if (config == null) - return fail(fail, - $"Unable to deserialize ({configObject.ToJsonString()}) into {typeof(T).FullName}."); - - return config; - } - - // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local - private T fail(bool fail, string message) where T : class, new() { - // We would be returning default. - // Check if caller wants us to cry and scream instead. - if (fail) throw new InvalidOperationException(message); - - logger.LogWarning( - "[Config] Tripped load fail state with message: {@Message}", message); - - return new T(); - } -} \ No newline at end of file diff --git a/src/Jailbreak/JailbreakServiceCollection.cs b/src/Jailbreak/JailbreakServiceCollection.cs index c7811e1..9051092 100644 --- a/src/Jailbreak/JailbreakServiceCollection.cs +++ b/src/Jailbreak/JailbreakServiceCollection.cs @@ -1,5 +1,4 @@ using CounterStrikeSharp.API.Core; -using Jailbreak.Config; using Jailbreak.Debug; using Jailbreak.English.Generic; using Jailbreak.English.LastGuard; @@ -18,7 +17,6 @@ using Jailbreak.LastGuard; using Jailbreak.LastRequest; using Jailbreak.Logs; using Jailbreak.Mute; -using Jailbreak.Public.Configuration; using Jailbreak.Rebel; using Jailbreak.SpecialDay; using Jailbreak.Warden; @@ -52,7 +50,6 @@ public class JailbreakServiceCollection : IPluginServiceCollection { // Do we want to make this scoped? // Not sure how this will behave with multiple rounds and whatnot. - serviceCollection.AddTransient(); serviceCollection.AddJailbreakGeneric(); serviceCollection.AddJailbreakLogs(); serviceCollection.AddJailbreakRebel();