diff --git a/Content.Server/Antag/AntagSelectionPlayerPool.cs b/Content.Server/Antag/AntagSelectionPlayerPool.cs index 054292dcf9..87873e96d1 100644 --- a/Content.Server/Antag/AntagSelectionPlayerPool.cs +++ b/Content.Server/Antag/AntagSelectionPlayerPool.cs @@ -5,15 +5,13 @@ using Robust.Shared.Random; namespace Content.Server.Antag; -public sealed class AntagSelectionPlayerPool(params List[] sessions) +public sealed class AntagSelectionPlayerPool (List> orderedPools) { - private readonly List> _orderedPools = sessions.ToList(); - public bool TryPickAndTake(IRobustRandom random, [NotNullWhen(true)] out ICommonSession? session) { session = null; - foreach (var pool in _orderedPools) + foreach (var pool in orderedPools) { if (pool.Count == 0) continue; @@ -25,5 +23,5 @@ public sealed class AntagSelectionPlayerPool(params List[] sessi return session != null; } - public int Count => _orderedPools.Sum(p => p.Count); + public int Count => orderedPools.Sum(p => p.Count); } diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index eb68e077b1..6bfb7394f5 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -35,7 +35,6 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem + /// Tries to makes a given player into the specified antagonist. + /// + public bool TryMakeAntag(Entity ent, ICommonSession? session, AntagSelectionDefinition def, bool ignoreSpawner = false) + { + if (!IsSessionValid(ent, session, def) || + !IsEntityValid(session?.AttachedEntity, def)) + { + return false; + } + + MakeAntag(ent, session, def, ignoreSpawner); + return true; + } + /// /// Makes a given player into the specified antagonist. /// @@ -262,7 +277,6 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem public AntagSelectionPlayerPool GetPlayerPool(Entity ent, List sessions, AntagSelectionDefinition def) { - var primaryList = new List(); - var secondaryList = new List(); - var fallbackList = new List(); - var rawList = new List(); + var preferredList = new List(); + var secondBestList = new List(); + var unwantedList = new List(); + var invalidList = new List(); foreach (var session in sessions) { if (!IsSessionValid(ent, session, def) || !IsEntityValid(session.AttachedEntity, def)) { - rawList.Add(session); + invalidList.Add(session); continue; } var pref = (HumanoidCharacterProfile) _pref.GetPreferences(session.UserId).SelectedCharacter; - if (def.PrefRoles.Count == 0 || pref.AntagPreferences.Any(p => def.PrefRoles.Contains(p))) + if (def.PrefRoles.Count != 0 && pref.AntagPreferences.Any(p => def.PrefRoles.Contains(p))) { - primaryList.Add(session); + preferredList.Add(session); } - else if (def.PrefRoles.Count == 0 || pref.AntagPreferences.Any(p => def.FallbackRoles.Contains(p))) + else if (def.FallbackRoles.Count != 0 && pref.AntagPreferences.Any(p => def.FallbackRoles.Contains(p))) { - secondaryList.Add(session); + secondBestList.Add(session); } else { - fallbackList.Add(session); + unwantedList.Add(session); } } - return new AntagSelectionPlayerPool(primaryList, secondaryList, fallbackList, rawList); + return new AntagSelectionPlayerPool(new() { preferredList, secondBestList, unwantedList, invalidList }); } /// /// Checks if a given session is valid for an antagonist. /// - public bool IsSessionValid(Entity ent, ICommonSession session, AntagSelectionDefinition def, EntityUid? mind = null) + public bool IsSessionValid(Entity ent, ICommonSession? session, AntagSelectionDefinition def, EntityUid? mind = null) { + if (session == null) + return true; + mind ??= session.GetMind(); if (session.Status is SessionStatus.Disconnected or SessionStatus.Zombie) diff --git a/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs index ea5c9a830b..0db9d195dc 100644 --- a/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs @@ -71,5 +71,5 @@ public sealed partial class TraitorRuleComponent : Component public int StartingBalance = 20; [DataField] - public int MaxDifficulty = 20; + public int MaxDifficulty = 5; } diff --git a/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs b/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs index 4534333417..27a9edbad7 100644 --- a/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs +++ b/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs @@ -16,6 +16,14 @@ public abstract partial class GameRuleSystem where T: IComponent return EntityQueryEnumerator(); } + /// + /// Queries all gamerules, regardless of if they're active or not. + /// + protected EntityQueryEnumerator QueryAllRules() + { + return EntityQueryEnumerator(); + } + /// /// Utility function for finding a random event-eligible station entity /// diff --git a/Content.Server/GameTicking/Rules/GameRuleSystem.cs b/Content.Server/GameTicking/Rules/GameRuleSystem.cs index bcad146c22..c167ae7b6c 100644 --- a/Content.Server/GameTicking/Rules/GameRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/GameRuleSystem.cs @@ -34,8 +34,8 @@ public abstract partial class GameRuleSystem : EntitySystem where T : ICompon if (args.Forced || args.Cancelled) return; - var query = QueryActiveRules(); - while (query.MoveNext(out var uid, out _, out _, out var gameRule)) + var query = QueryAllRules(); + while (query.MoveNext(out var uid, out _, out var gameRule)) { var minPlayers = gameRule.MinPlayers; if (args.Players.Length >= minPlayers) diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index 2f8b9dc927..232d24004b 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -344,7 +344,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem var timeRemain = nukeops.WarNukieArriveDelay + Timing.CurTime; ev.DeclaratorEntity.Comp.ShuttleDisabledTime = timeRemain; - DistributeExtraTc(nukeops); + DistributeExtraTc((uid, nukeops)); } } } @@ -371,7 +371,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem return WarConditionStatus.YesWar; } - private void DistributeExtraTc(NukeopsRuleComponent nukieRule) + private void DistributeExtraTc(Entity nukieRule) { var enumerator = EntityQueryEnumerator(); while (enumerator.MoveNext(out var uid, out var component)) @@ -379,13 +379,13 @@ public sealed class NukeopsRuleSystem : GameRuleSystem if (!_tag.HasTag(uid, NukeOpsUplinkTagPrototype)) continue; - if (GetOutpost(uid) is not {} outpost) + if (GetOutpost(nukieRule.Owner) is not { } outpost) continue; if (Transform(uid).MapID != Transform(outpost).MapID) // Will receive bonus TC only on their start outpost continue; - _store.TryAddCurrency(new () { { TelecrystalCurrencyPrototype, nukieRule.WarTcAmountPerNukie } }, uid, component); + _store.TryAddCurrency(new () { { TelecrystalCurrencyPrototype, nukieRule.Comp.WarTcAmountPerNukie } }, uid, component); var msg = Loc.GetString("store-currency-war-boost-given", ("target", uid)); _popupSystem.PopupEntity(msg, uid); @@ -510,7 +510,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem if (!Resolve(ent, ref ent.Comp, false)) return null; - return ent.Comp.MapGrids.FirstOrNull(); + return ent.Comp.MapGrids.Where(e => HasComp(e) && !HasComp(e)).FirstOrNull(); } /// diff --git a/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs b/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs index b778f7c645..083085fa0d 100644 --- a/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs @@ -34,6 +34,7 @@ public sealed class ThiefRuleSystem : GameRuleSystem //Generate objectives GenerateObjectives(mindId, mind, ent); + _antag.SendBriefing(args.EntityUid, MakeBriefing(args.EntityUid), null, null); } private void GenerateObjectives(EntityUid mindId, MindComponent mind, ThiefRuleComponent thiefRule) diff --git a/Content.Shared/Roles/SharedRoleSystem.cs b/Content.Shared/Roles/SharedRoleSystem.cs index 1a732eb750..d5ac2e5923 100644 --- a/Content.Shared/Roles/SharedRoleSystem.cs +++ b/Content.Shared/Roles/SharedRoleSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Shared.Administration.Logs; using Content.Shared.Database; using Content.Shared.Mind; @@ -62,6 +63,38 @@ public abstract class SharedRoleSystem : EntitySystem _antagTypes.Add(typeof(T)); } + public void MindAddRoles(EntityUid mindId, ComponentRegistry components, MindComponent? mind = null, bool silent = false) + { + if (!Resolve(mindId, ref mind)) + return; + + EntityManager.AddComponents(mindId, components); + var antagonist = false; + foreach (var compReg in components.Values) + { + var compType = compReg.Component.GetType(); + + var comp = EntityManager.ComponentFactory.GetComponent(compType); + if (IsAntagonistRole(comp.GetType())) + { + antagonist = true; + break; + } + } + + var mindEv = new MindRoleAddedEvent(silent); + RaiseLocalEvent(mindId, ref mindEv); + + var message = new RoleAddedEvent(mindId, mind, antagonist, silent); + if (mind.OwnedEntity != null) + { + RaiseLocalEvent(mind.OwnedEntity.Value, message, true); + } + + _adminLogger.Add(LogType.Mind, LogImpact.Low, + $"Role components {string.Join(components.Keys.ToString(), ", ")} added to mind of {_minds.MindOwnerLoggingString(mind)}"); + } + public void MindAddRole(EntityUid mindId, Component component, MindComponent? mind = null, bool silent = false) { if (!Resolve(mindId, ref mind))