diff --git a/Jailbreak.sln b/Jailbreak.sln
index 9570efb8..30f97c74 100644
--- a/Jailbreak.sln
+++ b/Jailbreak.sln
@@ -22,6 +22,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lang", "lang", "{CDCDE44E-0
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.English", "lang\Jailbreak.English\Jailbreak.English.csproj", "{FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Rebel", "mod\Jailbreak.Rebel\Jailbreak.Rebel.csproj", "{CB2391A1-6CDD-496F-B8D6-674FD6268038}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -56,6 +58,10 @@ Global
{FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CB2391A1-6CDD-496F-B8D6-674FD6268038}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CB2391A1-6CDD-496F-B8D6-674FD6268038}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CB2391A1-6CDD-496F-B8D6-674FD6268038}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CB2391A1-6CDD-496F-B8D6-674FD6268038}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9135CCC9-66C5-4A9C-AE3C-91475B5F0437} = {177DA48D-8306-4102-918D-992569878581}
@@ -65,5 +71,6 @@ Global
{28EE05E4-8FE3-4CC6-AA03-0C533EFBFBF2} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7}
{446E0B6F-E4FE-45E6-BD9B-BD943698327A} = {59311734-3648-43C2-B43C-385718B0D103}
{FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF} = {CDCDE44E-01D2-4B76-99DA-A57E1E956038}
+ {CB2391A1-6CDD-496F-B8D6-674FD6268038} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7}
EndGlobalSection
EndGlobal
diff --git a/mod/Jailbreak.Rebel/Jailbreak.Rebel.csproj b/mod/Jailbreak.Rebel/Jailbreak.Rebel.csproj
new file mode 100644
index 00000000..128ff34e
--- /dev/null
+++ b/mod/Jailbreak.Rebel/Jailbreak.Rebel.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/mod/Jailbreak.Rebel/RebelListener.cs b/mod/Jailbreak.Rebel/RebelListener.cs
new file mode 100644
index 00000000..a8f82b8b
--- /dev/null
+++ b/mod/Jailbreak.Rebel/RebelListener.cs
@@ -0,0 +1,41 @@
+using CounterStrikeSharp.API.Core;
+using CounterStrikeSharp.API.Modules.Utils;
+using Jailbreak.Public.Behaviors;
+using Jailbreak.Public.Extensions;
+using Jailbreak.Public.Mod.Rebel;
+
+namespace Jailbreak.Teams;
+
+public class RebelListener : IPluginBehavior
+{
+ private IRebelService _rebelService;
+
+ public RebelListener(IRebelService rebelService)
+ {
+ _rebelService = rebelService;
+ }
+
+ public void Start(BasePlugin parent)
+ {
+ parent.RegisterEventHandler(OnPlayerHurt);
+ }
+
+ HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info)
+ {
+ var player = @event.Userid;
+ if (!player.IsValid)
+ return HookResult.Continue;
+ if (player.GetTeam() != CsTeam.CounterTerrorist)
+ return HookResult.Continue;
+
+ var attacker = @event.Attacker;
+ if (!attacker.IsValid)
+ return HookResult.Continue;
+
+ if (attacker.GetTeam() != CsTeam.Terrorist)
+ return HookResult.Continue;
+
+ _rebelService.MarkRebel(attacker, 120);
+ return HookResult.Continue;
+ }
+}
\ No newline at end of file
diff --git a/mod/Jailbreak.Rebel/RebelManager.cs b/mod/Jailbreak.Rebel/RebelManager.cs
new file mode 100644
index 00000000..15b46289
--- /dev/null
+++ b/mod/Jailbreak.Rebel/RebelManager.cs
@@ -0,0 +1,100 @@
+using System.Drawing;
+using CounterStrikeSharp.API.Core;
+using CounterStrikeSharp.API.Core.Attributes.Registration;
+using Jailbreak.Public.Behaviors;
+using Jailbreak.Public.Mod.Rebel;
+
+namespace Jailbreak.Teams;
+
+public class RebelManager : IPluginBehavior, IRebelService
+{
+ private Dictionary rebelTimes = new();
+
+ public void Start(BasePlugin parent)
+ {
+ parent.RegisterEventHandler(OnPlayerDisconnect);
+
+ parent.AddTimer(1f, () =>
+ {
+ foreach (var player in GetActiveRebels())
+ {
+ if (!player.IsValid)
+ continue;
+
+ if (GetRebelTimeLeft(player) <= 0)
+ {
+ UnmarkRebel(player);
+ continue;
+ }
+
+ ApplyRebelColor(player);
+ }
+ });
+ }
+
+ HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
+ {
+ if (rebelTimes.ContainsKey(@event.Userid))
+ {
+ rebelTimes.Remove(@event.Userid);
+ }
+
+ return HookResult.Continue;
+ }
+
+ public ISet GetActiveRebels()
+ {
+ return rebelTimes.Keys.ToHashSet();
+ }
+
+ public float GetRebelTimeLeft(CCSPlayerController player)
+ {
+ if (rebelTimes.TryGetValue(player, out float time))
+ {
+ return time - DateTime.Now.Ticks / 1000f;
+ }
+
+ return 0;
+ }
+
+ public bool MarkRebel(CCSPlayerController player, float time)
+ {
+ rebelTimes.Add(player, DateTime.Now.Ticks / 1000f + time);
+ ApplyRebelColor(player);
+ return true;
+ }
+
+ public void UnmarkRebel(CCSPlayerController player)
+ {
+ player.PrintToChat("You are no longer a rebel");
+ rebelTimes.Remove(player);
+ ApplyRebelColor(player);
+ }
+
+ // https://www.desmos.com/calculator/g2v6vvg7ax
+ private float GetRebelTimePercentage(CCSPlayerController player)
+ {
+ float x = GetRebelTimeLeft(player);
+ if (x > 120)
+ return 1;
+ if (x <= 0)
+ return 0;
+ return (float)(100 - (120 - x) * (Math.Sqrt(120 - x)) / 13f) / 100;
+ }
+
+ private void ApplyRebelColor(CCSPlayerController player)
+ {
+ if (!player.IsValid || player.Pawn.Value == null)
+ return;
+ var percentage = GetRebelTimePercentage(player);
+ var inverse = 1 - percentage;
+ var inverseInt = (int)(inverse * 255);
+ var color = Color.FromArgb(254, (int)percentage * 255, inverseInt, inverseInt);
+ if (percentage <= 0)
+ {
+ color = Color.FromArgb(254, 255, 255, 255);
+ }
+
+ player.Pawn.Value.Render = color;
+ }
+}
\ No newline at end of file
diff --git a/mod/Jailbreak.Rebel/RebelServiceExtension.cs b/mod/Jailbreak.Rebel/RebelServiceExtension.cs
new file mode 100644
index 00000000..057552e1
--- /dev/null
+++ b/mod/Jailbreak.Rebel/RebelServiceExtension.cs
@@ -0,0 +1,16 @@
+using Jailbreak.Public.Extensions;
+using Jailbreak.Public.Mod.Rebel;
+using Jailbreak.Public.Mod.Teams;
+
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Jailbreak.Teams;
+
+public static class RebelServiceExtension
+{
+ public static void AddJailbreakRebel(this IServiceCollection collection)
+ {
+ collection.AddPluginBehavior();
+ collection.AddPluginBehavior();
+ }
+}
diff --git a/public/Jailbreak.Public/Mod/Rebel/IRebelService.cs b/public/Jailbreak.Public/Mod/Rebel/IRebelService.cs
new file mode 100644
index 00000000..f1fba6a5
--- /dev/null
+++ b/public/Jailbreak.Public/Mod/Rebel/IRebelService.cs
@@ -0,0 +1,19 @@
+using CounterStrikeSharp.API.Core;
+
+namespace Jailbreak.Public.Mod.Rebel;
+
+public interface IRebelService
+{
+ ISet GetActiveRebels();
+
+ bool IsRebel(CCSPlayerController player)
+ {
+ return GetRebelTimeLeft(player) > 0;
+ }
+
+ float GetRebelTimeLeft(CCSPlayerController player);
+
+ bool MarkRebel(CCSPlayerController player, float time);
+
+ void UnmarkRebel(CCSPlayerController player);
+}
\ No newline at end of file
diff --git a/src/Jailbreak/Jailbreak.csproj b/src/Jailbreak/Jailbreak.csproj
index 0a0c71f4..212d15e7 100644
--- a/src/Jailbreak/Jailbreak.csproj
+++ b/src/Jailbreak/Jailbreak.csproj
@@ -35,6 +35,7 @@
+
diff --git a/src/Jailbreak/JailbreakServiceCollection.cs b/src/Jailbreak/JailbreakServiceCollection.cs
index 30322612..4f70c9df 100644
--- a/src/Jailbreak/JailbreakServiceCollection.cs
+++ b/src/Jailbreak/JailbreakServiceCollection.cs
@@ -32,6 +32,7 @@ public void ConfigureServices(IServiceCollection serviceCollection)
serviceCollection.AddJailbreakGeneric();
serviceCollection.AddJailbreakWarden();
serviceCollection.AddJailbreakTeams();
+ serviceCollection.AddJailbreakRebel();
// Add in english localization
serviceCollection.AddLanguage(config =>