* Add RTD

* Add noscope reward

* Tidy up message

* Auto Format
This commit is contained in:
Isaac
2024-08-28 00:17:58 -07:00
committed by GitHub
parent a0015ee9d0
commit 8cb437a8b8
48 changed files with 1018 additions and 145 deletions

View File

@@ -42,6 +42,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Zones", "mod\Jail
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Trail", "mod\Jailbreak.Trail\Jailbreak.Trail.csproj", "{91F4EC7A-993A-4CA0-84C3-9F1100124A9C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.RTD", "mod\Jailbreak.RTD\Jailbreak.RTD.csproj", "{C68D4760-7E1E-4633-995A-5EC1EF40E63B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -116,6 +118,10 @@ Global
{91F4EC7A-993A-4CA0-84C3-9F1100124A9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91F4EC7A-993A-4CA0-84C3-9F1100124A9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91F4EC7A-993A-4CA0-84C3-9F1100124A9C}.Release|Any CPU.Build.0 = Release|Any CPU
{C68D4760-7E1E-4633-995A-5EC1EF40E63B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C68D4760-7E1E-4633-995A-5EC1EF40E63B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C68D4760-7E1E-4633-995A-5EC1EF40E63B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C68D4760-7E1E-4633-995A-5EC1EF40E63B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9135CCC9-66C5-4A9C-AE3C-91475B5F0437} = {177DA48D-8306-4102-918D-992569878581}
@@ -135,5 +141,6 @@ Global
{A6249693-5B7E-4E14-A675-C292914F10F3} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7}
{C93A626A-BB44-4309-8DAD-4B28B2941870} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7}
{91F4EC7A-993A-4CA0-84C3-9F1100124A9C} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7}
{C68D4760-7E1E-4633-995A-5EC1EF40E63B} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,34 @@
using CounterStrikeSharp.API.Modules.Utils;
using Jailbreak.Formatting.Base;
using Jailbreak.Formatting.Logistics;
using Jailbreak.Formatting.Views;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.English.RTD;
public class RTDLocale : IRTDLocale, ILanguage<Formatting.Languages.English> {
public static readonly string PREFIX =
$" {ChatColors.Purple}[{ChatColors.LightPurple}RTD{ChatColors.Purple}]";
public IView RewardSelected(IRTDReward reward) {
return new SimpleView {
{ PREFIX, "You rolled ", reward.Name + "." },
SimpleView.NEWLINE,
{ PREFIX, reward.Description }
};
}
public IView AlreadyRolled(IRTDReward reward) {
return new SimpleView {
PREFIX,
ChatColors.Red + "You already rolled " + ChatColors.DarkRed + reward.Name
+ ChatColors.Red + "."
};
}
public IView CannotRollYet() {
return new SimpleView {
PREFIX, "You can only roll once the round ends or you die."
};
}
}

View File

@@ -20,11 +20,13 @@ namespace Jailbreak.LastRequest;
public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
: ILastRequestManager, IDamageBlocker {
public static readonly FakeConVar<int> CV_LR_BASE_TIME = new("css_jb_lr_time_base",
"Round time to set when LR is activated, 0 to disable", 60);
public static readonly FakeConVar<int> CV_LR_BASE_TIME =
new("css_jb_lr_time_base",
"Round time to set when LR is activated, 0 to disable", 60);
public static readonly FakeConVar<int> CV_LR_BONUS_TIME = new("css_jb_lr_time_per_lr",
"Additional round time to add per LR completion", 30);
public static readonly FakeConVar<int> CV_LR_BONUS_TIME =
new("css_jb_lr_time_per_lr",
"Additional round time to add per LR completion", 30);
public static readonly FakeConVar<int> CV_LR_GUARD_TIME =
new("css_jb_lr_time_per_guard", "Additional round time to add per guard");
@@ -92,7 +94,8 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
var cts = Utilities.GetPlayers()
.Count(p => p is { Team: CsTeam.CounterTerrorist, PawnIsAlive: true });
if (CV_LR_BASE_TIME.Value != 0) RoundUtil.SetTimeRemaining(CV_LR_BASE_TIME.Value);
if (CV_LR_BASE_TIME.Value != 0)
RoundUtil.SetTimeRemaining(CV_LR_BASE_TIME.Value);
RoundUtil.AddTimeRemaining(CV_LR_GUARD_TIME.Value * cts);

View File

@@ -0,0 +1,21 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Admin;
using Jailbreak.Public.Behaviors;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD;
public class AutoRTDListener(IRTDRewarder rewarder) : IPluginBehavior {
[GameEventHandler]
public HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) {
foreach (var player in Utilities.GetPlayers()
.Where(player
=> AdminManager.PlayerHasPermissions(player, "@ego/dssilver"))
.Where(player => !rewarder.HasReward(player)))
player.ExecuteClientCommandFromServer("css_rtd");
return HookResult.Continue;
}
}

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\public\Jailbreak.Formatting\Jailbreak.Formatting.csproj"/>
<ProjectReference Include="..\..\public\Jailbreak.Public\Jailbreak.Public.csproj"/>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,68 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Commands;
using Jailbreak.Formatting.Extensions;
using Jailbreak.Formatting.Views;
using Jailbreak.Public.Behaviors;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD;
public class RTDCommand(IRTDRewarder rewarder, IRewardGenerator generator,
IRTDLocale locale, IGenericCmdLocale generic) : IPluginBehavior {
private bool inBetweenRounds;
[ConsoleCommand("css_rtd", "Roll the dice!")]
public void Command_RTD(CCSPlayerController? executor, CommandInfo info) {
if (executor == null) return;
var bypass = AdminManager.PlayerHasPermissions(executor, "@css/root")
&& info.ArgCount == 2;
var old = rewarder.GetReward(executor);
if (!bypass && old != null) {
locale.AlreadyRolled(old).ToChat(executor);
return;
}
if (!bypass && !inBetweenRounds && executor.PawnIsAlive) {
locale.CannotRollYet().ToChat(executor);
return;
}
var reward = generator.GenerateReward(executor);
if (bypass) {
if (!int.TryParse(info.GetArg(1), out var slot)) {
generic.InvalidParameter(info.GetArg(1), "integer").ToChat(executor);
return;
}
if (slot != -1) {
var rewards = generator.ToList();
if (slot < 0 || slot >= rewards.Count) {
generic.InvalidParameter(info.GetArg(1), "0-" + (rewards.Count - 1))
.ToChat(executor);
return;
}
reward = generator.ToList()[slot].Item1;
}
}
rewarder.SetReward(executor, reward);
locale.RewardSelected(reward).ToChat(executor);
}
[GameEventHandler]
public HookResult OnEnd(EventRoundEnd @event, GameEventInfo info) {
inBetweenRounds = true;
return HookResult.Continue;
}
[GameEventHandler]
public HookResult OnStart(EventRoundStart @event, GameEventInfo info) {
inBetweenRounds = false;
return HookResult.Continue;
}
}

