From 167be3cd5399b3baa8df57caba5e58f7545bcaf8 Mon Sep 17 00:00:00 2001 From: Aidenkrz Date: Sat, 21 Dec 2024 21:06:43 -0600 Subject: [PATCH 1/6] Creeper, aw man. --- .../UserInterface/SSSStatusUIController.cs | 5 + .../SuspicionRuleSystem.CVars.cs | 4 + .../SuspicionRuleSystem.Rules.cs | 19 ++- .../SuspicionRuleSystem.Spawning.cs | 125 ++++++++++++++++-- .../SuspicionRuleSystem.Utility.cs | 45 ++++++- .../SuspicionGameRule/SuspicionRuleSystem.cs | 28 +++- Content.Shared/_SSS/CCvar/CCVars.SSS.cs | 11 ++ .../Components/SuspicionRoleComponent.cs | 10 ++ .../SuspicionGameRule/SuspicionRuleEvents.cs | 3 +- Resources/Locale/en-US/_SSS/suspicion.ftl | 7 +- 10 files changed, 237 insertions(+), 20 deletions(-) diff --git a/Content.Client/_SSS/UserInterface/SSSStatusUIController.cs b/Content.Client/_SSS/UserInterface/SSSStatusUIController.cs index 474e9bc431..c21eba8986 100644 --- a/Content.Client/_SSS/UserInterface/SSSStatusUIController.cs +++ b/Content.Client/_SSS/UserInterface/SSSStatusUIController.cs @@ -197,6 +197,11 @@ public void UpdateRoleDisplay(SuspicionRuleUpdateRole ev, EntitySessionEventArgs SuspicionRole.Traitor => "roles-antag-suspicion-traitor-name", SuspicionRole.Detective => "roles-antag-suspicion-detective-name", SuspicionRole.Innocent => "roles-antag-suspicion-innocent-name", + SuspicionRole.Wildcard => ev.NewSubRole switch + { + SuspicionSubRole.Jester => "roles-antag-suspicion-jester-name", + _ => "roles-antag-suspicion-wildcard-unknown", + }, _ => "roles-antag-suspicion-unknown", }); SetRoleUI(roleName, Color.FromName(ev.NewRole.GetRoleColor())); diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.CVars.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.CVars.cs index 871d1797fb..1a5f9f05f7 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.CVars.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.CVars.cs @@ -8,6 +8,8 @@ private void InitializeCVars() { Subs.CVar(_cfg, CCVars.SSSTraitorPercentage, f => _traitorPercentage = f, true); Subs.CVar(_cfg, CCVars.SSSDetectivePercentage, f => _detectivePercentage = f, true); + Subs.CVar(_cfg, CCVars.SSSWildcardPercentage, f => _wildcardPercentage = f, true); + Subs.CVar(_cfg, CCVars.SSSWildcardChance, f => _wildcardChance = f, true); Subs.CVar(_cfg, CCVars.SSSPreparingDuration, i => _preparingDuration = i, true); Subs.CVar(_cfg, CCVars.SSSRoundDuration, i => _roundDuration = i, true); Subs.CVar(_cfg, CCVars.SSSTimeAddedPerKill, i => _timeAddedPerKill = i, true); @@ -16,6 +18,8 @@ private void InitializeCVars() private float _traitorPercentage = 0.25f; private float _detectivePercentage = 0.25f; + private float _wildcardPercentage = 0.15f; + private float _wildcardChance = 0.3f; private int _preparingDuration = 30; private int _roundDuration = 480; private int _timeAddedPerKill = 30; diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Rules.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Rules.cs index 8ca528d381..532a721f04 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Rules.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Rules.cs @@ -76,6 +76,8 @@ private void OnMobStateChanged(EntityUid uid, SuspicionPlayerComponent component var allInnocents = FindAllOfType(SuspicionRole.Innocent); var allDetectives = FindAllOfType(SuspicionRole.Detective); + var allJestersAlive = FindAllOfType(SuspicionSubRole.Jester); + var allJesters = FindAllOfType(SuspicionSubRole.Jester, false); if (allInnocents.Count == 0 && allDetectives.Count == 0) { @@ -92,6 +94,15 @@ private void OnMobStateChanged(EntityUid uid, SuspicionPlayerComponent component _roundEndSystem.EndRound(TimeSpan.FromSeconds(sus.PostRoundDuration)); return; } + + if (allJesters != allJestersAlive) + { + _chatManager.DispatchServerAnnouncement("The jesters have won the round."); + sus.GameState = SuspicionGameState.PostRound; + _roundEndSystem.EndRound(TimeSpan.FromSeconds(sus.PostRoundDuration)); + return; + } + break; } } @@ -166,7 +177,7 @@ private void OnExamine(EntityUid uid, SuspicionPlayerComponent component, ref Ex EntityUid.Invalid, false, client: session.Channel, - recordReplay:true + recordReplay: true ); } } @@ -176,11 +187,13 @@ private void OnExamine(EntityUid uid, SuspicionPlayerComponent component, ref Ex } } + var victimRole = role.Value.Comp2.SubRole?.ToString() ?? role.Value.Comp2.Role.ToString(); + args.PushMarkup(Loc.GetString( "suspicion-examination", ("ent", args.Examined), ("col", role.Value.Comp2.Role.GetRoleColor()), - ("role", role.Value.Comp2.Role.ToString())), + ("role", victimRole)), -10); if (!HasComp(args.Examiner)) @@ -211,7 +224,7 @@ private void OnExamine(EntityUid uid, SuspicionPlayerComponent component, ref Ex ("found", args.Examined), ("where", _navMapSystem.GetNearestBeaconString(loc)), ("col", role.Value.Comp2.Role.GetRoleColor()), - ("role", role.Value.Comp2.Role.ToString())); + ("role", victimRole)); SendAnnouncement( msg ); diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs index faf0c6ee55..5994d19e0c 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs @@ -24,6 +24,7 @@ using Content.Shared.Players; using Content.Shared.Security.Components; using Robust.Shared.Prototypes; +using Content.Shared.CombatMode.Pacification; namespace Content.Server._SSS.SuspicionGameRule; @@ -39,6 +40,11 @@ private void OnGetBriefing(Entity role, ref GetBriefingE SuspicionRole.Traitor => Loc.GetString("roles-antag-suspicion-traitor-objective"), SuspicionRole.Detective => Loc.GetString("roles-antag-suspicion-detective-objective"), SuspicionRole.Innocent => Loc.GetString("roles-antag-suspicion-innocent-objective"), + SuspicionRole.Wildcard => role.Comp.SubRole switch + { + SuspicionSubRole.Jester => Loc.GetString("roles-antag-suspicion-jester-objective"), + _ => "roles-antag-suspicion-pending-objective", + }, _ => Loc.GetString("roles-antag-suspicion-pending-objective") }; } @@ -79,10 +85,13 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul _rejuvenate.PerformRejuvenate(ent.Value); } - var traitorCount = MathHelper.Clamp((int) (participatingPlayers.Count * _traitorPercentage), 1, allPlayerData.Count); - var detectiveCount = MathHelper.Clamp((int) (participatingPlayers.Count * _detectivePercentage), 1, allPlayerData.Count); + var traitorCount = MathHelper.Clamp((int)(participatingPlayers.Count * _traitorPercentage), 1, allPlayerData.Count); + var detectiveCount = MathHelper.Clamp((int)(participatingPlayers.Count * _detectivePercentage), 1, allPlayerData.Count); + var wildcardCount = 0; // Zero by default, we roll to see if wildcards will be in the next round in the next line. + if (RobustRandom.NextFloat() <= _wildcardChance) + wildcardCount = MathHelper.Clamp((int)(participatingPlayers.Count * _wildcardPercentage), 1, allPlayerData.Count); - if (traitorCount + detectiveCount > participatingPlayers.Count) + if (traitorCount + detectiveCount + wildcardCount > participatingPlayers.Count) { // we somehow have more picked players than valid @@ -90,18 +99,65 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul traitorCount = participatingPlayers.Count; detectiveCount = 0; + wildcardCount = 0; } + /* Simyon, I think the issue is you didnt make it random enough, so I made it more random for you! RobustRandom.Shuffle(participatingPlayers); // Shuffle the list so we can just take the first N players RobustRandom.Shuffle(participatingPlayers); RobustRandom.Shuffle(participatingPlayers); // I don't trust the shuffle. RobustRandom.Shuffle(participatingPlayers); RobustRandom.Shuffle(participatingPlayers); // I really don't trust the shuffle. + */ + + int seed1 = (int)(Math.Sin(RobustRandom.Next()) * 10000); + int seed2 = (int)(Math.Cos(RobustRandom.Next()) * 10000); + int combinedSeed = seed1 ^ seed2; + + RobustRandom.SetSeed(combinedSeed); + + int depth = 5; + while (depth > 0) + { + int chaoticSeed = (int)Math.Pow(RobustRandom.Next(), 3) ^ (RobustRandom.Next() % 10000); + RobustRandom.SetSeed(chaoticSeed); + + int halfCount = participatingPlayers.Count / 2; + var shuffledSubset = participatingPlayers.Take(halfCount).ToList(); + RobustRandom.Shuffle(shuffledSubset); + participatingPlayers.RemoveRange(0, halfCount); + participatingPlayers.AddRange(shuffledSubset); + + depth--; + } + + RobustRandom.SetSeed(RobustRandom.Next()); + RobustRandom.Shuffle(participatingPlayers); + + RobustRandom.SetSeed(RobustRandom.Next()); + RobustRandom.Shuffle(participatingPlayers); + + var shuffledIndices = participatingPlayers + .Select((_, i) => (Index: i, Value: RobustRandom.Next())) + .OrderBy(tuple => tuple.Value) + .Select(tuple => tuple.Index) + .ToList(); + + var reorderedPlayers = shuffledIndices.Select(i => participatingPlayers[i]).ToList(); + participatingPlayers.Clear(); + participatingPlayers.AddRange(reorderedPlayers); + + for (int i = 0; i < 3; i++) + { + RobustRandom.SetSeed(RobustRandom.Next()); + RobustRandom.Shuffle(participatingPlayers); + } + // I hope thats random enough! for (var i = 0; i < traitorCount; i++) { - var role = participatingPlayers[i]; + var role = participatingPlayers[RobustRandom.Next(participatingPlayers.Count)]; role.comp.Role = SuspicionRole.Traitor; var ownedEntity = Comp(role.mind).OwnedEntity; if (!ownedEntity.HasValue) @@ -118,7 +174,7 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul _npcFactionSystem.AddFaction(ownedEntity.Value, component.TraitorFaction); - _subdermalImplant.AddImplants(ownedEntity.Value, new List {component.UplinkImplant}); // Why does this method only take in a list??? + _subdermalImplant.AddImplants(ownedEntity.Value, new List { component.UplinkImplant }); // Why does this method only take in a list??? _antagSelectionSystem.SendBriefing( ownedEntity.Value, @@ -127,11 +183,12 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul _traitorStartSound); RaiseNetworkEvent(new SuspicionRuleUpdateRole(SuspicionRole.Traitor), ownedEntity.Value); + participatingPlayers.Remove(role); } - for (var i = traitorCount; i < traitorCount + detectiveCount; i++) + for (var i = 0; i < detectiveCount; i++) { - var role = participatingPlayers[i]; + var role = participatingPlayers[RobustRandom.Next(participatingPlayers.Count)]; role.comp.Role = SuspicionRole.Detective; var ownedEntity = Comp(role.mind).OwnedEntity; if (!ownedEntity.HasValue) @@ -144,14 +201,62 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul AddKeyToRadio(ownedEntity.Value, component.DetectiveRadio); - _subdermalImplant.AddImplants(ownedEntity.Value, new List {component.DetectiveImplant}); + _subdermalImplant.AddImplants(ownedEntity.Value, new List { component.DetectiveImplant }); _antagSelectionSystem.SendBriefing( ownedEntity.Value, Loc.GetString("detective-briefing"), Color.LightBlue, - briefingSound:null); + briefingSound: null); RaiseNetworkEvent(new SuspicionRuleUpdateRole(SuspicionRole.Detective), ownedEntity.Value); + participatingPlayers.Remove(role); + } + + var wildcardRoles = new List + { + SuspicionSubRole.Jester + }; + + for (var i = 0; i < wildcardCount; i++) + { + var role = participatingPlayers[RobustRandom.Next(participatingPlayers.Count)]; + + var selectedSubRole = wildcardRoles[RobustRandom.Next(wildcardRoles.Count)]; + + role.comp.Role = SuspicionRole.Wildcard; + role.comp.SubRole = selectedSubRole; + + string briefingText = selectedSubRole switch + { + SuspicionSubRole.Jester => Loc.GetString("jester-briefing"), + _ => Loc.GetString("wildcard-briefing") + }; + + var ownedEntity = Comp(role.mind).OwnedEntity; + if (!ownedEntity.HasValue) + { + Log.Error("Player mind has no entity."); + continue; + } + + switch (selectedSubRole) + { + case SuspicionSubRole.Jester: + { + EnsureComp(ownedEntity.Value); + break; + } + } + + _antagSelectionSystem.SendBriefing( + ownedEntity.Value, + briefingText, + Color.LightPink, + briefingSound: null); + + RaiseNetworkEvent(new SuspicionRuleUpdateRole(SuspicionRole.Wildcard, selectedSubRole), ownedEntity.Value); + + participatingPlayers.Remove(role); } // Anyone who isn't a traitor will get the innocent role. @@ -169,7 +274,7 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul ownedEntity.Value, Loc.GetString("innocent-briefing"), briefingColor: Color.Green, - briefingSound:null); + briefingSound: null); RaiseNetworkEvent(new SuspicionRuleUpdateRole(SuspicionRole.Innocent), ownedEntity.Value); } diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Utility.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Utility.cs index b07bbe6e4c..1face71ddf 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Utility.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Utility.cs @@ -85,7 +85,7 @@ private void AddTcToPlayer(EntityUid player, int amount, bool displayMessage = t /// private List<(EntityUid body, Entity sus)> FindAllOfType(SuspicionRole role, bool filterDead = true) { - var allMinds = new HashSet>(); + var allMinds = new HashSet>(); if (filterDead) { allMinds = _mindSystem.GetAliveHumans(); @@ -123,6 +123,49 @@ private void AddTcToPlayer(EntityUid player, int amount, bool displayMessage = t return result; } + /// + /// Finds all players with a specific sub-role. + /// + private List<(EntityUid body, Entity sus)> FindAllOfType(SuspicionSubRole subRole, bool filterDead = true) + { + var allMinds = new HashSet>(); + if (filterDead) + { + allMinds = _mindSystem.GetAliveHumans(); + } + else + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _)) + { + if (!_mindSystem.TryGetMind(uid, out var mind, out var mindComp)) + continue; + + allMinds.Add(new Entity(mind, mindComp)); + } + } + + var result = new List<(EntityUid body, Entity)>(); + foreach (var mind in allMinds) + { + var nullableMind = new Entity(mind.Owner, mind.Comp); // Following the pattern from the original method. + + if (!_roleSystem.MindHasRole(nullableMind, out var roleComp)) + continue; + + if (roleComp.Value.Comp2.SubRole != subRole) + continue; + + var entity = Comp(mind).OwnedEntity; + if (!entity.HasValue) + continue; + + result.Add((entity.Value, roleComp.Value)); + } + + return result; + } + public void DropAllItemsOnEntity(EntityUid entity) { if (!TryComp(entity, out InventoryComponent? inventory)) diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.cs index 438adb286d..41c811fd38 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.cs @@ -95,10 +95,14 @@ protected override void AppendRoundEndText(EntityUid uid, var traitors = FindAllOfType(SuspicionRole.Traitor, false); var innocents = FindAllOfType(SuspicionRole.Innocent, false); var detectives = FindAllOfType(SuspicionRole.Detective, false); + var wildcards = FindAllOfType(SuspicionRole.Wildcard, false); + var jesters = FindAllOfType(SuspicionSubRole.Jester, false); var traitorsOnlyAlive = FindAllOfType(SuspicionRole.Traitor); var innocentsOnlyAlive = FindAllOfType(SuspicionRole.Innocent); var detectivesOnlyAlive = FindAllOfType(SuspicionRole.Detective); + var wildcardsOnlyAlive = FindAllOfType(SuspicionRole.Wildcard); + var jestersOnlyAlive = FindAllOfType(SuspicionSubRole.Jester); void Append(List people, ref RoundEndTextAppendEvent args) { @@ -113,8 +117,22 @@ void Append(List people, ref RoundEndTextAppendEvent args) } } - var victory = innocentsOnlyAlive.Count + detectivesOnlyAlive.Count == 0 ? "Traitors" : "Innocents"; - // Traitors win if there are no innocents or detectives left. + string victory; + + switch (true) + { + case var _ when jestersOnlyAlive.Count != jesters.Count: + victory = "Jesters"; + break; + + case var _ when innocentsOnlyAlive.Count + detectivesOnlyAlive.Count == 0: + victory = "Traitors"; + break; + + default: + victory = "Innocents"; + break; + } args.AddLine($"[bold]{victory}[/bold] have won the round."); @@ -124,6 +142,8 @@ void Append(List people, ref RoundEndTextAppendEvent args) Append(innocents.Select(t => t.body).ToList(), ref args); args.AddLine($"[color=blue][bold]Detectives[/bold][/color]: {detectives.Count}"); Append(detectives.Select(t => t.body).ToList(), ref args); + args.AddLine($"[color=pink][bold]Wildcards[/bold][/color]: {wildcards.Count}"); + Append(wildcards.Select(t => t.body).ToList(), ref args); } @@ -133,8 +153,8 @@ protected override void Started(EntityUid uid, SuspicionRuleComponent component, component.GameState = SuspicionGameState.Preparing; - Timer.Spawn(TimeSpan.FromSeconds(_preparingDuration - 5), () => _chatManager.DispatchServerAnnouncement("The round will start in 5 seconds.")); - Timer.Spawn(TimeSpan.FromSeconds(_preparingDuration), () => StartRound(uid, component, gameRule)); + Timer.Spawn(TimeSpan.FromSeconds(_preparingDuration - 5), () => _chatManager.DispatchServerAnnouncement("The round will start in 5 seconds.")); + Timer.Spawn(TimeSpan.FromSeconds(_preparingDuration), () => StartRound(uid, component, gameRule)); Log.Debug("Starting a game of Suspicion."); RaiseNetworkEvent(new SuspicionRulePreroundStarted(TimeSpan.FromSeconds(_preparingDuration))); diff --git a/Content.Shared/_SSS/CCvar/CCVars.SSS.cs b/Content.Shared/_SSS/CCvar/CCVars.SSS.cs index 3384b6d436..f8aa36840a 100644 --- a/Content.Shared/_SSS/CCvar/CCVars.SSS.cs +++ b/Content.Shared/_SSS/CCvar/CCVars.SSS.cs @@ -20,6 +20,17 @@ public sealed partial class CCVars CVarDef.Create("sss.detective_percentage", 0.25f, CVar.SERVERONLY); /// + /// Percentage of total players that will be a wildcard role. Handled similar to traitor percentage (rounded down etc). + /// + public static readonly CVarDef SSSWildcardPercentage = + CVarDef.Create("sss.wildcard_percentage", 0.15f, CVar.SERVERONLY); + + /// + /// Chance a round will include wildcard roles. + /// + public static readonly CVarDef SSSWildcardChance = + CVarDef.Create("sss.wildcard_chance", 0.3f, CVar.SERVERONLY); + /// /// How long to wait before the game starts after the round starts. /// public static readonly CVarDef SSSPreparingDuration = diff --git a/Content.Shared/_SSS/SuspicionGameRule/Components/SuspicionRoleComponent.cs b/Content.Shared/_SSS/SuspicionGameRule/Components/SuspicionRoleComponent.cs index fb6d4ce15a..38f1f0a2ee 100644 --- a/Content.Shared/_SSS/SuspicionGameRule/Components/SuspicionRoleComponent.cs +++ b/Content.Shared/_SSS/SuspicionGameRule/Components/SuspicionRoleComponent.cs @@ -8,6 +8,8 @@ public sealed partial class SuspicionRoleComponent : BaseMindRoleComponent { [ViewVariables] public SuspicionRole Role { get; set; } = SuspicionRole.Pending; + [ViewVariables] + public SuspicionSubRole? SubRole { get; set; } = null; } public static class SusRoleExtensions @@ -19,6 +21,7 @@ public static string GetRoleColor(this SuspicionRole role) SuspicionRole.Traitor => "red", SuspicionRole.Detective => "blue", SuspicionRole.Innocent => "green", + SuspicionRole.Wildcard => "pink", _ => "white", }; } @@ -32,4 +35,11 @@ public enum SuspicionRole Traitor, Detective, Innocent, + Wildcard, +} + +[Serializable, NetSerializable] +public enum SuspicionSubRole +{ + Jester, } diff --git a/Content.Shared/_SSS/SuspicionGameRule/SuspicionRuleEvents.cs b/Content.Shared/_SSS/SuspicionGameRule/SuspicionRuleEvents.cs index dba69bbf74..3bd4e32c88 100644 --- a/Content.Shared/_SSS/SuspicionGameRule/SuspicionRuleEvents.cs +++ b/Content.Shared/_SSS/SuspicionGameRule/SuspicionRuleEvents.cs @@ -17,9 +17,10 @@ public sealed class SuspicionRulePreroundStarted(TimeSpan preroundEndTime) : Ent } [Serializable, NetSerializable] -public sealed class SuspicionRuleUpdateRole(SuspicionRole newRole) : EntityEventArgs +public sealed class SuspicionRuleUpdateRole(SuspicionRole newRole, SuspicionSubRole? newSubRole = null) : EntityEventArgs { public readonly SuspicionRole NewRole = newRole; + public readonly SuspicionSubRole? NewSubRole = newSubRole; } [Serializable, NetSerializable] diff --git a/Resources/Locale/en-US/_SSS/suspicion.ftl b/Resources/Locale/en-US/_SSS/suspicion.ftl index f8337cf629..5eac8ad676 100644 --- a/Resources/Locale/en-US/_SSS/suspicion.ftl +++ b/Resources/Locale/en-US/_SSS/suspicion.ftl @@ -1,6 +1,8 @@ traitor-briefing = You are a traitor. Your goal is to [bold]kill[/bold] the other crew members while making sure your fellow traitors also surivive. Use your Syndicate radio to communicate with your fellow traitors. innocent-briefing = You are an innocent. Your goal is to [bold]survive[/bold] and to [bold]kill[/bold] the traitors while keeping your fellow crew alive. Good luck. detective-briefing = You are a detective. Your goal is to [bold]survive[/bold] and to [bold]kill[/bold] the traitors while keeping your fellow crew alive. Good luck. +jester-briefing = You are a jester. Your goal is to [bold]die[/bold] by the hands of your fellow crew. Good luck. +wildcard-briefing = You are an... unspecified wildcard role? Something fucked up badly for you to see this, so report it and do whatever you want I guess. suspicion-traitor-uplink = Traitor Uplink suspicion-detective-uplink = Detective Uplink tc-added-sus = You have been given {$tc} TC for your performance. @@ -14,9 +16,12 @@ roles-antag-suspicion-pending-name = Pending roles-antag-suspicion-pending-objective = The game is still starting, wait for your role to be assigned. roles-antag-suspicion-detective-name = Detective roles-antag-suspicion-detective-objective = Discover and eliminate all traitors with your special tools. +roles-antag-suspicion-jester-name = Jester +roles-antag-suspicion-jester-objective = Die at the hands of your fellow crew. +roles-antag-suspicion-wildcard-unknown = Wildcard roles-antag-suspicion-unknown = Unknown suspicion-status-ui-health-dead = DEAD -suspicion-status-ui-role-obserbing = Obserbing +suspicion-status-ui-role-obserbing = Spectating suspicion-status-ui-role-preround = Preround From f599697548b49412ae82388abcdefc9bdec4b022 Mon Sep 17 00:00:00 2001 From: Aidenkrz Date: Sat, 21 Dec 2024 23:46:52 -0600 Subject: [PATCH 2/6] Good enough --- .../SuspicionRuleSystem.Rules.cs | 29 ++++++++----- .../SuspicionRuleSystem.Spawning.cs | 9 +++- .../SuspicionRuleSystem.Utility.cs | 43 +++++++++++++++++-- .../SuspicionGameRule/SuspicionRuleSystem.cs | 2 + Resources/Locale/en-US/_SSS/suspicion.ftl | 4 +- 5 files changed, 70 insertions(+), 17 deletions(-) diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Rules.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Rules.cs index 532a721f04..e89807fbf5 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Rules.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Rules.cs @@ -17,6 +17,7 @@ using Content.Shared.Mobs.Components; using Content.Shared.Overlays; using Content.Shared.Popups; +using Content.Server.KillTracking; namespace Content.Server._SSS.SuspicionGameRule; @@ -53,6 +54,10 @@ private void OnMobStateChanged(EntityUid uid, SuspicionPlayerComponent component DropAllItemsOnEntity(args.Target); + } + + private void OnKillReported(ref KillReportedEvent ev) + { var query = EntityQueryEnumerator(); while (query.MoveNext(out var ruleId, out var sus, out var gameRule)) { @@ -76,10 +81,9 @@ private void OnMobStateChanged(EntityUid uid, SuspicionPlayerComponent component var allInnocents = FindAllOfType(SuspicionRole.Innocent); var allDetectives = FindAllOfType(SuspicionRole.Detective); - var allJestersAlive = FindAllOfType(SuspicionSubRole.Jester); - var allJesters = FindAllOfType(SuspicionSubRole.Jester, false); + var allWildcards = FindAllOfType(SuspicionRole.Wildcard); - if (allInnocents.Count == 0 && allDetectives.Count == 0) + if (allInnocents.Count == 0 && allDetectives.Count == 0 && allWildcards.Count == 0) { _chatManager.DispatchServerAnnouncement("The traitors have won the round."); sus.GameState = SuspicionGameState.PostRound; @@ -95,13 +99,17 @@ private void OnMobStateChanged(EntityUid uid, SuspicionPlayerComponent component return; } - if (allJesters != allJestersAlive) - { - _chatManager.DispatchServerAnnouncement("The jesters have won the round."); - sus.GameState = SuspicionGameState.PostRound; - _roundEndSystem.EndRound(TimeSpan.FromSeconds(sus.PostRoundDuration)); - return; - } + if (ev.Primary is KillPlayerSource player && !ev.Suicide) + if (TrySusRole(ev.Entity, out var roleComp)) + if (roleComp.SubRole == SuspicionSubRole.Jester) + if (TrySusRole(player.PlayerId, out var attackerRoleComp)) + if (attackerRoleComp.Role == SuspicionRole.Innocent || attackerRoleComp.Role == SuspicionRole.Detective) + { + _chatManager.DispatchServerAnnouncement("The jesters have won the round."); + sus.GameState = SuspicionGameState.PostRound; + _roundEndSystem.EndRound(TimeSpan.FromSeconds(sus.PostRoundDuration)); + return; + } break; } @@ -229,7 +237,6 @@ private void OnExamine(EntityUid uid, SuspicionPlayerComponent component, ref Ex msg ); } - private void UpdateSpaceWalkDamage(ref SuspicionRuleComponent sus, float frameTime) { var query = EntityQueryEnumerator(); diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs index 5994d19e0c..d56c236934 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs @@ -25,6 +25,7 @@ using Content.Shared.Security.Components; using Robust.Shared.Prototypes; using Content.Shared.CombatMode.Pacification; +using Robust.Shared.Audio; namespace Content.Server._SSS.SuspicionGameRule; @@ -232,6 +233,12 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul _ => Loc.GetString("wildcard-briefing") }; + SoundPathSpecifier? briefingSound = selectedSubRole switch + { + SuspicionSubRole.Jester => new SoundPathSpecifier("/Audio/Voice/Cluwne/cluwnelaugh1.ogg"), + _ => null + }; + var ownedEntity = Comp(role.mind).OwnedEntity; if (!ownedEntity.HasValue) { @@ -252,7 +259,7 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul ownedEntity.Value, briefingText, Color.LightPink, - briefingSound: null); + briefingSound: briefingSound); RaiseNetworkEvent(new SuspicionRuleUpdateRole(SuspicionRole.Wildcard, selectedSubRole), ownedEntity.Value); diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Utility.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Utility.cs index 1face71ddf..11c6343fab 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Utility.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Utility.cs @@ -11,7 +11,8 @@ using Content.Shared.Store.Components; using Robust.Shared.Map; using Robust.Shared.Physics.Components; - +using Robust.Shared.Network; +using System.Diagnostics.CodeAnalysis; namespace Content.Server._SSS.SuspicionGameRule; public sealed partial class SuspicionRuleSystem @@ -80,6 +81,42 @@ private void AddTcToPlayer(EntityUid player, int amount, bool displayMessage = t return null; } + /// + /// Tries to find the SuspicionRoleComponent of a entity. + /// + private bool TrySusRole(EntityUid ent, [NotNullWhen(true)] out SuspicionRoleComponent? suspicionRole) + { + suspicionRole = null; + + if (!_mindSystem.TryGetMind(ent, out var mind, out var mindComp)) + return false; + + if (!_roleSystem.MindHasRole(mind, out var susRole)) + return false; + + suspicionRole = susRole; + return true; + } + + /// + /// Tries to find the SuspicionRoleComponent of a user. + /// + private bool TrySusRole(NetUserId userId, [NotNullWhen(true)] out SuspicionRoleComponent? suspicionRole) + { + suspicionRole = null; + + if (!_mindSystem.TryGetMind(userId, out var mind, out var mindComp) || mind == null) + return false; + + var nullableMind = new Entity(mind.Value, mindComp); + + if (!_roleSystem.MindHasRole(nullableMind, out var susRole)) + return false; + + suspicionRole = susRole; + return true; + } + /// /// Finds all players with a specific role. /// @@ -105,7 +142,7 @@ private void AddTcToPlayer(EntityUid player, int amount, bool displayMessage = t var result = new List<(EntityUid body, Entity)>(); foreach (var mind in allMinds) { - var nullableMind = new Entity(mind.Owner, mind.Comp); // I see your shitcode, and i raise you MORE shit code. + var nullableMind = new Entity(mind.Owner, mind.Comp); if (!_roleSystem.MindHasRole(nullableMind, out var roleComp)) continue; @@ -148,7 +185,7 @@ private void AddTcToPlayer(EntityUid player, int amount, bool displayMessage = t var result = new List<(EntityUid body, Entity)>(); foreach (var mind in allMinds) { - var nullableMind = new Entity(mind.Owner, mind.Comp); // Following the pattern from the original method. + var nullableMind = new Entity(mind.Owner, mind.Comp); if (!_roleSystem.MindHasRole(nullableMind, out var roleComp)) continue; diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.cs index 41c811fd38..24e24dbbc4 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.cs @@ -35,6 +35,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; +using Content.Server.KillTracking; namespace Content.Server._SSS.SuspicionGameRule; @@ -82,6 +83,7 @@ public override void Initialize() SubscribeLocalEvent(OnShuttleCall); SubscribeLocalEvent(OnGhost); // Map init just doesn't work?? SubscribeLocalEvent(OnApcInit); + SubscribeLocalEvent(OnKillReported); } diff --git a/Resources/Locale/en-US/_SSS/suspicion.ftl b/Resources/Locale/en-US/_SSS/suspicion.ftl index 5eac8ad676..277b27af9d 100644 --- a/Resources/Locale/en-US/_SSS/suspicion.ftl +++ b/Resources/Locale/en-US/_SSS/suspicion.ftl @@ -2,11 +2,11 @@ innocent-briefing = You are an innocent. Your goal is to [bold]survive[/bold] and to [bold]kill[/bold] the traitors while keeping your fellow crew alive. Good luck. detective-briefing = You are a detective. Your goal is to [bold]survive[/bold] and to [bold]kill[/bold] the traitors while keeping your fellow crew alive. Good luck. jester-briefing = You are a jester. Your goal is to [bold]die[/bold] by the hands of your fellow crew. Good luck. -wildcard-briefing = You are an... unspecified wildcard role? Something fucked up badly for you to see this, so report it and do whatever you want I guess. +wildcard-briefing = You are an... unspecified wildcard? Something fucked up badly for you to see this, so report it and do whatever you want I guess. suspicion-traitor-uplink = Traitor Uplink suspicion-detective-uplink = Detective Uplink tc-added-sus = You have been given {$tc} TC for your performance. -suspicion-examination = { SUBJECT($ent) } were [color={$col}]{ $role }[/color] +suspicion-examination = { SUBJECT($ent) } was a [color={$col}]{ $role }[/color]! suspicion-examination-chat = [italic]{ $finder }[/italic] found the body of [italic]{ $found }[/italic] { $where } and discovered { SUBJECT($found) } { CONJUGATE-BASIC($found, "were", "was") } { INDEFINITE($role) } [bold][color={ $col }]{ $role }[/color][/bold]. suspicion-found-tc = You found [bold]{$tc} TC[/bold] on the body. They have been added to your uplink. From 54d6d8c44435286947dfdf8965a41d834297600a Mon Sep 17 00:00:00 2001 From: Aiden Date: Sat, 21 Dec 2024 23:48:24 -0600 Subject: [PATCH 3/6] Update Resources/Locale/en-US/_SSS/suspicion.ftl Co-authored-by: Simon <63975668+Simyon264@users.noreply.github.com> --- Resources/Locale/en-US/_SSS/suspicion.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Locale/en-US/_SSS/suspicion.ftl b/Resources/Locale/en-US/_SSS/suspicion.ftl index 5eac8ad676..44359fabcb 100644 --- a/Resources/Locale/en-US/_SSS/suspicion.ftl +++ b/Resources/Locale/en-US/_SSS/suspicion.ftl @@ -17,7 +17,7 @@ roles-antag-suspicion-pending-objective = The game is still starting, wait for y roles-antag-suspicion-detective-name = Detective roles-antag-suspicion-detective-objective = Discover and eliminate all traitors with your special tools. roles-antag-suspicion-jester-name = Jester -roles-antag-suspicion-jester-objective = Die at the hands of your fellow crew. +roles-antag-suspicion-jester-objective = Die by the hands of the crew. roles-antag-suspicion-wildcard-unknown = Wildcard roles-antag-suspicion-unknown = Unknown From e95cedc1d88852008b1931f2bc8e5d1a9016a3c3 Mon Sep 17 00:00:00 2001 From: Aidenkrz Date: Sat, 21 Dec 2024 23:54:35 -0600 Subject: [PATCH 4/6] millions must var --- .../SuspicionRuleSystem.Spawning.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs index d56c236934..85e9357ef9 100644 --- a/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs +++ b/Content.Server/_SSS/SuspicionGameRule/SuspicionRuleSystem.Spawning.cs @@ -111,19 +111,19 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul RobustRandom.Shuffle(participatingPlayers); // I really don't trust the shuffle. */ - int seed1 = (int)(Math.Sin(RobustRandom.Next()) * 10000); - int seed2 = (int)(Math.Cos(RobustRandom.Next()) * 10000); - int combinedSeed = seed1 ^ seed2; + var seed1 = (int)(Math.Sin(RobustRandom.Next()) * 10000); + var seed2 = (int)(Math.Cos(RobustRandom.Next()) * 10000); + var combinedSeed = seed1 ^ seed2; RobustRandom.SetSeed(combinedSeed); - int depth = 5; + var depth = 5; while (depth > 0) { - int chaoticSeed = (int)Math.Pow(RobustRandom.Next(), 3) ^ (RobustRandom.Next() % 10000); + var chaoticSeed = (int)Math.Pow(RobustRandom.Next(), 3) ^ (RobustRandom.Next() % 10000); RobustRandom.SetSeed(chaoticSeed); - int halfCount = participatingPlayers.Count / 2; + var halfCount = participatingPlayers.Count / 2; var shuffledSubset = participatingPlayers.Take(halfCount).ToList(); RobustRandom.Shuffle(shuffledSubset); participatingPlayers.RemoveRange(0, halfCount); @@ -148,7 +148,7 @@ private void StartRound(EntityUid uid, SuspicionRuleComponent component, GameRul participatingPlayers.Clear(); participatingPlayers.AddRange(reorderedPlayers); - for (int i = 0; i < 3; i++) + for (var i = 0; i < 3; i++) { RobustRandom.SetSeed(RobustRandom.Next()); RobustRandom.Shuffle(participatingPlayers); From 2fe4b88930e3e42a6d87c22672d935849854abb7 Mon Sep 17 00:00:00 2001 From: Aiden Date: Sat, 21 Dec 2024 23:55:51 -0600 Subject: [PATCH 5/6] Update Resources/Locale/en-US/_SSS/suspicion.ftl Co-authored-by: Simon <63975668+Simyon264@users.noreply.github.com> --- Resources/Locale/en-US/_SSS/suspicion.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Locale/en-US/_SSS/suspicion.ftl b/Resources/Locale/en-US/_SSS/suspicion.ftl index eecd262cd0..e7d373d456 100644 --- a/Resources/Locale/en-US/_SSS/suspicion.ftl +++ b/Resources/Locale/en-US/_SSS/suspicion.ftl @@ -1,7 +1,7 @@ traitor-briefing = You are a traitor. Your goal is to [bold]kill[/bold] the other crew members while making sure your fellow traitors also surivive. Use your Syndicate radio to communicate with your fellow traitors. innocent-briefing = You are an innocent. Your goal is to [bold]survive[/bold] and to [bold]kill[/bold] the traitors while keeping your fellow crew alive. Good luck. detective-briefing = You are a detective. Your goal is to [bold]survive[/bold] and to [bold]kill[/bold] the traitors while keeping your fellow crew alive. Good luck. -jester-briefing = You are a jester. Your goal is to [bold]die[/bold] by the hands of your fellow crew. Good luck. +jester-briefing = You are a jester. Your goal is to [bold]die[/bold] by the hands of the crew. Good luck. wildcard-briefing = You are an... unspecified wildcard? Something fucked up badly for you to see this, so report it and do whatever you want I guess. suspicion-traitor-uplink = Traitor Uplink suspicion-detective-uplink = Detective Uplink From 46d587401454eb5129e6dcce7858a936967ecfb5 Mon Sep 17 00:00:00 2001 From: Aidenkrz Date: Sat, 21 Dec 2024 23:59:58 -0600 Subject: [PATCH 6/6] idk --- .../SuspicionGameRule/Components/SuspicionRoleComponent.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Content.Shared/_SSS/SuspicionGameRule/Components/SuspicionRoleComponent.cs b/Content.Shared/_SSS/SuspicionGameRule/Components/SuspicionRoleComponent.cs index 38f1f0a2ee..eeb09b04f3 100644 --- a/Content.Shared/_SSS/SuspicionGameRule/Components/SuspicionRoleComponent.cs +++ b/Content.Shared/_SSS/SuspicionGameRule/Components/SuspicionRoleComponent.cs @@ -8,6 +8,9 @@ public sealed partial class SuspicionRoleComponent : BaseMindRoleComponent { [ViewVariables] public SuspicionRole Role { get; set; } = SuspicionRole.Pending; + /// + /// SubRole of the normal role, lets you specialize a role more if you want. If null everything just uses the normal Role definition. + /// [ViewVariables] public SuspicionSubRole? SubRole { get; set; } = null; }