View File

@@ -0,0 +1,42 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using Jailbreak.Formatting.Views;
using Jailbreak.Formatting.Views.Logging;
using Jailbreak.Public.Behaviors;
using Jailbreak.Public.Mod.RTD;
using Jailbreak.Public.Utils;
namespace Jailbreak.RTD;
public class RTDRewarder(IRichLogService logs, IRTDLocale locale)
: IRTDRewarder, IPluginBehavior {
private readonly Dictionary<int, IRTDReward> rewards = new();
public bool HasReward(int id) { return GetReward(id) != null; }
public IRTDReward? GetReward(int id) {
return rewards.TryGetValue(id, out var reward) ? reward : null;
}
public bool SetReward(int id, IRTDReward reward) {
if (!reward.PrepareReward(id)) return false;
rewards[id] = reward;
return true;
}
[GameEventHandler]
public HookResult OnStart(EventRoundStart @event, GameEventInfo info) {
foreach (var player in PlayerUtil.GetAlive()) {
var id = player.UserId ?? -1;
var reward = GetReward(id);
if (reward == null) continue;
logs.Append("Granted", reward.Name, "to", logs.Player(player));
reward.GrantReward(id);
}
rewards.Clear();
return HookResult.Continue;
}
}

View File

@@ -0,0 +1,15 @@
using Jailbreak.Public.Extensions;
using Jailbreak.Public.Mod.RTD;
using Microsoft.Extensions.DependencyInjection;
namespace Jailbreak.RTD;
public static class RTDServiceExtensions {
public static void AddDiceRoll(this IServiceCollection collection) {
collection.AddPluginBehavior<IRewardGenerator, RewardGenerator>();
collection.AddPluginBehavior<IRTDRewarder, RTDRewarder>();
collection.AddPluginBehavior<RTDCommand>();
collection.AddPluginBehavior<AutoRTDListener>();
collection.AddPluginBehavior<RTDStatsCommand>();
}
}

View File

@@ -0,0 +1,28 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Utils;
using Jailbreak.Public.Behaviors;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD;
public class RTDStatsCommand(IRewardGenerator generator) : IPluginBehavior {
[ConsoleCommand("css_rtdstats", "View stats and probabilities of the die")]
public void
Command_RTDStats(CCSPlayerController? executor, CommandInfo info) {
if (executor == null) return;
var total = generator.Sum(r => r.Item2);
var rewards = generator.ToList();
rewards.Sort((a, b) => a.Item2.CompareTo(b.Item2));
var index = 0;
foreach (var (reward, prob) in rewards) {
var name = reward.Name;
var percent = prob / total * 100;
executor.PrintToChat(
$"{ChatColors.Orange}{index++}. {ChatColors.LightBlue}{name}{ChatColors.Grey}: {ChatColors.Yellow}{percent:0.00}%");
}
}
}

View File

@@ -0,0 +1,89 @@
using System.Collections;
using System.Drawing;
using CounterStrikeSharp.API.Core;
using Jailbreak.Public.Behaviors;
using Jailbreak.Public.Mod.Rebel;
using Jailbreak.Public.Mod.RTD;
using Jailbreak.Public.Mod.Zones;
using Jailbreak.RTD.Rewards;
namespace Jailbreak.RTD;
public class RewardGenerator(IZoneManager mgr, IC4Service bomb)
: IPluginBehavior, IRewardGenerator {
private static readonly float PROB_LOTTERY = 1 / 5000f;
private static readonly float PROB_EXTREMELY_LOW = 1 / 1000f;
private static readonly float PROB_VERY_LOW = 1 / 100f;
private static readonly float PROB_LOW = 1 / 20f;
private static readonly float PROB_MEDIUM = 1 / 10f;
private static readonly float PROB_OFTEN = 1 / 5f;
private static readonly float PROB_VERY_OFTEN = 1 / 2f;
private readonly List<(IRTDReward, float)> rewards = [
(new NothingReward(), PROB_OFTEN),
(new WeaponReward("weapon_healthshot"), PROB_OFTEN),
(new WeaponReward("weapon_decoy"), PROB_OFTEN),
(new CreditReward(1), PROB_MEDIUM), (new CreditReward(2), PROB_MEDIUM),
(new CreditReward(3), PROB_MEDIUM),
(new WeaponReward("weapon_flashbang"), PROB_MEDIUM),
(new WeaponReward("weapon_hegrenade"), PROB_MEDIUM),
(new WeaponReward("weapon_smokegrenade"), PROB_MEDIUM),
(new WeaponReward("weapon_molotov"), PROB_MEDIUM),
(new WeaponReward("weapon_taser"), PROB_MEDIUM),
(new HPReward(150), PROB_MEDIUM), (new HPReward(50), PROB_MEDIUM),
(new ArmorReward(150), PROB_MEDIUM), (new HPReward(1), PROB_LOW),
(new ColorReward(Color.FromArgb(0, 255, 0), true), PROB_LOW),
(new ColorReward(Color.FromArgb(255, 0, 0), true), PROB_LOW),
(new TransparentReward(), PROB_LOW),
(new AmmoWeaponReward("weapon_glock", 2, 0), PROB_LOW),
(new AmmoWeaponReward("weapon_negev", 0, 5), PROB_LOW),
(new NoWeaponReward(), PROB_VERY_LOW),
(new AmmoWeaponReward("weapon_deagle", 1, 0), PROB_VERY_LOW),
(new RandomTeleportReward(mgr), PROB_VERY_LOW),
(new BombReward(bomb), PROB_VERY_LOW),
(new AmmoWeaponReward("weapon_awp", 1, 0), PROB_EXTREMELY_LOW)
];
private readonly Random rng = new();
private float totalWeight
=> rewards.Where(r => r.Item1.Enabled).Select(s => s.Item2).Sum();
public void Start(BasePlugin basePlugin) {
rewards.Add((new CannotPickupReward(basePlugin, WeaponType.GRENADE),
PROB_LOW));
rewards.Add((new CannotPickupReward(basePlugin, WeaponType.UTILITY),
PROB_LOW));
rewards.Add((new CannotScopeReward(basePlugin), PROB_LOW));
rewards.Add((
new CannotPickupReward(basePlugin,
WeaponType.GRENADE | WeaponType.UTILITY), PROB_LOW));
rewards.Add((new CannotPickupReward(basePlugin, WeaponType.PISTOLS),
PROB_VERY_LOW));
rewards.Add((new CannotPickupReward(basePlugin, WeaponType.SNIPERS),
PROB_VERY_LOW));
rewards.Add((new CannotPickupReward(basePlugin, WeaponType.HEAVY),
PROB_VERY_LOW));
rewards.Add((new CannotPickupReward(basePlugin, WeaponType.RIFLES),
PROB_EXTREMELY_LOW));
}
public IRTDReward GenerateReward(int? id) {
var roll = rng.NextDouble() * totalWeight;
foreach (var reward in rewards.Where(reward => reward.Item1.Enabled)) {
if (id != null && reward.Item1.CanGrantReward(id.Value)) continue;
roll -= reward.Item2;
if (roll <= 0) return reward.Item1;
}
throw new InvalidOperationException("No reward was generated.");
}
public IEnumerator<(IRTDReward, float)> GetEnumerator() {
return rewards.Where(r => r.Item1.Enabled).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public int Count => rewards.Count(r => r.Item1.Enabled);
}

View File

@@ -0,0 +1,24 @@
using System.Diagnostics;
using CounterStrikeSharp.API.Core;
using Jailbreak.Public.Extensions;
namespace Jailbreak.RTD.Rewards;
public class AmmoWeaponReward : WeaponReward {
private readonly int primary, secondary;
public AmmoWeaponReward(string weapon, int primary, int secondary) :
base(weapon) {
Trace.Assert(Tag.GUNS.Contains(weapon));
this.primary = primary;
this.secondary = secondary;
}
public override bool GrantReward(CCSPlayerController player) {
var success = base.GrantReward(player);
if (!success) return false;
player.GetWeaponBase(weapon).SetAmmo(primary, secondary);
return true;
}
}

View File

@@ -0,0 +1,15 @@
using CounterStrikeSharp.API.Core;
using Jailbreak.Public.Extensions;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class ArmorReward(int armor) : IRTDReward {
public string Name => armor + " Armor";
public string Description => "You won " + armor + " Armor next round.";
public bool GrantReward(CCSPlayerController player) {
player.SetArmor(armor);
return true;
}
}

View File

@@ -0,0 +1,25 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using Jailbreak.Public.Mod.Rebel;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class BombReward(IC4Service bombService) : IRTDReward {
public string Name => "Bomb";
public string Description => "You won the bomb next round.";
public bool PrepareReward(int userid) {
bombService.DontGiveC4NextRound();
return true;
}
public bool CanGrantReward(CCSPlayerController player) {
return player.Team == CsTeam.Terrorist;
}
public bool GrantReward(CCSPlayerController player) {
bombService.TryGiveC4ToPlayer(player);
return true;
}
}

View File

@@ -0,0 +1,56 @@
using System.Collections.Immutable;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using Jailbreak.Public.Extensions;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class CannotPickupReward : IRTDReward {
private readonly HashSet<int> blockedPlayerIDs = [];
private readonly ImmutableHashSet<string> blockedWeapons;
private readonly BasePlugin plugin;
public CannotPickupReward(BasePlugin plugin, WeaponType blocked) : this(
plugin, blocked.GetItems().ToArray()) {
Name = $"Cannot Pickup {blocked}";
}
public CannotPickupReward(BasePlugin plugin, params string[] weapons) {
this.plugin = plugin;
this.plugin.RegisterEventHandler<EventItemPickup>(onPickup);
this.plugin.RegisterEventHandler<EventRoundEnd>(onRoundEnd);
blockedWeapons = weapons.ToImmutableHashSet();
Name =
$"Cannot Pickup {string.Join(", ", blockedWeapons.Select(s => s.GetFriendlyWeaponName()))}";
}
public string Name { get; }
public string Description
=> $"You will not be able to pickup {Name} next round.";
public bool GrantReward(CCSPlayerController player) {
if (player.UserId == null) return false;
blockedPlayerIDs.Add(player.UserId.Value);
return true;
}
private HookResult onRoundEnd(EventRoundEnd @event, GameEventInfo info) {
blockedPlayerIDs.Clear();
return HookResult.Continue;
}
private HookResult onPickup(EventItemPickup @event, GameEventInfo info) {
var player = @event.Userid;
if (player == null || !player.IsValid || player.UserId == null)
return HookResult.Continue;
if (!blockedPlayerIDs.Contains(player.UserId.Value))
return HookResult.Continue;
var weapon = "weapon_" + @event.Item;
if (!blockedWeapons.Contains(weapon)) return HookResult.Continue;
player.RemoveItemByDesignerName(weapon, true);
return HookResult.Continue;
}
}

View File

@@ -0,0 +1,69 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using Jailbreak.Public.Extensions;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class CannotScopeReward : IRTDReward {
private readonly HashSet<int> blockedPlayerIDs = [];
private readonly BasePlugin plugin;
private bool registered;
public CannotScopeReward(BasePlugin plugin, WeaponType blocked) : this(plugin,
blocked.GetItems().ToArray()) { }
public CannotScopeReward(BasePlugin plugin, params string[] weapons) {
this.plugin = plugin;
this.plugin.RegisterEventHandler<EventRoundEnd>(onRoundEnd);
}
public string Name => "Cannot Scope";
public string Description => "You will not be able to scope next round.";
public bool GrantReward(CCSPlayerController player) {
if (player.UserId == null) return false;
if (!registered) {
plugin.RegisterListener<Listeners.OnTick>(onTick);
registered = true;
}
blockedPlayerIDs.Add(player.UserId.Value);
return true;
}
private HookResult onRoundEnd(EventRoundEnd @event, GameEventInfo info) {
blockedPlayerIDs.Clear();
plugin.RemoveListener<Listeners.OnTick>(onTick);
registered = false;
return HookResult.Continue;
}
private void onTick() {
registered = true;
if (blockedPlayerIDs.Count == 0) {
plugin.RemoveListener<Listeners.OnTick>(onTick);
registered = false;
return;
}
foreach (var player in blockedPlayerIDs.Select(
Utilities.GetPlayerFromUserid)) {
if (player == null || player.UserId == null || !player.IsValid) continue;
disableScope(player);
}
}
private void disableScope(CCSPlayerController player) {
if (!player.IsReal()) return;
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid) return;
var weaponServices = pawn.WeaponServices;
if (weaponServices == null) return;
var activeWeapon = weaponServices.ActiveWeapon.Value;
if (activeWeapon == null || !activeWeapon.IsValid) return;
activeWeapon.NextSecondaryAttackTick = Server.TickCount + 500;
}
}

View File

@@ -0,0 +1,47 @@
using System.Drawing;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using Jailbreak.Public.Extensions;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class ColorReward(Color color, bool prisonerOnly) : IRTDReward {
public string ColorName
=> color.IsNamedColor ?
color.Name :
color.GetHue() switch {
0 => "Red",
60 => "Yellow",
120 => "Green",
180 => "Cyan",
240 => "Blue",
300 => "Magenta",
_ => "#" + color.ToArgb().ToString("X8")
};
public char ChatColor
=> color.GetHue() switch {
0 => ChatColors.Red,
60 => ChatColors.Yellow,
120 => ChatColors.Green,
180 => ChatColors.LightBlue,
240 => ChatColors.Blue,
300 => ChatColors.Magenta,
_ => ChatColors.White
};
public virtual string Name => "Spawn " + ColorName;
public virtual string Description
=> $"You won spawning {ChatColor}{ColorName}{ChatColors.Grey} next round.";
public bool CanGrantReward(CCSPlayerController player) {
return player.Team == CsTeam.Terrorist || !prisonerOnly;
}
public bool GrantReward(CCSPlayerController player) {
player.SetColor(color);
return true;
}
}

View File

@@ -0,0 +1,24 @@
using CounterStrikeSharp.API.Core;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class CreditReward(int credits) : IRTDReward {
public string Name => credits + " Credit";
public string Description
=> "You won " + credits + " credit" + (credits == 1 ? "" : "s")
+ (credits > 500 ? "!" : ".");
public bool Enabled => false; // TODO: Implement
public bool PrepareReward(int userid) {
// TODO: When we do implement, set their credits here
return true;
}
public bool GrantReward(CCSPlayerController player) {
// We would have already set their credits in PrepareReward, so do nothing here
return true;
}
}

View File

@@ -0,0 +1,23 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using Jailbreak.Public.Mod.RTD;
using Jailbreak.Public.Mod.Warden;
namespace Jailbreak.RTD.Rewards;
public class GuaranteedWardenReward(IWardenSelectionService service)
: IRTDReward {
public string Name => "Guaranteed Warden";
public string Description
=> "You are guaranteed to be warden next round if you queue for it";
public bool CanGrantReward(CCSPlayerController player) {
return player.Team == CsTeam.CounterTerrorist;
}
public bool GrantReward(CCSPlayerController player) {
service.SetGuaranteedWarden(player);
return true;
}
}

View File

@@ -0,0 +1,15 @@
using CounterStrikeSharp.API.Core;
using Jailbreak.Public.Extensions;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class HPReward(int hp) : IRTDReward {
public string Name => hp + " HP";
public string Description => "You won " + hp + " HP next round.";
public bool GrantReward(CCSPlayerController player) {
player.SetHealth(hp);
return true;
}
}

View File

@@ -0,0 +1,14 @@
using CounterStrikeSharp.API.Core;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class NoWeaponReward : IRTDReward {
public string Name => "No Weapon";
public string Description => "You will not spawn with a knife next round.";
public bool GrantReward(CCSPlayerController player) {
player.RemoveWeapons();
return true;
}
}

View File

@@ -0,0 +1,10 @@
using CounterStrikeSharp.API.Core;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class NothingReward : IRTDReward {
public string Name => "Nothing";
public string Description => "You won nothing.";
public bool GrantReward(CCSPlayerController player) { return true; }
}

View File

@@ -0,0 +1,25 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using Jailbreak.Public.Mod.RTD;
using Jailbreak.Public.Mod.Zones;
using Jailbreak.Public.Utils;
namespace Jailbreak.RTD.Rewards;
public class RandomTeleportReward(IZoneManager zones) : IRTDReward {
public string Name => "Random Teleport";
public string Description
=> "You will be teleported to a random location next round.";
public bool CanGrantReward(CCSPlayerController player) {
return player.Team == CsTeam.Terrorist;
}
public bool GrantReward(CCSPlayerController player) {
var zone = MapUtil.GetRandomSpawns(1, zones).FirstOrDefault();
if (zone == null) return false;
player.Teleport(zone);
return true;
}
}

View File

@@ -0,0 +1,11 @@
using System.Drawing;
namespace Jailbreak.RTD.Rewards;
public class TransparentReward()
: ColorReward(Color.FromArgb(128, 255, 255, 255), false) {
public override string Name => "Spawn Transparent";
public override string Description
=> "You won spawning transparent next round.";
}

View File

@@ -0,0 +1,33 @@
using System.Diagnostics;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using Jailbreak.Public.Extensions;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.RTD.Rewards;
public class WeaponReward : IRTDReward {
protected readonly string weapon;
public WeaponReward(string weapon) {
this.weapon = weapon;
Trace.Assert(Tag.GUNS.Contains(weapon));
}
public string Name => weapon.GetFriendlyWeaponName();
public string Description
=> "You won a"
+ (weapon.GetFriendlyWeaponName()[0].IsVowel() ? "n" : "" + " ")
+ weapon.GetFriendlyWeaponName() + " next round.";
public bool CanGrantReward(CCSPlayerController player) {
// No point in giving a weapon to someone on CT
return player.Team == CsTeam.Terrorist;
}
public virtual bool GrantReward(CCSPlayerController player) {
player.GiveNamedItem(weapon);
return true;
}
}

View File

@@ -17,16 +17,6 @@ namespace Jailbreak.Rebel.C4Bomb;
public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
: IPluginBehavior, IC4Service {
private readonly Dictionary<CC4, C4Metadata> bombs = new();
// EmitSound(CBaseEntity* pEnt, const char* sSoundName, int nPitch, float flVolume, float flDelay)
private readonly MemoryFunctionVoid<CBaseEntity, string, int, float, float>
// ReSharper disable once InconsistentNaming
CBaseEntity_EmitSoundParamsLinux = new(
"48 B8 ? ? ? ? ? ? ? ? 55 48 89 E5 41 55 41 54 49 89 FC 53 48 89 F3"); // LINUX ONLY.
private BasePlugin? plugin;
public static readonly FakeConVar<bool> CV_GIVE_BOMB = new("css_jb_c4_give",
"Whether to give a random prisoner a bomb at the beginning of the round.",
true);
@@ -43,6 +33,18 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
new("css_jb_c4_damage", "Base damage to apply", 340, ConVarFlags.FCVAR_NONE,
new RangeValidator<float>(0, 10000));
private readonly Dictionary<CC4, C4Metadata> bombs = new();
// EmitSound(CBaseEntity* pEnt, const char* sSoundName, int nPitch, float flVolume, float flDelay)
private readonly MemoryFunctionVoid<CBaseEntity, string, int, float, float>
// ReSharper disable once InconsistentNaming
CBaseEntity_EmitSoundParamsLinux = new(
"48 B8 ? ? ? ? ? ? ? ? 55 48 89 E5 41 55 41 54 49 89 FC 53 48 89 F3"); // LINUX ONLY.
private bool giveNextRound = true;
private BasePlugin? plugin;
public void ClearActiveC4s() { bombs.Clear(); }
public void TryGiveC4ToPlayer(CCSPlayerController player) {
@@ -90,6 +92,8 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
});
}
public void DontGiveC4NextRound() { giveNextRound = false; }
public void Start(BasePlugin basePlugin) {
plugin = basePlugin;
plugin.RegisterListener<Listeners.OnTick>(playerUseC4ListenerCallback);
@@ -120,7 +124,13 @@ public class C4Behavior(IC4Locale ic4Locale, IRebelService rebelService)
public HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) {
ClearActiveC4s();
if (CV_GIVE_BOMB.Value) TryGiveC4ToRandomTerrorist();
if (!CV_GIVE_BOMB.Value) return HookResult.Continue;
if (!giveNextRound) {
giveNextRound = true;
return HookResult.Continue;
}
TryGiveC4ToRandomTerrorist();
return HookResult.Continue;
}

View File

@@ -11,11 +11,11 @@ using Jailbreak.Zones;
namespace Jailbreak.SpecialDay.SpecialDays;
public abstract class AbstractZoneRestrictedDay : AbstractSpecialDay {
protected CsTeam RestrictedTeam;
protected readonly IList<MovementRestrictor> Restrictors =
new List<MovementRestrictor>();
protected CsTeam RestrictedTeam;
protected AbstractZoneRestrictedDay(BasePlugin plugin,
IServiceProvider provider,
CsTeam restrictedTeam = CsTeam.Terrorist) : base(plugin, provider) {

View File

@@ -7,7 +7,9 @@ using Jailbreak.Formatting.Views.SpecialDay;
using Jailbreak.Public.Extensions;
using Jailbreak.Public.Mod.SpecialDay;
using Jailbreak.Public.Mod.SpecialDay.Enums;
using Jailbreak.Public.Mod.Zones;
using Jailbreak.Public.Utils;
using Microsoft.Extensions.DependencyInjection;
namespace Jailbreak.SpecialDay.SpecialDays;
@@ -57,8 +59,10 @@ public class GunGameDay(BasePlugin plugin, IServiceProvider provider)
Timers[10] += Execute;
base.Setup();
var mgr = Provider.GetService<IZoneManager>();
spawns =
new ShuffleBag<Vector>(getAtLeastRandom(Utilities.GetPlayers().Count));
new ShuffleBag<Vector>(
MapUtil.GetRandomSpawns(Utilities.GetPlayers().Count, mgr));
Plugin.RegisterEventHandler<EventPlayerDeath>(OnDeath, HookMode.Pre);
Plugin.RegisterEventHandler<EventPlayerSpawn>(OnRespawn);

View File

@@ -17,13 +17,6 @@ namespace Jailbreak.SpecialDay.SpecialDays;
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;
public ISDInstanceLocale Locale => new HNSDayLocale();
// Set to -1 to not modify values
public static readonly FakeConVar<int> CV_PRISONER_PRE_HEALTH = new(
"jb_sd_hns_hide_hp_t", "Health to give to prisoners during HNS hide time",
@@ -78,6 +71,12 @@ public class HideAndSeekDay(BasePlugin plugin, IServiceProvider provider)
"Duration in seconds to give the hiders time to hide", 45,
ConVarFlags.FCVAR_NONE, new RangeValidator<int>(5, 120));
public override SDType Type => SDType.HNS;
private HNSDayLocale Msg => (HNSDayLocale)Locale;
public override SpecialDaySettings Settings => new HnsSettings();
public override IView ArmoryReminder => Msg.StayInArmory;
private CsTeam? SeekerTeam => TeamUtil.FromString(CV_SEEKER_TEAM.Value);
private CsTeam? HiderTeam
@@ -85,6 +84,8 @@ public class HideAndSeekDay(BasePlugin plugin, IServiceProvider provider)
CsTeam.CounterTerrorist :
CsTeam.Terrorist;
public ISDInstanceLocale Locale => new HNSDayLocale();
public override void Setup() {
if (SeekerTeam == null || HiderTeam == null) return;
RestrictedTeam = SeekerTeam.Value;

View File

@@ -14,14 +14,6 @@ namespace Jailbreak.SpecialDay.SpecialDays;
public class NoScopeDay(BasePlugin plugin, IServiceProvider provider)
: FFADay(plugin, provider) {
public override SDType Type => SDType.NOSCOPE;
public override ISDInstanceLocale Locale
=> new SoloDayLocale("No Scope",
"Your scope broke! Fight against everyone else. No camping!");
public override SpecialDaySettings Settings => new NoScopeSettings();
public static readonly FakeConVar<string> CV_WEAPON = new(
"jb_sd_noscope_weapon",
"Weapon to give to all players, recommended it be a weapon with a scope (duh)",
@@ -44,6 +36,14 @@ public class NoScopeDay(BasePlugin plugin, IServiceProvider provider)
new("jb_sd_noscope_gravity",
"Gravity to set during the special day, default is 800", 200f);
public override SDType Type => SDType.NOSCOPE;
public override ISDInstanceLocale Locale
=> new SoloDayLocale("No Scope",
"Your scope broke! Fight against everyone else. No camping!");
public override SpecialDaySettings Settings => new NoScopeSettings();
public override void Setup() {
if (CV_KNIFE_DELAY.Value > 0)
Timers[CV_KNIFE_DELAY.Value] += () => {

View File

@@ -13,17 +13,9 @@ namespace Jailbreak.SpecialDay.SpecialDays;
public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider)
: FFADay(plugin, provider) {
public override SDType Type => SDType.OITC;
public override ISDInstanceLocale Locale
=> new SoloDayLocale("One in the Chamber", "You only have one bullet.",
"Kill someone to get another bullet.", "One-Hit-Kills! No camping!");
public override SpecialDaySettings Settings => new OitcSettings();
public static readonly FakeConVar<string> 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));
ConVarFlags.FCVAR_NONE, new ItemValidator(WeaponType.GUNS));
public static readonly FakeConVar<string> CV_ADDITIONAL_WEAPON = new(
"jb_sd_oitc_additionalweapon",
@@ -31,6 +23,13 @@ public class OneInTheChamberDay(BasePlugin plugin, IServiceProvider provider)
"weapon_knife", ConVarFlags.FCVAR_NONE, new ItemValidator());
private bool started;
public override SDType Type => SDType.OITC;
public override ISDInstanceLocale Locale
=> new SoloDayLocale("One in the Chamber", "You only have one bullet.",
"Kill someone to get another bullet.", "One-Hit-Kills! No camping!");
public override SpecialDaySettings Settings => new OitcSettings();
public override void Setup() {
base.Setup();

View File

@@ -38,9 +38,6 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
ISpecialTreatmentService specialTreatment, IRebelService rebels,
IMuteService mute, IServiceProvider provider)
: IPluginBehavior, IWardenService {
private readonly ISet<CCSPlayerController> bluePrisoners =
new HashSet<CCSPlayerController>();
public static readonly FakeConVar<int> CV_ARMOR_EQUAL =
new("css_jb_hp_outnumbered", "Health points for CTs have equal balance", 50,
ConVarFlags.FCVAR_NONE, new RangeValidator<int>(1, 200));
@@ -84,6 +81,9 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
public static readonly FakeConVar<int> CV_WARDEN_TERRORIST_RATIO =
new("css_jb_warden_t_ratio", "Ratio of T:CT to use for HP adjustments", 3);
private readonly ISet<CCSPlayerController> bluePrisoners =
new HashSet<CCSPlayerController>();
private bool firstWarden;
private string? oldTag;
private char? oldTagColor;

View File

@@ -48,7 +48,8 @@ public class WardenMarkerBehavior(IWardenService warden) : IPluginBehavior {
- placementTime;
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);
distance = Math.Clamp(distance, CV_MIN_RADIUS.Value,
CV_MAX_RADIUS.Value);
marker?.SetRadius(distance);
marker?.Update();
radius = distance;

View File

@@ -22,6 +22,8 @@ public class
private readonly IPlayerState<QueueFavorState> favor;
private readonly HashSet<int> guaranteedWarden = [];
private readonly IWardenLocale locale;
private readonly ILogger<WardenSelectionBehavior> logger;
@@ -57,9 +59,18 @@ public class
public void Dispose() { }
public void SetGuaranteedWarden(CCSPlayerController player) {
guaranteedWarden.Add(player.UserId ?? -1);
}
public bool TryEnter(CCSPlayerController player) {
if (!canEnterQueue(player)) return false;
if (guaranteedWarden.Contains(player.UserId ?? -1)) {
warden.TrySetWarden(player);
return true;
}
queue.Get(player).InQueue = true;
return true;
}
@@ -100,6 +111,7 @@ public class
/// Timer callback that states it's time to choose the warden.
/// </summary>
protected void OnChooseWarden() {
if (warden.HasWarden) return;
var eligible = Utilities.GetPlayers()
.Where(player => player.PawnIsAlive)
.Where(player => player.Team == CsTeam.CounterTerrorist)

View File

@@ -8,8 +8,8 @@ using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
namespace Jailbreak.Zones;
public class SqlZoneManager(IZoneFactory factory) : IZoneManager {
public static readonly FakeConVar<string> CV_SQL_TABLE = new("css_jb_zonetable",
"The table name for the zones", "cs2_jb_zones");
public static readonly FakeConVar<string> CV_SQL_TABLE =
new("css_jb_zonetable", "The table name for the zones", "cs2_jb_zones");
public static readonly FakeConVar<string> CV_SQL_CONNECTION_STRING =
new("css_jb_sqlconnection", "The connection string for the database", "",

View File

@@ -0,0 +1,10 @@
using Jailbreak.Formatting.Base;
using Jailbreak.Public.Mod.RTD;
namespace Jailbreak.Formatting.Views;
public interface IRTDLocale {
public IView RewardSelected(IRTDReward reward);
public IView AlreadyRolled(IRTDReward reward);
public IView CannotRollYet();
}

View File

@@ -124,6 +124,7 @@ public static class PlayerExtensions {
var pawn = player.PlayerPawn.Value;
if (!player.IsValid || pawn == null || !pawn.IsValid) return;
// TODO: Don't always override to allow other plugins to show legs.
if (color.A == 255) color = Color.FromArgb(254, color.R, color.G, color.B);
pawn.RenderMode = RenderMode_t.kRenderTransColor;
pawn.Render = color;

View File

@@ -125,8 +125,10 @@ public static class WeaponExtensions {
case "weapon_knife_t":
case "weapon_knife":
return "Knife";
default:
return designerName.Replace("weapon_", "").ToUpper();
default: {
var name = designerName.Replace("weapon_", "");
return char.ToUpper(name[0]) + name[1..];
}
}
}

View File

@@ -0,0 +1,33 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
namespace Jailbreak.Public.Mod.RTD;
public interface IRTDReward {
public string Name { get; }
public string Description { get; }
bool Enabled => true;
bool CanGrantReward(int userid) {
var player = Utilities.GetPlayerFromUserid(userid);
return player != null && player.IsValid && CanGrantReward(player);
}
bool CanGrantReward(CCSPlayerController player) { return true; }
bool PrepareReward(int userid) {
var player = Utilities.GetPlayerFromUserid(userid);
if (player == null || !player.IsValid) return false;
return PrepareReward(player);
}
bool PrepareReward(CCSPlayerController player) { return true; }
bool GrantReward(int userid) {
var player = Utilities.GetPlayerFromUserid(userid);
if (player == null || !player.IsValid) return false;
return player.PawnIsAlive && GrantReward(player);
}
bool GrantReward(CCSPlayerController player);
}

View File

@@ -0,0 +1,42 @@
using CounterStrikeSharp.API.Core;
namespace Jailbreak.Public.Mod.RTD;
/// <summary>
/// A rewarder that manages rewards for players.
/// </summary>
public interface IRTDRewarder {
/// <summary>
/// True if the player currently has a reward.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
bool HasReward(int id) { return GetReward(id) != null; }
bool HasReward(CCSPlayerController player) {
return HasReward(player.UserId ?? -1);
}
/// <summary>
/// Gets the reward for the player.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
IRTDReward? GetReward(int id);
IRTDReward? GetReward(CCSPlayerController player) {
return GetReward(player.UserId ?? -1);
}
/// <summary>
/// Attempts to give a reward to the player.
/// </summary>
/// <param name="id"></param>
/// <param name="reward"></param>
/// <returns></returns>
bool SetReward(int id, IRTDReward reward);
bool SetReward(CCSPlayerController player, IRTDReward reward) {
return SetReward(player.UserId ?? -1, reward);
}
}

View File

@@ -0,0 +1,11 @@
using CounterStrikeSharp.API.Core;
namespace Jailbreak.Public.Mod.RTD;
public interface IRewardGenerator : IReadOnlyCollection<(IRTDReward, float)> {
IRTDReward GenerateReward(int? id);
IRTDReward GenerateReward(CCSPlayerController player) {
return GenerateReward(player.UserId);
}
}

View File

@@ -25,5 +25,7 @@ public interface IC4Service {
/// </summary>
void TryGiveC4ToRandomTerrorist();
void DontGiveC4NextRound() { }
void ClearActiveC4s();
}

View File

@@ -147,6 +147,7 @@ public abstract class AbstractSpecialDay(BasePlugin plugin,
var ctVectors = ctSpawns.ToArray();
ctVectors.Shuffle();
var mgr = Provider.GetService<IZoneManager>();
IEnumerable<Vector> spawnPositions;
switch (type) {
case SpecialDaySettings.TeleportType.CELL:
@@ -162,10 +163,11 @@ public abstract class AbstractSpecialDay(BasePlugin plugin,
spawnPositions = [ctVectors.First()];
break;
case SpecialDaySettings.TeleportType.RANDOM:
spawnPositions = getAtLeastRandom(PlayerUtil.GetAlive().Count());
spawnPositions =
MapUtil.GetRandomSpawns(PlayerUtil.GetAlive().Count(), mgr);
break;
case SpecialDaySettings.TeleportType.RANDOM_STACKED:
spawnPositions = [getAtLeastRandom(1).First()];
spawnPositions = [MapUtil.GetRandomSpawns(1, mgr).First()];
break;
default:
return;
@@ -176,61 +178,6 @@ public abstract class AbstractSpecialDay(BasePlugin plugin,
player.PlayerPawn.Value?.Teleport(baggedSpawns.GetNext());
}
protected List<Vector> getAtLeastRandom(int count) {
// Progressively get more lax with our "randomness quality"
var result = getRandomSpawns(false, false, false);
if (result.Count < count) result = getRandomSpawns(false, false);
if (result.Count < count) result = getRandomSpawns(false);
if (result.Count < count) result = getRandomSpawns();
return result;
}
protected List<Vector> getRandomSpawns(bool includeSpawns = true,
bool includeTps = true, bool includeAuto = true) {
var result = new List<Vector>();
if (includeTps) {
var worldTp = Utilities
.FindAllEntitiesByDesignerName<CInfoTeleportDestination>(
"info_teleport_destination")
.Where(s => s.AbsOrigin != null)
.Select(s => s.AbsOrigin!);
result.AddRange(worldTp);
}
if (includeSpawns) {
var tSpawns = Utilities
.FindAllEntitiesByDesignerName<SpawnPoint>("info_player_terrorist")
.Where(s => s.AbsOrigin != null)
.Select(s => s.AbsOrigin!);
var ctSpawns = Utilities
.FindAllEntitiesByDesignerName<
SpawnPoint>("info_player_counterterrorist")
.Where(s => s.AbsOrigin != null)
.Select(s => s.AbsOrigin!);
result.AddRange(tSpawns);
result.AddRange(ctSpawns);
}
var zoneManager = Provider.GetService<IZoneManager>();
if (zoneManager != null) {
if (includeAuto)
result.AddRange(zoneManager
.GetZones(Server.MapName, ZoneType.SPAWN_AUTO)
.GetAwaiter()
.GetResult()
.Select(z => z.GetCenterPoint()));
var zones = zoneManager.GetZones(Server.MapName, ZoneType.SPAWN)
.GetAwaiter()
.GetResult();
result.AddRange(zones.Select(z => z.GetCenterPoint()));
}
result.Shuffle();
return result;
}
protected object GetConvarValue(ConVar? cvar) {
try {
if (cvar == null) return "";

View File

@@ -8,6 +8,14 @@ public interface IWardenSelectionService {
/// </summary>
bool Active { get; }
/// <summary>
/// Whether the player should be guaranteed warden if they enter the queue
/// this will act as a bypass to the queue. Thus, if multiple players are
/// applied with this, the first player to be apply for warden will receive it.
/// </summary>
/// <param name="player"></param>
void SetGuaranteedWarden(CCSPlayerController player);
/// <summary>
/// Enter this player into the warden queue
/// </summary>

View File

@@ -121,6 +121,61 @@ public static class MapUtil {
return false;
}
public static List<Vector> GetRandomSpawns(int count, IZoneManager? zones) {
// Progressively get more lax with our "randomness quality"
var result = GetRandomSpawns(zones, false, false, false);
if (result.Count < count) result = GetRandomSpawns(zones, false, false);
if (result.Count < count) result = GetRandomSpawns(zones, false);
if (result.Count < count) result = GetRandomSpawns(zones);
return result;
}
public static List<Vector> GetRandomSpawns(IZoneManager? zoneManager = null,
bool includeSpawns = true, bool includeTps = true,
bool includeAuto = true) {
var result = new List<Vector>();
if (includeTps) {
var worldTp = Utilities
.FindAllEntitiesByDesignerName<CInfoTeleportDestination>(
"info_teleport_destination")
.Where(s => s.AbsOrigin != null)
.Select(s => s.AbsOrigin!);
result.AddRange(worldTp);
}
if (includeSpawns) {
var tSpawns = Utilities
.FindAllEntitiesByDesignerName<SpawnPoint>("info_player_terrorist")
.Where(s => s.AbsOrigin != null)
.Select(s => s.AbsOrigin!);
var ctSpawns = Utilities
.FindAllEntitiesByDesignerName<
SpawnPoint>("info_player_counterterrorist")
.Where(s => s.AbsOrigin != null)
.Select(s => s.AbsOrigin!);
result.AddRange(tSpawns);
result.AddRange(ctSpawns);
}
if (zoneManager != null) {
if (includeAuto)
result.AddRange(zoneManager
.GetZones(Server.MapName, ZoneType.SPAWN_AUTO)
.GetAwaiter()
.GetResult()
.Select(z => z.GetCenterPoint()));
var zones = zoneManager.GetZones(Server.MapName, ZoneType.SPAWN)
.GetAwaiter()
.GetResult();
result.AddRange(zones.Select(z => z.GetCenterPoint()));
}
result.Shuffle();
return result;
}
}
public enum Sensitivity {

View File

@@ -0,0 +1,52 @@
[Flags]
public enum WeaponType {
GRENADE = 1 << 0, // 1
UTILITY = 1 << 1, // 2
WEAPON = 1 << 2, // 4
SNIPERS = 1 << 3, // 8
RIFLES = 1 << 4, // 16
PISTOLS = 1 << 5, // 32
SHOTGUNS = 1 << 6, // 64
SMGS = 1 << 7, // 128
HEAVY = 1 << 8, // 256
GUNS = 1 << 9 // 512
}
public static class WeaponTypeExtensions {
public static IReadOnlySet<string> GetItems(this WeaponType type) {
var result = new HashSet<string>();
foreach (var t in Enum.GetValues<WeaponType>())
if (type.HasFlag(t))
result.UnionWith(t.GetItems());
switch (type) {
case WeaponType.GUNS:
return Tag.GUNS;
case WeaponType.HEAVY:
return Tag.HEAVY;
case WeaponType.SMGS:
return Tag.SMGS;
case WeaponType.SHOTGUNS:
return Tag.SHOTGUNS;
case WeaponType.PISTOLS:
return Tag.PISTOLS;
case WeaponType.RIFLES:
return Tag.RIFLES;
case WeaponType.SNIPERS:
return Tag.SNIPERS;
case WeaponType.UTILITY:
return Tag.UTILITY;
case WeaponType.GRENADE:
return Tag.GRENADES;
case WeaponType.WEAPON:
return Tag.WEAPONS;
default:
foreach (var t in Enum.GetValues<WeaponType>())
if (type.HasFlag(t))
result.UnionWith(t.GetItems());
return result;
}
}
}

View File

@@ -3,23 +3,8 @@
namespace Jailbreak.Validator;
public class ItemValidator(
ItemValidator.WeaponType type = ItemValidator.WeaponType.WEAPON
| ItemValidator.WeaponType.UTILITY, bool allowEmpty = true,
bool allowMultiple = false) : IValidator<string> {
[Flags]
public enum WeaponType {
GRENADE = 1 << 0, // 1
UTILITY = 1 << 1, // 2
WEAPON = 1 << 2, // 4
SNIPERS = 1 << 3, // 8
RIFLES = 1 << 4, // 16
PISTOLS = 1 << 5, // 32
SHOTGUNS = 1 << 6, // 64
SMGS = 1 << 7, // 128
HEAVY = 1 << 8, // 256
GUNS = 1 << 9 // 512
}
WeaponType type = WeaponType.WEAPON | WeaponType.UTILITY,
bool allowEmpty = true, bool allowMultiple = false) : IValidator<string> {
public bool Validate(string value, out string? errorMessage) {
if (value.Contains(',') && !allowMultiple) {
errorMessage = "Value cannot contain multiple values";
@@ -42,29 +27,10 @@ public class ItemValidator(
}
errorMessage = $"invalid {type.ToString()}: {weapon}";
return Enum.GetValues<WeaponType>()
.Where(t => type.HasFlag(t))
.Any(t => validateType(t, weapon));
return type.GetItems().Contains(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;
}
}

View File

@@ -61,6 +61,7 @@
<ProjectReference Include="..\..\mod\Jailbreak.LastRequest\Jailbreak.LastRequest.csproj"/>
<ProjectReference Include="..\..\mod\Jailbreak.Mute\Jailbreak.Mute.csproj"/>
<ProjectReference Include="..\..\mod\Jailbreak.LastGuard\Jailbreak.LastGuard.csproj"/>
<ProjectReference Include="..\..\mod\Jailbreak.RTD\Jailbreak.RTD.csproj"/>
<ProjectReference Include="..\..\mod\Jailbreak.SpecialDay\Jailbreak.SpecialDay.csproj"/>
<ProjectReference Include="..\..\mod\Jailbreak.Warden\Jailbreak.Warden.csproj"/>
<ProjectReference Include="..\..\mod\Jailbreak.Rebel\Jailbreak.Rebel.csproj"/>

View File

@@ -6,6 +6,7 @@ using Jailbreak.English.LastRequest;
using Jailbreak.English.Logs;
using Jailbreak.English.Mute;
using Jailbreak.English.Rebel;
using Jailbreak.English.RTD;
using Jailbreak.English.SpecialDay;
using Jailbreak.English.Warden;
using Jailbreak.Formatting.Views;
@@ -18,6 +19,7 @@ using Jailbreak.LastRequest;
using Jailbreak.Logs;
using Jailbreak.Mute;
using Jailbreak.Rebel;
using Jailbreak.RTD;
using Jailbreak.SpecialDay;
using Jailbreak.Warden;
using Jailbreak.Zones;
@@ -47,6 +49,7 @@ public class JailbreakServiceCollection : IPluginServiceCollection<Jailbreak> {
serviceCollection.AddSingleton<IWardenLocale, WardenLocale>();
serviceCollection.AddSingleton<IWardenPeaceLocale, WardenPeaceLocale>();
serviceCollection.AddSingleton<IWardenSTLocale, WardenSTLocale>();
serviceCollection.AddSingleton<IRTDLocale, RTDLocale>();
// Do we want to make this scoped?
// Not sure how this will behave with multiple rounds and whatnot.
@@ -60,5 +63,6 @@ public class JailbreakServiceCollection : IPluginServiceCollection<Jailbreak> {
serviceCollection.AddJailbreakLastGuard();
serviceCollection.AddJailbreakSpecialDay();
serviceCollection.AddJailbreakZones();
serviceCollection.AddDiceRoll();
}
}