#nullable enable
+using System.Collections.Generic;
using System.Linq;
using Content.Server.Body.Components;
using Content.Server.GameTicking;
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind));
Assert.That(factionSys.IsMember(player, "Syndicate"), Is.True);
Assert.That(factionSys.IsMember(player, "NanoTrasen"), Is.False);
- var roles = roleSys.MindGetAllRoles(mind);
- var cmdRoles = roles.Where(x => x.Prototype == "NukeopsCommander" && x.Component is NukeopsRoleComponent);
+ var roles = roleSys.MindGetAllRoleInfo(mind);
+ var cmdRoles = roles.Where(x => x.Prototype == "NukeopsCommander");
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
// The second dummy player should be a medic
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(dummyMind));
Assert.That(factionSys.IsMember(dummyEnts[1], "Syndicate"), Is.True);
Assert.That(factionSys.IsMember(dummyEnts[1], "NanoTrasen"), Is.False);
- roles = roleSys.MindGetAllRoles(dummyMind);
- cmdRoles = roles.Where(x => x.Prototype == "NukeopsMedic" && x.Component is NukeopsRoleComponent);
+ roles = roleSys.MindGetAllRoleInfo(dummyMind);
+ cmdRoles = roles.Where(x => x.Prototype == "NukeopsMedic");
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
// The other two players should have just spawned in as normal.
void CheckDummy(int i)
{
var ent = dummyEnts[i];
- var mind = mindSys.GetMind(ent)!.Value;
+ var mindCrew = mindSys.GetMind(ent)!.Value;
Assert.That(entMan.HasComponent<NukeOperativeComponent>(ent), Is.False);
- Assert.That(roleSys.MindIsAntagonist(mind), Is.False);
- Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind), Is.False);
+ Assert.That(roleSys.MindIsAntagonist(mindCrew), Is.False);
+ Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mindCrew), Is.False);
Assert.That(factionSys.IsMember(ent, "Syndicate"), Is.False);
Assert.That(factionSys.IsMember(ent, "NanoTrasen"), Is.True);
- Assert.That(roleSys.MindGetAllRoles(mind).Any(x => x.Component is NukeopsRoleComponent), Is.False);
+ var nukeroles = new List<string>() { "Nukeops", "NukeopsMedic", "NukeopsCommander" };
+ Assert.That(roleSys.MindGetAllRoleInfo(mindCrew).Any(x => nukeroles.Contains(x.Prototype)), Is.False);
}
// The game rule exists, and all the stations/shuttles/maps are properly initialized
for (var i = 0; i < nukies.Length - 1; i++)
{
entMan.DeleteEntity(nukies[i]);
- Assert.That(roundEndSys.IsRoundEndRequested, Is.False,
+ Assert.That(roundEndSys.IsRoundEndRequested,
+ Is.False,
$"The round ended, but {nukies.Length - i - 1} nukies are still alive!");
}
// Delete the last nukie and make sure the round ends.
using Content.Server.Body.Systems;
using Content.Server.Station.Systems;
using Content.Shared.Preferences;
-using Content.Shared.Roles.Jobs;
namespace Content.IntegrationTests.Tests.Internals;
await server.WaitAssertion(() =>
{
var profile = new HumanoidCharacterProfile();
- var dummy = stationSpawning.SpawnPlayerMob(testMap.GridCoords, new JobComponent()
- {
- Prototype = "TestInternalsDummy"
- }, profile, station: null);
+ var dummy = stationSpawning.SpawnPlayerMob(testMap.GridCoords, "TestInternalsDummy", profile, station: null);
Assert.That(atmos.HasAtmosphere(testMap.Grid), Is.False, "Test map has atmosphere - test needs adjustment!");
Assert.That(internals.AreInternalsWorking(dummy), "Internals did not automatically connect!");
#nullable enable
using System.Linq;
-using Content.Server.Ghost;
using Content.Server.Ghost.Roles;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Mind.Commands;
-using Content.Server.Players;
using Content.Server.Roles;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
- Assert.That(roleSystem.MindHasRole<JobComponent>(mindId), Is.False);
+ Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId), Is.False);
});
- var traitorRole = new TraitorRoleComponent();
+ var traitorRole = "MindRoleTraitor";
roleSystem.MindAddRole(mindId, traitorRole);
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId));
- Assert.That(roleSystem.MindHasRole<JobComponent>(mindId), Is.False);
+ Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId), Is.False);
});
- var jobRole = new JobComponent();
+ var jobRole = "";
- roleSystem.MindAddRole(mindId, jobRole);
+ roleSystem.MindAddJobRole(mindId, jobPrototype:jobRole);
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId));
- Assert.That(roleSystem.MindHasRole<JobComponent>(mindId));
+ Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId));
});
roleSystem.MindRemoveRole<TraitorRoleComponent>(mindId);
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
- Assert.That(roleSystem.MindHasRole<JobComponent>(mindId));
+ Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId));
});
- roleSystem.MindRemoveRole<JobComponent>(mindId);
+ roleSystem.MindRemoveRole<JobRoleComponent>(mindId);
Assert.Multiple(() =>
{
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
- Assert.That(roleSystem.MindHasRole<JobComponent>(mindId), Is.False);
+ Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId), Is.False);
});
});
using Content.Shared.Inventory;
using Content.Shared.Preferences;
using Content.Shared.Preferences.Loadouts;
-using Content.Shared.Roles.Jobs;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
profile.SetLoadout(new RoleLoadout("LoadoutTester"));
- var tester = stationSystem.SpawnPlayerMob(testMap.GridCoords, job: new JobComponent()
- {
- Prototype = "LoadoutTester"
- }, profile, station: null);
+ var tester = stationSystem.SpawnPlayerMob(testMap.GridCoords, job: "LoadoutTester", profile, station: null);
var slotQuery = inventorySystem.GetSlotEnumerator(tester);
var checkedCount = 0;
using Content.Server.Roles;
using Content.Server.Roles.Jobs;
using Content.Server.Shuttles.Components;
-using Content.Server.Station.Systems;
using Content.Shared.Antag;
using Content.Shared.Clothing;
using Content.Shared.GameTicking;
using Content.Shared.Humanoid;
using Content.Shared.Mind;
using Content.Shared.Players;
-using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles;
using Content.Shared.Whitelist;
using Robust.Server.Audio;
public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelectionComponent>
{
- [Dependency] private readonly IChatManager _chat = default!;
- [Dependency] private readonly IPlayerManager _playerManager = default!;
- [Dependency] private readonly IServerPreferencesManager _pref = default!;
[Dependency] private readonly AudioSystem _audio = default!;
+ [Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly GhostRoleSystem _ghostRole = default!;
[Dependency] private readonly JobSystem _jobs = default!;
[Dependency] private readonly LoadoutSystem _loadout = default!;
[Dependency] private readonly MindSystem _mind = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly IServerPreferencesManager _pref = default!;
[Dependency] private readonly RoleSystem _role = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
/// <summary>
/// Chooses antagonists from the given selection of players
/// </summary>
+ /// <param name="ent">The antagonist rule entity</param>
+ /// <param name="pool">The players to choose from</param>
+ /// <param name="midround">Disable picking players for pre-spawn antags in the middle of a round</param>
public void ChooseAntags(Entity<AntagSelectionComponent> ent, IList<ICommonSession> pool, bool midround = false)
{
if (ent.Comp.SelectionsComplete)
/// <summary>
/// Chooses antagonists from the given selection of players for the given antag definition.
/// </summary>
+ /// <param name="ent">The antagonist rule entity</param>
+ /// <param name="pool">The players to choose from</param>
+ /// <param name="def">The antagonist selection parameters and criteria</param>
/// <param name="midround">Disable picking players for pre-spawn antags in the middle of a round</param>
- public void ChooseAntags(Entity<AntagSelectionComponent> ent, IList<ICommonSession> pool, AntagSelectionDefinition def, bool midround = false)
+ public void ChooseAntags(Entity<AntagSelectionComponent> ent,
+ IList<ICommonSession> pool,
+ AntagSelectionDefinition def,
+ bool midround = false)
{
var playerPool = GetPlayerPool(ent, pool, def);
var count = GetTargetAntagCount(ent, GetTotalPlayerCount(pool), def);
EntityManager.AddComponents(player, def.Components);
// Equip the entity's RoleLoadout and LoadoutGroup
- List<ProtoId<StartingGearPrototype>>? gear = new();
+ List<ProtoId<StartingGearPrototype>> gear = new();
if (def.StartingGear is not null)
gear.Add(def.StartingGear.Value);
if (session != null)
{
var curMind = session.GetMind();
-
- if (curMind == null ||
+
+ if (curMind == null ||
!TryComp<MindComponent>(curMind.Value, out var mindComp) ||
mindComp.OwnedEntity != antagEnt)
{
}
_mind.TransferTo(curMind.Value, antagEnt, ghostCheckOverride: true);
- _role.MindAddRoles(curMind.Value, def.MindComponents, null, true);
+ _role.MindAddRoles(curMind.Value, def.MindRoles, null, true);
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
SendBriefing(session, def.Briefing);
}
using Content.Shared.Destructible.Thresholds;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles;
-using Content.Shared.Storage;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.Player;
/// <summary>
/// Components added to the player's mind.
+ /// Do NOT use this to add role-type components. Add those as MindRoles instead
/// </summary>
[DataField]
public ComponentRegistry MindComponents = new();
+ /// <summary>
+ /// List of Mind Role Prototypes to be added to the player's mind.
+ /// </summary>
+ [DataField]
+ public List<ProtoId<EntityPrototype>>? MindRoles;
+
/// <summary>
/// A set of starting gear that's equipped to the player.
/// </summary>
// TODO: Ideally, components like this should be components on the mind entity so this isn't necessary.
// Add on special job components to the mob.
- if (_jobs.MindTryGetJob(mindEnt, out _, out var prototype))
+ if (_jobs.MindTryGetJob(mindEnt, out var prototype))
{
foreach (var special in prototype.Special)
{
using System.Linq;
using Content.Shared.EntityEffects;
-using Content.Shared.Mobs;
-using Content.Shared.Mobs.Components;
using Content.Shared.Localizations;
-using Robust.Shared.Prototypes;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Roles;
using Content.Shared.Roles.Jobs;
-using Content.Shared.Station;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using Robust.Shared.IoC;
+using Robust.Shared.Prototypes;
namespace Content.Server.EntityEffects.EffectConditions;
public sealed partial class JobCondition : EntityEffectCondition
{
[DataField(required: true)] public List<ProtoId<JobPrototype>> Job;
-
+
public override bool Condition(EntityEffectBaseArgs args)
- {
+ {
args.EntityManager.TryGetComponent<MindContainerComponent>(args.TargetEntity, out var mindContainer);
- if (mindContainer != null && mindContainer.Mind != null)
+
+ if ( mindContainer is null
+ || !args.EntityManager.TryGetComponent<MindComponent>(mindContainer.Mind, out var mind))
+ return false;
+
+ foreach (var roleId in mind.MindRoles)
{
- var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
- if (args.EntityManager.TryGetComponent<JobComponent>(mindContainer?.Mind, out var comp) && prototypeManager.TryIndex(comp.Prototype, out var prototype))
- {
- foreach (var jobId in Job)
- {
- if (prototype.ID == jobId)
- {
- return true;
- }
- }
- }
+ if(!args.EntityManager.HasComponent<JobRoleComponent>(roleId))
+ continue;
+
+ if(!args.EntityManager.TryGetComponent<MindRoleComponent>(roleId, out var mindRole)
+ || mindRole.JobPrototype is null)
+ continue;
+
+ if (Job.Contains(mindRole.JobPrototype.Value))
+ return true;
}
-
+
return false;
}
-
+
public override string GuidebookExplanation(IPrototypeManager prototype)
{
var localizedNames = Job.Select(jobId => prototype.Index(jobId).LocalizedName).ToList();
return Loc.GetString("reagent-effect-condition-guidebook-job-condition", ("job", ContentLocalizationManager.FormatListToOr(localizedNames)));
}
}
-
-
using Content.Server.GameTicking.Events;
using Content.Server.Ghost;
using Content.Server.Maps;
+using Content.Server.Roles;
using Content.Shared.CCVar;
using Content.Shared.Database;
using Content.Shared.GameTicking;
public sealed partial class GameTicker
{
[Dependency] private readonly DiscordWebhook _discord = default!;
+ [Dependency] private readonly RoleSystem _role = default!;
[Dependency] private readonly ITaskManager _taskManager = default!;
private static readonly Counter RoundNumberMetric = Metrics.CreateCounter(
var userId = mind.UserId ?? mind.OriginalOwnerUserId;
var connected = false;
- var observer = HasComp<ObserverRoleComponent>(mindId);
+ var observer = _role.MindHasRole<ObserverRoleComponent>(mindId);
// Continuing
if (userId != null && _playerManager.ValidSessionId(userId.Value))
{
_pvsOverride.AddGlobalOverride(GetNetEntity(entity.Value), recursive: true);
}
- var roles = _roles.MindGetAllRoles(mindId);
+ var roles = _roles.MindGetAllRoleInfo(mindId);
var playerEndRoundInfo = new RoundEndMessageEvent.RoundEndPlayerInfo()
{
using System.Numerics;
using Content.Server.Administration.Managers;
using Content.Server.GameTicking.Events;
-using Content.Server.Ghost;
-using Content.Server.Shuttles.Components;
using Content.Server.Spawners.Components;
using Content.Server.Speech.Components;
using Content.Server.Station.Components;
_mind.SetUserId(newMind, data.UserId);
var jobPrototype = _prototypeManager.Index<JobPrototype>(jobId);
- var job = new JobComponent {Prototype = jobId};
- _roles.MindAddRole(newMind, job, silent: silent);
+ _roles.MindAddJobRole(newMind, silent: silent, jobPrototype:jobId);
var jobName = _jobs.MindTryGetJobName(newMind);
_playTimeTrackings.PlayerRolesChanged(player);
- var mobMaybe = _stationSpawning.SpawnPlayerCharacterOnStation(station, job, character);
+ var mobMaybe = _stationSpawning.SpawnPlayerCharacterOnStation(station, jobId, character);
DebugTools.AssertNotNull(mobMaybe);
var mob = mobMaybe!.Value;
_stationJobs.TryAssignJob(station, jobPrototype, player.UserId);
if (lateJoin)
+ {
_adminLogger.Add(LogType.LateJoin,
LogImpact.Medium,
$"Player {player.Name} late joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}.");
+ }
else
+ {
_adminLogger.Add(LogType.RoundStartJoin,
LogImpact.Medium,
$"Player {player.Name} joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}.");
+ }
// Make sure they're aware of extended access.
if (Comp<StationJobsComponent>(station).ExtendedAccess
var (mindId, mindComp) = _mind.CreateMind(player.UserId, name);
mind = (mindId, mindComp);
_mind.SetUserId(mind.Value, player.UserId);
- _roles.MindAddRole(mind.Value, new ObserverRoleComponent());
+ _roles.MindAddRole(mind.Value, "MindRoleObserver");
}
var ghost = _ghost.SpawnGhost(mind.Value);
using Content.Server.Shuttles.Events;
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Components;
-using Content.Server.Store.Components;
using Content.Server.Store.Systems;
using Content.Shared.GameTicking.Components;
using Content.Shared.Mobs;
public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
{
+ [Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly EmergencyShuttleSystem _emergency = default!;
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
- [Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
[Dependency] private readonly StoreSystem _store = default!;
SubscribeLocalEvent<NukeOperativeComponent, MobStateChangedEvent>(OnMobStateChanged);
SubscribeLocalEvent<NukeOperativeComponent, EntityZombifiedEvent>(OnOperativeZombified);
+ SubscribeLocalEvent<NukeopsRoleComponent, GetBriefingEvent>(OnGetBriefing);
+
SubscribeLocalEvent<ConsoleFTLAttemptEvent>(OnShuttleFTLAttempt);
SubscribeLocalEvent<WarDeclaredEvent>(OnWarDeclared);
SubscribeLocalEvent<CommunicationConsoleCallShuttleAttemptEvent>(OnShuttleCallAttempt);
SubscribeLocalEvent<NukeopsRuleComponent, RuleLoadedGridsEvent>(OnRuleLoadedGrids);
}
- protected override void Started(EntityUid uid, NukeopsRuleComponent component, GameRuleComponent gameRule,
+ protected override void Started(EntityUid uid,
+ NukeopsRuleComponent component,
+ GameRuleComponent gameRule,
GameRuleStartedEvent args)
{
var eligible = new List<Entity<StationEventEligibleComponent, NpcFactionMemberComponent>>();
}
#region Event Handlers
- protected override void AppendRoundEndText(EntityUid uid, NukeopsRuleComponent component, GameRuleComponent gameRule,
+ protected override void AppendRoundEndText(EntityUid uid,
+ NukeopsRuleComponent component,
+ GameRuleComponent gameRule,
ref RoundEndTextAppendEvent args)
{
var winText = Loc.GetString($"nukeops-{component.WinType.ToString().ToLower()}");
// If the disk is currently at Central Command, the crew wins - just slightly.
// This also implies that some nuclear operatives have died.
- SetWinType(ent, diskAtCentCom
+ SetWinType(ent,
+ diskAtCentCom
? WinType.CrewMinor
: WinType.OpsMinor);
ent.Comp.WinConditions.Add(diskAtCentCom
: WinCondition.AllNukiesDead);
SetWinType(ent, WinType.CrewMajor, false);
- _roundEndSystem.DoRoundEndBehavior(
- nukeops.RoundEndBehavior, nukeops.EvacShuttleTime, nukeops.RoundEndTextSender, nukeops.RoundEndTextShuttleCall, nukeops.RoundEndTextAnnouncement);
+ _roundEndSystem.DoRoundEndBehavior(nukeops.RoundEndBehavior,
+ nukeops.EvacShuttleTime,
+ nukeops.RoundEndTextSender,
+ nukeops.RoundEndTextShuttleCall,
+ nukeops.RoundEndTextAnnouncement);
// prevent it called multiple times
nukeops.RoundEndBehavior = RoundEndBehavior.Nothing;
private void OnAfterAntagEntSelected(Entity<NukeopsRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
{
- if (ent.Comp.TargetStation is not { } station)
- return;
+ var target = (ent.Comp.TargetStation is not null) ? Name(ent.Comp.TargetStation.Value) : "the target";
- _antag.SendBriefing(args.Session, Loc.GetString("nukeops-welcome",
- ("station", station),
+ _antag.SendBriefing(args.Session,
+ Loc.GetString("nukeops-welcome",
+ ("station", target),
("name", Name(ent))),
Color.Red,
ent.Comp.GreetSoundNotification);
}
+ private void OnGetBriefing(Entity<NukeopsRoleComponent> role, ref GetBriefingEvent args)
+ {
+ // TODO Different character screen briefing for the 3 nukie types
+ args.Append(Loc.GetString("nukeops-briefing"));
+ }
+
/// <remarks>
/// Is this method the shitty glue holding together the last of my sanity? yes.
/// Do i have a better solution? not presently.
using Content.Shared.GameTicking.Components;
using Content.Shared.Humanoid;
using Content.Shared.IdentityManagement;
-using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Mindshield.Components;
using Content.Shared.Mobs;
public sealed class RevolutionaryRuleSystem : GameRuleSystem<RevolutionaryRuleComponent>
{
[Dependency] private readonly IAdminLogManager _adminLogManager = default!;
- [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly AntagSelectionSystem _antag = default!;
+ [Dependency] private readonly EmergencyShuttleSystem _emergencyShuttle = default!;
[Dependency] private readonly EuiManager _euiMan = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly SharedStunSystem _stun = default!;
[Dependency] private readonly RoundEndSystem _roundEnd = default!;
[Dependency] private readonly StationSystem _stationSystem = default!;
- [Dependency] private readonly EmergencyShuttleSystem _emergencyShuttle = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
//Used in OnPostFlash, no reference to the rule component is available
public readonly ProtoId<NpcFactionPrototype> RevolutionaryNpcFaction = "Revolutionary";
{
base.Initialize();
SubscribeLocalEvent<CommandStaffComponent, MobStateChangedEvent>(OnCommandMobStateChanged);
+
+ SubscribeLocalEvent<HeadRevolutionaryComponent, AfterFlashedEvent>(OnPostFlash);
SubscribeLocalEvent<HeadRevolutionaryComponent, MobStateChangedEvent>(OnHeadRevMobStateChanged);
+
SubscribeLocalEvent<RevolutionaryRoleComponent, GetBriefingEvent>(OnGetBriefing);
- SubscribeLocalEvent<HeadRevolutionaryComponent, AfterFlashedEvent>(OnPostFlash);
+
}
protected override void Started(EntityUid uid, RevolutionaryRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
}
}
- protected override void AppendRoundEndText(EntityUid uid, RevolutionaryRuleComponent component, GameRuleComponent gameRule,
+ protected override void AppendRoundEndText(EntityUid uid,
+ RevolutionaryRuleComponent component,
+ GameRuleComponent gameRule,
ref RoundEndTextAppendEvent args)
{
base.AppendRoundEndText(uid, component, gameRule, ref args);
args.AddLine(Loc.GetString("rev-headrev-count", ("initialCount", sessionData.Count)));
foreach (var (mind, data, name) in sessionData)
{
- var count = CompOrNull<RevolutionaryRoleComponent>(mind)?.ConvertedCount ?? 0;
+ _role.MindHasRole<RevolutionaryRoleComponent>(mind, out var role);
+ var count = CompOrNull<RevolutionaryRoleComponent>(role)?.ConvertedCount ?? 0;
+
args.AddLine(Loc.GetString("rev-headrev-name-user",
("name", name),
("username", data.UserName),
private void OnGetBriefing(EntityUid uid, RevolutionaryRoleComponent comp, ref GetBriefingEvent args)
{
- if (!TryComp<MindComponent>(uid, out var mind) || mind.OwnedEntity == null)
- return;
-
- var head = HasComp<HeadRevolutionaryComponent>(mind.OwnedEntity);
+ var ent = args.Mind.Comp.OwnedEntity;
+ var head = HasComp<HeadRevolutionaryComponent>(ent);
args.Append(Loc.GetString(head ? "head-rev-briefing" : "rev-briefing"));
}
if (ev.User != null)
{
- _adminLogManager.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(ev.User.Value)} converted {ToPrettyString(ev.Target)} into a Revolutionary");
+ _adminLogManager.Add(LogType.Mind,
+ LogImpact.Medium,
+ $"{ToPrettyString(ev.User.Value)} converted {ToPrettyString(ev.Target)} into a Revolutionary");
- if (_mind.TryGetRole<RevolutionaryRoleComponent>(ev.User.Value, out var headrev))
- headrev.ConvertedCount++;
+ if (_mind.TryGetMind(ev.User.Value, out var revMindId, out _))
+ {
+ if (_role.MindHasRole<RevolutionaryRoleComponent>(revMindId, out _, out var role))
+ role.Value.Comp.ConvertedCount++;
+ }
}
if (mindId == default || !_role.MindHasRole<RevolutionaryRoleComponent>(mindId))
{
- _role.MindAddRole(mindId, new RevolutionaryRoleComponent { PrototypeId = RevPrototypeId });
+ _role.MindAddRole(mindId, "MindRoleRevolutionary");
}
if (mind?.Session != null)
using Content.Server.Antag;
using Content.Server.GameTicking.Rules.Components;
-using Content.Server.Mind;
-using Content.Server.Objectives;
using Content.Server.Roles;
using Content.Shared.Humanoid;
-using Content.Shared.Mind;
-using Content.Shared.Objectives.Components;
-using Robust.Shared.Random;
namespace Content.Server.GameTicking.Rules;
public sealed class ThiefRuleSystem : GameRuleSystem<ThiefRuleComponent>
{
- [Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly AntagSelectionSystem _antag = default!;
public override void Initialize()
SubscribeLocalEvent<ThiefRoleComponent, GetBriefingEvent>(OnGetBriefing);
}
- private void AfterAntagSelected(Entity<ThiefRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
+ // Greeting upon thief activation
+ private void AfterAntagSelected(Entity<ThiefRuleComponent> mindId, ref AfterAntagEntitySelectedEvent args)
{
- if (!_mindSystem.TryGetMind(args.EntityUid, out var mindId, out var mind))
- return;
-
- //Generate objectives
- _antag.SendBriefing(args.EntityUid, MakeBriefing(args.EntityUid), null, null);
+ var ent = args.EntityUid;
+ _antag.SendBriefing(ent, MakeBriefing(ent), null, null);
}
- //Add mind briefing
- private void OnGetBriefing(Entity<ThiefRoleComponent> thief, ref GetBriefingEvent args)
+ // Character screen briefing
+ private void OnGetBriefing(Entity<ThiefRoleComponent> role, ref GetBriefingEvent args)
{
- if (!TryComp<MindComponent>(thief.Owner, out var mind) || mind.OwnedEntity == null)
- return;
+ var ent = args.Mind.Comp.OwnedEntity;
- args.Append(MakeBriefing(mind.OwnedEntity.Value));
+ if (ent is null)
+ return;
+ args.Append(MakeBriefing(ent.Value));
}
- private string MakeBriefing(EntityUid thief)
+ private string MakeBriefing(EntityUid ent)
{
- var isHuman = HasComp<HumanoidAppearanceComponent>(thief);
+ var isHuman = HasComp<HumanoidAppearanceComponent>(ent);
var briefing = isHuman
? Loc.GetString("thief-role-greeting-human")
: Loc.GetString("thief-role-greeting-animal");
- briefing += "\n \n" + Loc.GetString("thief-role-greeting-equipment") + "\n";
+ if (isHuman)
+ briefing += "\n \n" + Loc.GetString("thief-role-greeting-equipment") + "\n";
+
return briefing;
}
}
using Content.Shared.GameTicking.Components;
using Content.Shared.Mind;
using Content.Shared.NPC.Systems;
-using Content.Shared.Objectives.Components;
using Content.Shared.PDA;
-using Content.Shared.Radio;
using Content.Shared.Roles;
using Content.Shared.Roles.Jobs;
using Content.Shared.Roles.RoleCodeword;
private static readonly Color TraitorCodewordColor = Color.FromHex("#cc3b3b");
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
- [Dependency] private readonly NpcFactionSystem _npcFaction = default!;
[Dependency] private readonly AntagSelectionSystem _antag = default!;
- [Dependency] private readonly UplinkSystem _uplink = default!;
- [Dependency] private readonly MindSystem _mindSystem = default!;
- [Dependency] private readonly SharedRoleSystem _roleSystem = default!;
[Dependency] private readonly SharedJobSystem _jobs = default!;
+ [Dependency] private readonly MindSystem _mindSystem = default!;
+ [Dependency] private readonly NpcFactionSystem _npcFaction = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedRoleCodewordSystem _roleCodewordSystem = default!;
+ [Dependency] private readonly SharedRoleSystem _roleSystem = default!;
+ [Dependency] private readonly UplinkSystem _uplink = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<TraitorRuleComponent, AfterAntagEntitySelectedEvent>(AfterEntitySelected);
-
SubscribeLocalEvent<TraitorRuleComponent, ObjectivesTextPrependEvent>(OnObjectivesTextPrepend);
}
public bool MakeTraitor(EntityUid traitor, TraitorRuleComponent component, bool giveUplink = true)
{
- //Grab the mind if it wasnt provided
+ //Grab the mind if it wasn't provided
if (!_mindSystem.TryGetMind(traitor, out var mindId, out var mind))
return false;
{
// Calculate the amount of currency on the uplink.
var startingBalance = component.StartingBalance;
- if (_jobs.MindTryGetJob(mindId, out _, out var prototype))
+ if (_jobs.MindTryGetJob(mindId, out var prototype))
startingBalance = Math.Max(startingBalance - prototype.AntagAdvantage, 0);
// creadth: we need to create uplink for the antag.
_antag.SendBriefing(traitor, GenerateBriefing(component.Codewords, code, issuer), null, component.GreetSoundNotification);
-
component.TraitorMinds.Add(mindId);
// Assign briefing
- _roleSystem.MindAddRole(mindId, new RoleBriefingComponent
+ //Since this provides neither an antag/job prototype, nor antag status/roletype,
+ //and is intrinsically related to the traitor role
+ //it does not need to be a separate Mind Role Entity
+ _roleSystem.MindHasRole<TraitorRoleComponent>(mindId, out var traitorRole);
+ if (traitorRole is not null)
{
- Briefing = briefing
- }, mind, true);
+ AddComp<RoleBriefingComponent>(traitorRole.Value.Owner);
+ Comp<RoleBriefingComponent>(traitorRole.Value.Owner).Briefing = briefing;
+ }
// Send codewords to only the traitor client
var color = TraitorCodewordColor; // Fall back to a dark red Syndicate color if a prototype is not found
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
+using Content.Shared.Roles;
using Content.Shared.Zombies;
using Robust.Shared.Player;
using Robust.Shared.Timing;
public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
{
+ [Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly ChatSystem _chat = default!;
- [Dependency] private readonly RoundEndSystem _roundEnd = default!;
- [Dependency] private readonly PopupSystem _popup = default!;
- [Dependency] private readonly MobStateSystem _mobState = default!;
- [Dependency] private readonly ZombieSystem _zombie = default!;
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
+ [Dependency] private readonly MobStateSystem _mobState = default!;
+ [Dependency] private readonly PopupSystem _popup = default!;
+ [Dependency] private readonly SharedRoleSystem _roles = default!;
+ [Dependency] private readonly RoundEndSystem _roundEnd = default!;
[Dependency] private readonly StationSystem _station = default!;
- [Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly ZombieSystem _zombie = default!;
public override void Initialize()
{
SubscribeLocalEvent<IncurableZombieComponent, ZombifySelfActionEvent>(OnZombifySelf);
}
- private void OnGetBriefing(EntityUid uid, InitialInfectedRoleComponent component, ref GetBriefingEvent args)
+ private void OnGetBriefing(Entity<InitialInfectedRoleComponent> role, ref GetBriefingEvent args)
{
- if (!TryComp<MindComponent>(uid, out var mind) || mind.OwnedEntity == null)
- return;
- if (HasComp<ZombieRoleComponent>(uid)) // don't show both briefings
- return;
- args.Append(Loc.GetString("zombie-patientzero-role-greeting"));
+ if (!_roles.MindHasRole<ZombieRoleComponent>(args.Mind.Owner))
+ args.Append(Loc.GetString("zombie-patientzero-role-greeting"));
}
- private void OnGetBriefing(EntityUid uid, ZombieRoleComponent component, ref GetBriefingEvent args)
+ private void OnGetBriefing(Entity<ZombieRoleComponent> role, ref GetBriefingEvent args)
{
- if (!TryComp<MindComponent>(uid, out var mind) || mind.OwnedEntity == null)
- return;
args.Append(Loc.GetString("zombie-infection-greeting"));
}
- protected override void AppendRoundEndText(EntityUid uid, ZombieRuleComponent component, GameRuleComponent gameRule,
+ protected override void AppendRoundEndText(EntityUid uid,
+ ZombieRuleComponent component,
+ GameRuleComponent gameRule,
ref RoundEndTextAppendEvent args)
{
base.AppendRoundEndText(uid, component, gameRule, ref args);
-namespace Content.Server.Ghost.Roles;
+using Content.Shared.Roles;
+
+namespace Content.Server.Ghost.Roles;
/// <summary>
/// This is used for round end display of ghost roles.
/// It may also be used to ensure some ghost roles count as antagonists in future.
/// </summary>
[RegisterComponent]
-public sealed partial class GhostRoleMarkerRoleComponent : Component
+public sealed partial class GhostRoleMarkerRoleComponent : BaseMindRoleComponent
{
[DataField("name")] public string? Name;
}
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
+
SubscribeLocalEvent<GhostTakeoverAvailableComponent, MindAddedMessage>(OnMindAdded);
SubscribeLocalEvent<GhostTakeoverAvailableComponent, MindRemovedMessage>(OnMindRemoved);
SubscribeLocalEvent<GhostTakeoverAvailableComponent, MobStateChangedEvent>(OnMobStateChanged);
+ SubscribeLocalEvent<GhostTakeoverAvailableComponent, TakeGhostRoleEvent>(OnTakeoverTakeRole);
+
SubscribeLocalEvent<GhostRoleComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<GhostRoleComponent, ComponentStartup>(OnRoleStartup);
SubscribeLocalEvent<GhostRoleComponent, ComponentShutdown>(OnRoleShutdown);
SubscribeLocalEvent<GhostRoleComponent, EntityPausedEvent>(OnPaused);
SubscribeLocalEvent<GhostRoleComponent, EntityUnpausedEvent>(OnUnpaused);
+
SubscribeLocalEvent<GhostRoleRaffleComponent, ComponentInit>(OnRaffleInit);
SubscribeLocalEvent<GhostRoleRaffleComponent, ComponentShutdown>(OnRaffleShutdown);
+
SubscribeLocalEvent<GhostRoleMobSpawnerComponent, TakeGhostRoleEvent>(OnSpawnerTakeRole);
- SubscribeLocalEvent<GhostTakeoverAvailableComponent, TakeGhostRoleEvent>(OnTakeoverTakeRole);
SubscribeLocalEvent<GhostRoleMobSpawnerComponent, GetVerbsEvent<Verb>>(OnVerb);
SubscribeLocalEvent<GhostRoleMobSpawnerComponent, GhostRoleRadioMessage>(OnGhostRoleRadioMessage);
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
var newMind = _mindSystem.CreateMind(player.UserId,
EntityManager.GetComponent<MetaDataComponent>(mob).EntityName);
- _roleSystem.MindAddRole(newMind, new GhostRoleMarkerRoleComponent { Name = role.RoleName });
+
+ _roleSystem.MindAddRole(newMind, "MindRoleGhostMarker");
+
+ if(_roleSystem.MindHasRole<GhostRoleMarkerRoleComponent>(newMind, out _, out var markerRole))
+ markerRole.Value.Comp.Name = role.RoleName;
_mindSystem.SetUserId(newMind, player.UserId);
_mindSystem.TransferTo(newMind, mob);
if (ghostRole.JobProto != null)
{
- if (HasComp<JobComponent>(args.Mind))
- _roleSystem.MindRemoveRole<JobComponent>(args.Mind);
-
- _roleSystem.MindAddRole(args.Mind, new JobComponent { Prototype = ghostRole.JobProto });
+ _roleSystem.MindAddJobRole(args.Mind, args.Mind, silent:false,ghostRole.JobProto);
}
ghostRole.Taken = true;
builder.AppendFormat("player: {0}, mob: {1}\nroles: ", mind.UserId, mind.OwnedEntity);
var roles = _entities.System<SharedRoleSystem>();
- foreach (var role in roles.MindGetAllRoles(mindId))
+ foreach (var role in roles.MindGetAllRoleInfo(mindId))
{
builder.AppendFormat("{0} ", role.Name);
}
foreach (var mind in allHumans)
{
// RequireAdminNotify used as a cheap way to check for command department
- if (_job.MindTryGetJob(mind, out _, out var prototype) && prototype.RequireAdminNotify)
+ if (_job.MindTryGetJob(mind, out var prototype) && prototype.RequireAdminNotify)
allHeads.Add(mind);
}
using Content.Server.Objectives.Components;
+using Content.Server.Roles;
using Content.Server.Warps;
using Content.Shared.Objectives.Components;
using Content.Shared.Ninja.Components;
+using Content.Shared.Roles;
using Robust.Shared.Random;
-using Content.Server.Roles;
namespace Content.Server.Objectives.Systems;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly NumberObjectiveSystem _number = default!;
[Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly SharedRoleSystem _roles = default!;
public override void Initialize()
{
// spider charge
private void OnSpiderChargeRequirementCheck(EntityUid uid, SpiderChargeConditionComponent comp, ref RequirementCheckEvent args)
{
- if (args.Cancelled || !HasComp<NinjaRoleComponent>(args.MindId))
- {
+ if (args.Cancelled || !_roles.MindHasRole<NinjaRoleComponent>(args.MindId))
return;
- }
// choose spider charge detonation point
var warps = new List<EntityUid>();
return;
// cheap equivalent to checking that job department is command, since all command members require admin notification when leaving
- if (_job.MindTryGetJob(args.MindId, out _, out var prototype) && prototype.RequireAdminNotify)
+ if (_job.MindTryGetJob(args.MindId, out var prototype) && prototype.RequireAdminNotify)
args.Cancelled = true;
}
}
/// </summary>
public sealed class NotJobRequirementSystem : EntitySystem
{
+ [Dependency] private readonly SharedJobSystem _jobs = default!;
+
public override void Initialize()
{
base.Initialize();
if (args.Cancelled)
return;
- // if player has no job then don't care
- if (!TryComp<JobComponent>(args.MindId, out var job))
- return;
+ _jobs.MindTryGetJob(args.MindId, out var proto);
- if (job.Prototype == comp.Job)
+ // if player has no job then don't care
+ if (proto is not null && proto.ID == comp.Job)
args.Cancelled = true;
}
}
if (args.Cancelled)
return;
- // this whitelist trick only works because roles are components on the mind and not entities
- // if that gets reworked then this will need changing
if (_whitelistSystem.IsWhitelistFail(comp.Roles, args.MindId))
args.Cancelled = true;
}
/// </summary>
public sealed class PlayTimeTrackingSystem : EntitySystem
{
+ [Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IAfkManager _afk = default!;
- [Dependency] private readonly IPlayerManager _playerManager = default!;
- [Dependency] private readonly IPrototypeManager _prototypes = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly MindSystem _minds = default!;
- [Dependency] private readonly PlayTimeTrackingManager _tracking = default!;
- [Dependency] private readonly IAdminManager _adminManager = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IServerPreferencesManager _preferencesManager = default!;
+ [Dependency] private readonly IPrototypeManager _prototypes = default!;
+ [Dependency] private readonly SharedRoleSystem _roles = default!;
+ [Dependency] private readonly PlayTimeTrackingManager _tracking = default!;
public override void Initialize()
{
public IEnumerable<string> GetTimedRoles(EntityUid mindId)
{
- var ev = new MindGetAllRolesEvent(new List<RoleInfo>());
- RaiseLocalEvent(mindId, ref ev);
-
- foreach (var role in ev.Roles)
+ foreach (var role in _roles.MindGetAllRoleInfo(mindId))
{
if (string.IsNullOrWhiteSpace(role.PlayTimeTrackerId))
continue;
{
}
+
+//TODO this should probably be on a mind role, not the mob
namespace Content.Server.Roles;
/// <summary>
-/// Role used to keep track of space dragons for antag purposes.
+/// Added to mind role entities to tag that they are a space dragon.
/// </summary>
-[RegisterComponent, Access(typeof(DragonSystem)), ExclusiveAntagonist]
-public sealed partial class DragonRoleComponent : AntagonistRoleComponent
+[RegisterComponent, Access(typeof(DragonSystem))]
+public sealed partial class DragonRoleComponent : BaseMindRoleComponent
{
}
namespace Content.Server.Roles;
-[RegisterComponent, ExclusiveAntagonist]
-public sealed partial class InitialInfectedRoleComponent : AntagonistRoleComponent
+/// <summary>
+/// Added to mind role entities to tag that they are an initial infected.
+/// </summary>
+[RegisterComponent]
+public sealed partial class InitialInfectedRoleComponent : BaseMindRoleComponent
{
}
if (!_mind.TryGetSession(mindId, out var session))
return;
- if (!MindTryGetJob(mindId, out _, out var prototype))
+ if (!MindTryGetJob(mindId, out var prototype))
return;
_chat.DispatchServerMessage(session, Loc.GetString("job-greet-introduce-job-name",
if (MindHasJobWithId(mindId, jobPrototypeId))
return;
- _roles.MindAddRole(mindId, new JobComponent { Prototype = jobPrototypeId });
+ _roles.MindAddJobRole(mindId, null, false, jobPrototypeId);
}
}
namespace Content.Server.Roles;
-[RegisterComponent, ExclusiveAntagonist]
-public sealed partial class NinjaRoleComponent : AntagonistRoleComponent
+/// <summary>
+/// Added to mind role entities to tag that they are a space ninja.
+/// </summary>
+[RegisterComponent]
+public sealed partial class NinjaRoleComponent : BaseMindRoleComponent
{
}
namespace Content.Server.Roles;
/// <summary>
-/// Added to mind entities to tag that they are a nuke operative.
+/// Added to mind role entities to tag that they are a nuke operative.
/// </summary>
-[RegisterComponent, ExclusiveAntagonist]
-public sealed partial class NukeopsRoleComponent : AntagonistRoleComponent
+[RegisterComponent]
+public sealed partial class NukeopsRoleComponent : BaseMindRoleComponent
{
}
var roles = _entityManager.System<SharedRoleSystem>();
var jobs = _entityManager.System<SharedJobSystem>();
if (jobs.MindHasJobWithId(mind, args[1]))
- roles.MindRemoveRole<JobComponent>(mind.Value);
+ roles.MindTryRemoveRole<JobRoleComponent>(mind.Value);
}
}
}
namespace Content.Server.Roles;
/// <summary>
-/// Added to mind entities to tag that they are a Revolutionary.
+/// Added to mind role entities to tag that they are a Revolutionary.
/// </summary>
-[RegisterComponent, ExclusiveAntagonist]
-public sealed partial class RevolutionaryRoleComponent : AntagonistRoleComponent
+[RegisterComponent]
+public sealed partial class RevolutionaryRoleComponent : BaseMindRoleComponent
{
/// <summary>
/// For headrevs, how many people you have converted.
+using Content.Shared.Mind;
using Content.Shared.Roles;
namespace Content.Server.Roles;
public sealed class RoleSystem : SharedRoleSystem
{
- public override void Initialize()
- {
- // TODO make roles entities
- base.Initialize();
-
- SubscribeAntagEvents<DragonRoleComponent>();
- SubscribeAntagEvents<InitialInfectedRoleComponent>();
- SubscribeAntagEvents<NinjaRoleComponent>();
- SubscribeAntagEvents<NukeopsRoleComponent>();
- SubscribeAntagEvents<RevolutionaryRoleComponent>();
- SubscribeAntagEvents<SubvertedSiliconRoleComponent>();
- SubscribeAntagEvents<TraitorRoleComponent>();
- SubscribeAntagEvents<ZombieRoleComponent>();
- SubscribeAntagEvents<ThiefRoleComponent>();
- }
-
public string? MindGetBriefing(EntityUid? mindId)
{
if (mindId == null)
+ {
+ Log.Error($"MingGetBriefing failed for mind {mindId}");
+ return null;
+ }
+
+ TryComp<MindComponent>(mindId.Value, out var mindComp);
+
+ if (mindComp is null)
+ {
+ Log.Error($"MingGetBriefing failed for mind {mindId}");
return null;
+ }
var ev = new GetBriefingEvent();
- RaiseLocalEvent(mindId.Value, ref ev);
+
+ // This is on the event because while this Entity<T> is also present on every Mind Role Entity's MindRoleComp
+ // getting to there from a GetBriefing event subscription can be somewhat boilerplate
+ // and this needs to be looked up for the event anyway so why calculate it again later
+ ev.Mind = (mindId.Value, mindComp);
+
+ // Briefing is no longer raised on the mind entity itself
+ // because all the components that briefings subscribe to should be on Mind Role Entities
+ foreach(var role in mindComp.MindRoles)
+ {
+ RaiseLocalEvent(role, ref ev);
+ }
+
return ev.Briefing;
}
}
[ByRefEvent]
public sealed class GetBriefingEvent
{
+ /// <summary>
+ /// The text that will be shown on the Character Screen
+ /// </summary>
public string? Briefing;
+ /// <summary>
+ /// The Mind to whose Mind Role Entities the briefing is sent to
+ /// </summary>
+ public Entity<MindComponent> Mind;
+
public GetBriefingEvent(string? briefing = null)
{
Briefing = briefing;
namespace Content.Server.Roles;
+/// <summary>
+/// Added to mind role entities to tag that they are a hacked borg.
+/// </summary>
[RegisterComponent]
-public sealed partial class SubvertedSiliconRoleComponent : AntagonistRoleComponent
+public sealed partial class SubvertedSiliconRoleComponent : BaseMindRoleComponent
{
}
namespace Content.Server.Roles;
+/// <summary>
+/// Added to mind role entities to tag that they are a thief.
+/// </summary>
[RegisterComponent]
-public sealed partial class ThiefRoleComponent : AntagonistRoleComponent
+public sealed partial class ThiefRoleComponent : BaseMindRoleComponent
{
}
namespace Content.Server.Roles;
-[RegisterComponent, ExclusiveAntagonist]
-public sealed partial class TraitorRoleComponent : AntagonistRoleComponent
+/// <summary>
+/// Added to mind role entities to tag that they are a syndicate traitor.
+/// </summary>
+[RegisterComponent]
+public sealed partial class TraitorRoleComponent : BaseMindRoleComponent
{
}
namespace Content.Server.Roles;
-[RegisterComponent, ExclusiveAntagonist]
-public sealed partial class ZombieRoleComponent : AntagonistRoleComponent
+/// <summary>
+/// Added to mind role entities to tag that they are a zombie.
+/// </summary>
+[RegisterComponent]
+public sealed partial class ZombieRoleComponent : BaseMindRoleComponent
{
}
public sealed class SiliconLawSystem : SharedSiliconLawSystem
{
[Dependency] private readonly IChatManager _chatManager = default!;
- [Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
+ [Dependency] private readonly IPrototypeManager _prototype = default!;
+ [Dependency] private readonly SharedRoleSystem _roles = default!;
[Dependency] private readonly StationSystem _station = default!;
- [Dependency] private readonly UserInterfaceSystem _userInterface = default!;
[Dependency] private readonly SharedStunSystem _stunSystem = default!;
- [Dependency] private readonly SharedRoleSystem _roles = default!;
+ [Dependency] private readonly UserInterfaceSystem _userInterface = default!;
/// <inheritdoc/>
public override void Initialize()
if (component.AntagonistRole == null || !_mind.TryGetMind(uid, out var mindId, out _))
return;
- if (_roles.MindHasRole<SubvertedSiliconRoleComponent>(mindId))
- return;
-
- _roles.MindAddRole(mindId, new SubvertedSiliconRoleComponent { PrototypeId = component.AntagonistRole });
+ if (!_roles.MindHasRole<SubvertedSiliconRoleComponent>(mindId))
+ _roles.MindAddRole(mindId, "MindRoleSubvertedSilicon");
}
public SiliconLawset GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null)
public sealed class ContainerSpawnPointSystem : EntitySystem
{
+ [Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
- [Dependency] private readonly ContainerSystem _container = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly StationSpawningSystem _stationSpawning = default!;
// If it's just a spawn pref check if it's for cryo (silly).
if (args.HumanoidCharacterProfile?.SpawnPriority != SpawnPriorityPreference.Cryosleep &&
- (!_proto.TryIndex(args.Job?.Prototype, out var jobProto) || jobProto.JobEntity == null))
+ (!_proto.TryIndex(args.Job, out var jobProto) || jobProto.JobEntity == null))
{
return;
}
if (spawnPoint.SpawnType == SpawnPointType.Unset)
{
// make sure we also check the job here for various reasons.
- if (spawnPoint.Job == null || spawnPoint.Job == args.Job?.Prototype)
+ if (spawnPoint.Job == null || spawnPoint.Job == args.Job)
possibleContainers.Add((uid, spawnPoint, container, xform));
continue;
}
if (_gameTicker.RunLevel != GameRunLevel.InRound &&
spawnPoint.SpawnType == SpawnPointType.Job &&
- (args.Job == null || spawnPoint.Job == args.Job.Prototype))
+ (args.Job == null || spawnPoint.Job == args.Job))
{
possibleContainers.Add((uid, spawnPoint, container, xform));
}
if (_gameTicker.RunLevel != GameRunLevel.InRound &&
spawnPoint.SpawnType == SpawnPointType.Job &&
- (args.Job == null || spawnPoint.Job == args.Job.Prototype))
+ (args.Job == null || spawnPoint.Job == args.Job))
{
possiblePositions.Add(xform.Coordinates);
}
-using System.Linq;
using Content.Server.Access.Systems;
using Content.Server.DetailExaminable;
using Content.Server.Humanoid;
using Content.Shared.PDA;
using Content.Shared.Preferences;
using Content.Shared.Preferences.Loadouts;
-using Content.Shared.Preferences.Loadouts.Effects;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Content.Shared.Roles;
-using Content.Shared.Roles.Jobs;
using Content.Shared.Station;
-using Content.Shared.StatusIcon;
using JetBrains.Annotations;
using Robust.Shared.Configuration;
using Robust.Shared.Map;
[PublicAPI]
public sealed class StationSpawningSystem : SharedStationSpawningSystem
{
- [Dependency] private readonly IConfigurationManager _configurationManager = default!;
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly SharedAccessSystem _accessSystem = default!;
[Dependency] private readonly ActorSystem _actors = default!;
- [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!;
+ [Dependency] private readonly ArrivalsSystem _arrivalsSystem = default!;
[Dependency] private readonly IdCardSystem _cardSystem = default!;
+ [Dependency] private readonly IConfigurationManager _configurationManager = default!;
+ [Dependency] private readonly ContainerSpawnPointSystem _containerSpawnPointSystem = default!;
+ [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!;
[Dependency] private readonly IdentitySystem _identity = default!;
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
[Dependency] private readonly PdaSystem _pdaSystem = default!;
- [Dependency] private readonly SharedAccessSystem _accessSystem = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
private bool _randomizeCharacters;
/// <remarks>
/// This only spawns the character, and does none of the mind-related setup you'd need for it to be playable.
/// </remarks>
- public EntityUid? SpawnPlayerCharacterOnStation(EntityUid? station, JobComponent? job, HumanoidCharacterProfile? profile, StationSpawningComponent? stationSpawning = null)
+ public EntityUid? SpawnPlayerCharacterOnStation(EntityUid? station, ProtoId<JobPrototype>? job, HumanoidCharacterProfile? profile, StationSpawningComponent? stationSpawning = null)
{
if (station != null && !Resolve(station.Value, ref stationSpawning))
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
/// <returns>The spawned entity</returns>
public EntityUid SpawnPlayerMob(
EntityCoordinates coordinates,
- JobComponent? job,
+ ProtoId<JobPrototype>? job,
HumanoidCharacterProfile? profile,
EntityUid? station,
EntityUid? entity = null)
{
- _prototypeManager.TryIndex(job?.Prototype ?? string.Empty, out var prototype);
+ _prototypeManager.TryIndex(job ?? string.Empty, out var prototype);
RoleLoadout? loadout = null;
// Need to get the loadout up-front to handle names if we use an entity spawn override.
return entity.Value;
}
- private void DoJobSpecials(JobComponent? job, EntityUid entity)
+ private void DoJobSpecials(ProtoId<JobPrototype>? job, EntityUid entity)
{
- if (!_prototypeManager.TryIndex(job?.Prototype ?? string.Empty, out JobPrototype? prototype))
+ if (!_prototypeManager.TryIndex(job ?? string.Empty, out JobPrototype? prototype))
return;
foreach (var jobSpecial in prototype.Special)
/// <summary>
/// The job to use, if any.
/// </summary>
- public readonly JobComponent? Job;
+ public readonly ProtoId<JobPrototype>? Job;
/// <summary>
/// The profile to use, if any.
/// </summary>
/// </summary>
public readonly EntityUid? Station;
- public PlayerSpawningEvent(JobComponent? job, HumanoidCharacterProfile? humanoidCharacterProfile, EntityUid? station)
+ public PlayerSpawningEvent(ProtoId<JobPrototype>? job, HumanoidCharacterProfile? humanoidCharacterProfile, EntityUid? station)
{
Job = job;
HumanoidCharacterProfile = humanoidCharacterProfile;
return true;
var roleSystem = ent.System<SharedRoleSystem>();
- var roles = roleSystem.MindGetAllRoles(mindId);
+ var roles = roleSystem.MindGetAllRoleInfo(mindId);
if (Blacklist != null)
{
foreach (var role in roles)
{
- if (role.Component is not AntagonistRoleComponent blacklistantag)
+ if (!role.Antagonist || string.IsNullOrEmpty(role.Prototype))
continue;
- if (blacklistantag.PrototypeId != null && Blacklist.Contains(blacklistantag.PrototypeId))
+ if (Blacklist.Contains(role.Prototype))
return false;
}
}
var found = false;
foreach (var role in roles)
{
- if (role.Component is not AntagonistRoleComponent antag)
+
+ if (!role.Antagonist || string.IsNullOrEmpty(role.Prototype))
continue;
- if (antag.PrototypeId != null && Whitelist.Contains(antag.PrototypeId))
+ if (Whitelist.Contains(role.Prototype))
found = true;
}
if (!found)
return true;
var jobs = ent.System<SharedJobSystem>();
- jobs.MindTryGetJob(mindId, out var job, out _);
+ jobs.MindTryGetJob(mindId, out var job);
- if (Blacklist != null && job?.Prototype != null)
+ if (Blacklist != null && job != null)
{
foreach (var department in prototypeManager.EnumeratePrototypes<DepartmentPrototype>())
{
- if (department.Roles.Contains(job.Prototype.Value) && Blacklist.Contains(department.ID))
+ if (department.Roles.Contains(job.ID) && Blacklist.Contains(department.ID))
return false;
}
}
{
var found = false;
- if (job?.Prototype != null)
+ if (job != null)
{
foreach (var department in prototypeManager.EnumeratePrototypes<DepartmentPrototype>())
{
- if (department.Roles.Contains(job.Prototype.Value) && Whitelist.Contains(department.ID))
+ if (department.Roles.Contains(job.ID) && Whitelist.Contains(department.ID))
{
found = true;
break;
return true;
var jobs = ent.System<SharedJobSystem>();
- jobs.MindTryGetJob(mindId, out var job, out _);
+ jobs.MindTryGetJob(mindId, out var job);
if (Blacklist != null)
{
- if (job?.Prototype != null && Blacklist.Contains(job.Prototype))
+ if (job is not null && Blacklist.Contains(job.ID))
return false;
}
if (Whitelist != null)
{
- if (job?.Prototype == null || !Whitelist.Contains(job.Prototype))
+ if (job == null || !Whitelist.Contains(job.ID))
return false;
}
using Content.Server.NPC;
using Content.Server.NPC.HTN;
using Content.Server.NPC.Systems;
-using Content.Server.Roles;
using Content.Server.Speech.Components;
using Content.Server.Temperature.Components;
using Content.Shared.CombatMode;
/// </remarks>
public sealed partial class ZombieSystem
{
- [Dependency] private readonly SharedHandsSystem _hands = default!;
- [Dependency] private readonly ServerInventorySystem _inventory = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly IChatManager _chatMan = default!;
+ [Dependency] private readonly SharedCombatModeSystem _combat = default!;
[Dependency] private readonly NpcFactionSystem _faction = default!;
- [Dependency] private readonly NPCSystem _npc = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearance = default!;
[Dependency] private readonly IdentitySystem _identity = default!;
- [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
- [Dependency] private readonly SharedCombatModeSystem _combat = default!;
- [Dependency] private readonly IChatManager _chatMan = default!;
+ [Dependency] private readonly ServerInventorySystem _inventory = default!;
[Dependency] private readonly MindSystem _mind = default!;
+ [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
+ [Dependency] private readonly NPCSystem _npc = default!;
[Dependency] private readonly SharedRoleSystem _roles = default!;
- [Dependency] private readonly SharedAudioSystem _audio = default!;
/// <summary>
/// Handles an entity turning into a zombie when they die or go into crit
if (hasMind && _mind.TryGetSession(mindId, out var session))
{
//Zombie role for player manifest
- _roles.MindAddRole(mindId, new ZombieRoleComponent { PrototypeId = zombiecomp.ZombieRoleId });
+ _roles.MindAddRole(mindId, "MindRoleZombie", mind: null, silent: true);
//Greeting message for new bebe zombers
_chatMan.DispatchServerMessage(session, Loc.GetString("zombie-infection-greeting"));
/// The mind controlling this mob. Can be null.
/// </summary>
[DataField, AutoNetworkedField]
- [Access(typeof(SharedMindSystem), Other = AccessPermissions.ReadWriteExecute)] // FIXME Friends
public EntityUid? Mind { get; set; }
/// <summary>
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("ghostOnShutdown")]
- [Access(typeof(SharedMindSystem), Other = AccessPermissions.ReadWriteExecute)] // FIXME Friends
public bool GhostOnShutdown { get; set; } = true;
}
-using Content.Shared.Actions;
using Content.Shared.GameTicking;
using Content.Shared.Mind.Components;
using Robust.Shared.GameStates;
/// <summary>
/// Prevents user from ghosting out
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("preventGhosting")]
+ [DataField]
public bool PreventGhosting { get; set; }
/// <summary>
/// Prevents user from suiciding
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("preventSuicide")]
+ [DataField]
public bool PreventSuicide { get; set; }
+ /// <summary>
+ /// Mind Role Entities belonging to this Mind
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public List<EntityUid> MindRoles = new List<EntityUid>();
+
/// <summary>
/// The session of the player owning this mind.
/// Can be null, in which case the player is currently not logged in.
+++ /dev/null
-using JetBrains.Annotations;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Shared.Roles;
-
-public abstract partial class AntagonistRoleComponent : Component
-{
- [DataField("prototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<AntagPrototype>))]
- public string? PrototypeId;
-}
-
-/// <summary>
-/// Mark the antagonist role component as being exclusive
-/// IE by default other antagonists should refuse to select the same entity for a different antag role
-/// </summary>
-[AttributeUsage(AttributeTargets.Class, Inherited = false)]
-[BaseTypeRequired(typeof(AntagonistRoleComponent))]
-public sealed partial class ExclusiveAntagonistAttribute : Attribute
-{
-}
+++ /dev/null
-using Robust.Shared.GameStates;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.Roles.Jobs;
-
-/// <summary>
-/// Added to mind entities to hold the data for the player's current job.
-/// </summary>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
-public sealed partial class JobComponent : Component
-{
- [DataField(required: true), AutoNetworkedField]
- public ProtoId<JobPrototype>? Prototype;
-}
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Roles.Jobs;
+
+/// <summary>
+/// Added to mind role entities to mark them as a job role entity.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class JobRoleComponent : BaseMindRoleComponent
+{
+
+}
/// </summary>
public abstract class SharedJobSystem : EntitySystem
{
- [Dependency] private readonly IPrototypeManager _prototypes = default!;
[Dependency] private readonly SharedPlayerSystem _playerSystem = default!;
+ [Dependency] private readonly IPrototypeManager _prototypes = default!;
+ [Dependency] private readonly SharedRoleSystem _roles = default!;
+
private readonly Dictionary<string, string> _inverseTrackerLookup = new();
public override void Initialize()
public bool MindHasJobWithId(EntityUid? mindId, string prototypeId)
{
- return CompOrNull<JobComponent>(mindId)?.Prototype == prototypeId;
+
+ MindRoleComponent? comp = null;
+ if (mindId is null)
+ return false;
+
+ _roles.MindHasRole<JobRoleComponent>(mindId.Value, out var role);
+
+ if (role is null)
+ return false;
+
+ comp = role.Value.Comp;
+
+ return (comp.JobPrototype == prototypeId);
}
public bool MindTryGetJob(
[NotNullWhen(true)] EntityUid? mindId,
- [NotNullWhen(true)] out JobComponent? comp,
[NotNullWhen(true)] out JobPrototype? prototype)
{
- comp = null;
prototype = null;
+ MindTryGetJobId(mindId, out var protoId);
- return TryComp(mindId, out comp) &&
- comp.Prototype != null &&
- _prototypes.TryIndex(comp.Prototype, out prototype);
+ return (_prototypes.TryIndex<JobPrototype>(protoId, out prototype) || prototype is not null);
}
- public bool MindTryGetJobId([NotNullWhen(true)] EntityUid? mindId, out ProtoId<JobPrototype>? job)
+ public bool MindTryGetJobId(
+ [NotNullWhen(true)] EntityUid? mindId,
+ out ProtoId<JobPrototype>? job)
{
- if (!TryComp(mindId, out JobComponent? comp))
- {
- job = null;
+ job = null;
+
+ if (mindId is null)
return false;
- }
- job = comp.Prototype;
- return true;
+ if (_roles.MindHasRole<JobRoleComponent>(mindId.Value, out var role))
+ job = role.Value.Comp.JobPrototype;
+
+ return (job is not null);
}
/// <summary>
/// </summary>
public bool MindTryGetJobName([NotNullWhen(true)] EntityUid? mindId, out string name)
{
- if (MindTryGetJob(mindId, out _, out var prototype))
+ if (MindTryGetJob(mindId, out var prototype))
{
name = prototype.LocalizedName;
return true;
if (_playerSystem.ContentData(player) is not { Mind: { } mindId })
return true;
- if (!MindTryGetJob(mindId, out _, out var prototype))
+ if (!MindTryGetJob(mindId, out var prototype))
return true;
return prototype.CanBeAntag;
/// </summary>
/// <param name="Roles">The list of roles on the player.</param>
[ByRefEvent]
-public readonly record struct MindGetAllRolesEvent(List<RoleInfo> Roles);
+public readonly record struct MindGetAllRoleInfoEvent(List<RoleInfo> Roles);
/// <summary>
/// Returned by <see cref="MindGetAllRolesEvent"/> to give some information about a player's role.
/// <param name="Antagonist">Whether or not this role makes this player an antagonist.</param>
/// <param name="PlayTimeTrackerId">The <see cref="PlayTimeTrackerPrototype"/> id associated with the role.</param>
/// <param name="Prototype">The prototype ID of the role</param>
-public readonly record struct RoleInfo(Component Component, string Name, bool Antagonist, string? PlayTimeTrackerId, string Prototype);
+public readonly record struct RoleInfo(string Name, bool Antagonist, string? PlayTimeTrackerId, string Prototype);
--- /dev/null
+using Content.Shared.Mind;
+using JetBrains.Annotations;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Roles;
+
+/// <summary>
+/// This holds data for, and indicates, a Mind Role entity
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class MindRoleComponent : BaseMindRoleComponent
+{
+ /// <summary>
+ /// Marks this Mind Role as Antagonist
+ /// A single antag Mind Role is enough to make the owner mind count as Antagonist.
+ /// </summary>
+ [DataField]
+ public bool Antag { get; set; } = false;
+
+ /// <summary>
+ /// True if this mindrole is an exclusive antagonist. Antag setting is not checked if this is True.
+ /// </summary>
+ [DataField]
+ public bool ExclusiveAntag { get; set; } = false;
+
+ /// <summary>
+ /// The Mind that this role belongs to
+ /// </summary>
+ public Entity<MindComponent> Mind { get; set; }
+
+ /// <summary>
+ /// The Antagonist prototype of this role
+ /// </summary>
+ [DataField]
+ public ProtoId<AntagPrototype>? AntagPrototype { get; set; }
+
+ /// <summary>
+ /// The Job prototype of this role
+ /// </summary>
+ [DataField]
+ public ProtoId<JobPrototype>? JobPrototype { get; set; }
+}
+
+public abstract partial class BaseMindRoleComponent : Component
+{
+
+}
+using System.Diagnostics.CodeAnalysis;
using Content.Shared.Administration.Logs;
using Content.Shared.CCVar;
using Content.Shared.Database;
-using Content.Shared.Ghost.Roles;
+using Content.Shared.GameTicking;
using Content.Shared.Mind;
using Content.Shared.Roles.Jobs;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
+using Robust.Shared.Map;
using Robust.Shared.Prototypes;
-using Robust.Shared.Utility;
namespace Content.Shared.Roles;
public abstract class SharedRoleSystem : EntitySystem
{
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
- [Dependency] private readonly IPrototypeManager _prototypes = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly SharedMindSystem _minds = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
-
- // TODO please lord make role entities
- private readonly HashSet<Type> _antagTypes = new();
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+ [Dependency] private readonly SharedGameTicker _gameTicker = default!;
+ [Dependency] private readonly IPrototypeManager _prototypes = default!;
private JobRequirementOverridePrototype? _requirementOverride;
public override void Initialize()
{
- // TODO make roles entities
- SubscribeLocalEvent<JobComponent, MindGetAllRolesEvent>(OnJobGetAllRoles);
Subs.CVar(_cfg, CCVars.GameRoleTimerOverride, SetRequirementOverride, true);
}
Log.Error($"Unknown JobRequirementOverridePrototype: {value}");
}
- private void OnJobGetAllRoles(EntityUid uid, JobComponent component, ref MindGetAllRolesEvent args)
+ /// <summary>
+ /// Adds multiple mind roles to a mind
+ /// </summary>
+ /// <param name="mindId">The mind entity to add the role to</param>
+ /// <param name="roles">The list of mind roles to add</param>
+ /// <param name="mind">If the mind component is provided, it will be checked if it belongs to the mind entity</param>
+ /// <param name="silent">If true, no briefing will be generated upon receiving the mind role</param>
+ public void MindAddRoles(EntityUid mindId,
+ List<ProtoId<EntityPrototype>>? roles,
+ MindComponent? mind = null,
+ bool silent = false)
{
- var name = "game-ticker-unknown-role";
- var prototype = "";
- string? playTimeTracker = null;
- if (component.Prototype != null && _prototypes.TryIndex(component.Prototype, out JobPrototype? job))
+ if (roles is null || roles.Count == 0)
+ return;
+
+ foreach (var proto in roles)
{
- name = job.Name;
- prototype = job.ID;
- playTimeTracker = job.PlayTimeTracker;
+ MindAddRole(mindId, proto, mind, silent);
}
+ }
- name = Loc.GetString(name);
-
- args.Roles.Add(new RoleInfo(component, name, false, playTimeTracker, prototype));
+ /// <summary>
+ /// Adds a mind role to a mind
+ /// </summary>
+ /// <param name="mindId">The mind entity to add the role to</param>
+ /// <param name="protoId">The mind role to add</param>
+ /// <param name="mind">If the mind component is provided, it will be checked if it belongs to the mind entity</param>
+ /// <param name="silent">If true, no briefing will be generated upon receiving the mind role</param>
+ public void MindAddRole(EntityUid mindId,
+ ProtoId<EntityPrototype> protoId,
+ MindComponent? mind = null,
+ bool silent = false)
+ {
+ if (protoId == "MindRoleJob")
+ MindAddJobRole(mindId, mind, silent, "");
+ else
+ MindAddRoleDo(mindId, protoId, mind, silent);
}
- protected void SubscribeAntagEvents<T>() where T : AntagonistRoleComponent
+ /// <summary>
+ /// Adds a Job mind role with the specified job prototype
+ /// </summary>
+ /// /// <param name="mindId">The mind entity to add the job role to</param>
+ /// <param name="mind">If the mind component is provided, it will be checked if it belongs to the mind entity</param>
+ /// <param name="silent">If true, no briefing will be generated upon receiving the mind role</param>
+ /// <param name="jobPrototype">The Job prototype for the new role</param>
+ public void MindAddJobRole(EntityUid mindId,
+ MindComponent? mind = null,
+ bool silent = false,
+ string? jobPrototype = null)
{
- SubscribeLocalEvent((EntityUid _, T component, ref MindGetAllRolesEvent args) =>
+ // Can't have someone get paid for two jobs now, can we
+ if (MindHasRole<JobRoleComponent>(mindId, out var jobRole)
+ && jobRole.Value.Comp.JobPrototype != jobPrototype)
{
- var name = "game-ticker-unknown-role";
- var prototype = "";
- if (component.PrototypeId != null && _prototypes.TryIndex(component.PrototypeId, out AntagPrototype? antag))
+ Resolve(mindId, ref mind);
+ if (mind is not null)
{
- name = antag.Name;
- prototype = antag.ID;
+ _adminLogger.Add(LogType.Mind,
+ LogImpact.Low,
+ $"Job Role of {ToPrettyString(mind.OwnedEntity)} changed from '{jobRole.Value.Comp.JobPrototype}' to '{jobPrototype}'");
}
- name = Loc.GetString(name);
-
- args.Roles.Add(new RoleInfo(component, name, true, null, prototype));
- });
- SubscribeLocalEvent((EntityUid _, T _, ref MindIsAntagonistEvent args) => { args.IsAntagonist = true; args.IsExclusiveAntagonist |= typeof(T).TryGetCustomAttribute<ExclusiveAntagonistAttribute>(out _); });
- _antagTypes.Add(typeof(T));
+ jobRole.Value.Comp.JobPrototype = jobPrototype;
+ }
+ else
+ MindAddRoleDo(mindId, "MindRoleJob", mind, silent, jobPrototype);
}
- public void MindAddRoles(EntityUid mindId, ComponentRegistry components, MindComponent? mind = null, bool silent = false)
+ /// <summary>
+ /// Creates a Mind Role
+ /// </summary>
+ private void MindAddRoleDo(EntityUid mindId,
+ ProtoId<EntityPrototype> protoId,
+ MindComponent? mind = null,
+ bool silent = false,
+ string? jobPrototype = null)
{
if (!Resolve(mindId, ref mind))
+ {
+ Log.Error($"Failed to add role {protoId} to mind {mindId} : Mind does not match provided mind component");
return;
+ }
- EntityManager.AddComponents(mindId, components);
var antagonist = false;
- foreach (var compReg in components.Values)
+
+ if (!_prototypes.TryIndex(protoId, out var protoEnt))
{
- var compType = compReg.Component.GetType();
+ Log.Error($"Failed to add role {protoId} to mind {mindId} : Role prototype does not exist");
+ return;
+ }
- var comp = EntityManager.ComponentFactory.GetComponent(compType);
- if (IsAntagonistRole(comp.GetType()))
- {
- antagonist = true;
- break;
- }
+ //TODO don't let a prototype being added a second time
+ //If that was somehow to occur, a second mindrole for that comp would be created
+ //Meaning any mind role checks could return wrong results, since they just return the first match they find
+
+ var mindRoleId = Spawn(protoId, MapCoordinates.Nullspace);
+ EnsureComp<MindRoleComponent>(mindRoleId);
+ var mindRoleComp = Comp<MindRoleComponent>(mindRoleId);
+
+ mindRoleComp.Mind = (mindId,mind);
+ if (jobPrototype is not null)
+ {
+ mindRoleComp.JobPrototype = jobPrototype;
+ EnsureComp<JobRoleComponent>(mindRoleId);
}
+ if (mindRoleComp.Antag || mindRoleComp.ExclusiveAntag)
+ antagonist = true;
+
+ mind.MindRoles.Add(mindRoleId);
+
var mindEv = new MindRoleAddedEvent(silent);
RaiseLocalEvent(mindId, ref mindEv);
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)}");
+ var name = Loc.GetString(protoEnt.Name);
+ if (mind.OwnedEntity is not null)
+ {
+ _adminLogger.Add(LogType.Mind,
+ LogImpact.Low,
+ $"{name} added to mind of {ToPrettyString(mind.OwnedEntity)}");
+ }
+ else
+ {
+ //TODO: This is not tied to the player on the Admin Log filters.
+ //Probably only happens when Job Role is added on initial spawn, before the mind entity is put in a mob
+ _adminLogger.Add(LogType.Mind,
+ LogImpact.Low,
+ $"{name} added to {ToPrettyString(mindId)}");
+ }
}
- public void MindAddRole(EntityUid mindId, Component component, MindComponent? mind = null, bool silent = false)
+ /// <summary>
+ /// Removes all instances of a specific role from this mind.
+ /// </summary>
+ /// <param name="mindId">The mind to remove the role from.</param>
+ /// <typeparam name="T">The type of the role to remove.</typeparam>
+ /// <exception cref="ArgumentException">Thrown if the mind does not exist or does not have this role.</exception>
+ /// <returns>Returns False if there was something wrong with the mind or the removal. True if successful</returns>>
+ public bool MindRemoveRole<T>(EntityUid mindId) where T : IComponent
{
- if (!Resolve(mindId, ref mind))
- return;
+ if (!TryComp<MindComponent>(mindId, out var mind) )
+ throw new ArgumentException($"{mindId} does not exist or does not have mind component");
- if (HasComp(mindId, component.GetType()))
+ var found = false;
+ var antagonist = false;
+ var delete = new List<EntityUid>();
+ foreach (var role in mind.MindRoles)
{
- throw new ArgumentException($"We already have this role: {component}");
+ if (!HasComp<T>(role))
+ continue;
+
+ var roleComp = Comp<MindRoleComponent>(role);
+ antagonist = roleComp.Antag;
+ _entityManager.DeleteEntity(role);
+
+ delete.Add(role);
+ found = true;
+
}
- EntityManager.AddComponent(mindId, component);
- var antagonist = IsAntagonistRole(component.GetType());
+ foreach (var role in delete)
+ {
+ mind.MindRoles.Remove(role);
+ }
- var mindEv = new MindRoleAddedEvent(silent);
- RaiseLocalEvent(mindId, ref mindEv);
+ if (!found)
+ {
+ throw new ArgumentException($"{mindId} does not have this role: {typeof(T)}");
+ }
+
+ var message = new RoleRemovedEvent(mindId, mind, antagonist);
- 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 {component}' added to mind of {_minds.MindOwnerLoggingString(mind)}");
+ _adminLogger.Add(LogType.Mind,
+ LogImpact.Low,
+ $"'Role {typeof(T).Name}' removed from mind of {ToPrettyString(mind.OwnedEntity)}");
+ return true;
}
/// <summary>
- /// Gives this mind a new role.
+ /// Finds and removes all mind roles of a specific type
/// </summary>
- /// <param name="mindId">The mind to add the role to.</param>
- /// <param name="component">The role instance to add.</param>
- /// <typeparam name="T">The role type to add.</typeparam>
- /// <param name="silent">Whether or not the role should be added silently</param>
- /// <returns>The instance of the role.</returns>
- /// <exception cref="ArgumentException">
- /// Thrown if we already have a role with this type.
- /// </exception>
- public void MindAddRole<T>(EntityUid mindId, T component, MindComponent? mind = null, bool silent = false) where T : IComponent, new()
+ /// <param name="mindId">The mind entity</param>
+ /// <typeparam name="T">The type of the role to remove.</typeparam>
+ /// <returns>True if the role existed and was removed</returns>
+ public bool MindTryRemoveRole<T>(EntityUid mindId) where T : IComponent
{
- if (!Resolve(mindId, ref mind))
- return;
-
- if (HasComp<T>(mindId))
+ if (!MindHasRole<T>(mindId))
{
- throw new ArgumentException($"We already have this role: {typeof(T)}");
+ Log.Warning($"Failed to remove role {typeof(T)} from {mindId} : mind does not have role ");
+ return false;
}
- AddComp(mindId, component);
- var antagonist = IsAntagonistRole<T>();
+ if (typeof(T) == typeof(MindRoleComponent))
+ return false;
- var mindEv = new MindRoleAddedEvent(silent);
- RaiseLocalEvent(mindId, ref mindEv);
+ return MindRemoveRole<T>(mindId);
+ }
- var message = new RoleAddedEvent(mindId, mind, antagonist, silent);
- if (mind.OwnedEntity != null)
+ /// <summary>
+ /// Finds the first mind role of a specific T type on a mind entity.
+ /// Outputs entity components for the mind role's MindRoleComponent and for T
+ /// </summary>
+ /// <param name="mindId">The mind entity</param>
+ /// <typeparam name="T">The type of the role to find.</typeparam>
+ /// <param name="role">The Mind Role entity component</param>
+ /// <param name="roleT">The Mind Role's entity component for T</param>
+ /// <returns>True if the role is found</returns>
+ public bool MindHasRole<T>(EntityUid mindId,
+ [NotNullWhen(true)] out Entity<MindRoleComponent>? role,
+ [NotNullWhen(true)] out Entity<T>? roleT) where T : IComponent
+ {
+ role = null;
+ roleT = null;
+
+ if (!TryComp<MindComponent>(mindId, out var mind))
+ return false;
+
+ var found = false;
+
+ foreach (var roleEnt in mind.MindRoles)
{
- RaiseLocalEvent(mind.OwnedEntity.Value, message, true);
+ if (!HasComp<T>(roleEnt))
+ continue;
+
+ role = (roleEnt,Comp<MindRoleComponent>(roleEnt));
+ roleT = (roleEnt,Comp<T>(roleEnt));
+ found = true;
+ break;
}
- _adminLogger.Add(LogType.Mind, LogImpact.Low,
- $"'Role {typeof(T).Name}' added to mind of {_minds.MindOwnerLoggingString(mind)}");
+ return found;
}
/// <summary>
- /// Removes a role from this mind.
+ /// Finds the first mind role of a specific type on a mind entity.
+ /// Outputs an entity component for the mind role's MindRoleComponent
/// </summary>
- /// <param name="mindId">The mind to remove the role from.</param>
- /// <typeparam name="T">The type of the role to remove.</typeparam>
- /// <exception cref="ArgumentException">
- /// Thrown if we do not have this role.
- /// </exception>
- public void MindRemoveRole<T>(EntityUid mindId) where T : IComponent
+ /// <param name="mindId">The mind entity</param>
+ /// <param name="type">The Type to look for</param>
+ /// <param name="role">The output role</param>
+ /// <returns>True if the role is found</returns>
+ public bool MindHasRole(EntityUid mindId,
+ Type type,
+ [NotNullWhen(true)] out Entity<MindRoleComponent>? role)
{
- if (!RemComp<T>(mindId))
+ role = null;
+ // All MindRoles have this component, it would just return the first one.
+ // Order might not be what is expected.
+ // Better to report null
+ if (type == Type.GetType("MindRoleComponent"))
{
- throw new ArgumentException($"We do not have this role: {typeof(T)}");
+ Log.Error($"Something attempted to query mind role 'MindRoleComponent' on mind {mindId}. This component is present on every single mind role.");
+ return false;
}
- var mind = Comp<MindComponent>(mindId);
- var antagonist = IsAntagonistRole<T>();
- var message = new RoleRemovedEvent(mindId, mind, antagonist);
+ if (!TryComp<MindComponent>(mindId, out var mind))
+ return false;
- if (mind.OwnedEntity != null)
+ var found = false;
+
+ foreach (var roleEnt in mind.MindRoles)
{
- RaiseLocalEvent(mind.OwnedEntity.Value, message, true);
+ if (!HasComp(roleEnt, type))
+ continue;
+
+ role = (roleEnt,Comp<MindRoleComponent>(roleEnt));
+ found = true;
+ break;
}
- _adminLogger.Add(LogType.Mind, LogImpact.Low,
- $"'Role {typeof(T).Name}' removed from mind of {_minds.MindOwnerLoggingString(mind)}");
+
+ return found;
}
- public bool MindTryRemoveRole<T>(EntityUid mindId) where T : IComponent
+ /// <summary>
+ /// Finds the first mind role of a specific type on a mind entity.
+ /// Outputs an entity component for the mind role's MindRoleComponent
+ /// </summary>
+ /// <param name="mindId">The mind entity</param>
+ /// <param name="role">The Mind Role entity component</param>
+ /// <typeparam name="T">The type of the role to find.</typeparam>
+ /// <returns>True if the role is found</returns>
+ public bool MindHasRole<T>(EntityUid mindId,
+ [NotNullWhen(true)] out Entity<MindRoleComponent>? role) where T : IComponent
{
- if (!MindHasRole<T>(mindId))
- return false;
-
- MindRemoveRole<T>(mindId);
- return true;
+ return MindHasRole<T>(mindId, out role, out _);
}
+ /// <summary>
+ /// Finds the first mind role of a specific type on a mind entity.
+ /// </summary>
+ /// <param name="mindId">The mind entity</param>
+ /// <typeparam name="T">The type of the role to find.</typeparam>
+ /// <returns>True if the role is found</returns>
public bool MindHasRole<T>(EntityUid mindId) where T : IComponent
{
- DebugTools.Assert(HasComp<MindComponent>(mindId));
- return HasComp<T>(mindId);
+ return MindHasRole<T>(mindId, out _, out _);
}
- public List<RoleInfo> MindGetAllRoles(EntityUid mindId)
+ //TODO: Delete this later
+ /// <summary>
+ /// Returns the first mind role of a specific type
+ /// </summary>
+ /// <param name="mindId">The mind entity</param>
+ /// <returns>Entity Component of the mind role</returns>
+ [Obsolete("Use MindHasRole's output value")]
+ public Entity<MindRoleComponent>? MindGetRole<T>(EntityUid mindId) where T : IComponent
{
- DebugTools.Assert(HasComp<MindComponent>(mindId));
- var ev = new MindGetAllRolesEvent(new List<RoleInfo>());
- RaiseLocalEvent(mindId, ref ev);
- return ev.Roles;
+ Entity<MindRoleComponent>? result = null;
+
+ var mind = Comp<MindComponent>(mindId);
+
+ foreach (var uid in mind.MindRoles)
+ {
+ if (HasComp<T>(uid) && TryComp<MindRoleComponent>(uid, out var comp))
+ result = (uid,comp);
+ }
+ return result;
}
+ /// <summary>
+ /// Reads all Roles of a mind Entity and returns their data as RoleInfo
+ /// </summary>
+ /// <param name="mindId">The mind entity</param>
+ /// <returns>RoleInfo list</returns>
+ public List<RoleInfo> MindGetAllRoleInfo(EntityUid mindId)
+ {
+ var roleInfo = new List<RoleInfo>();
+
+ if (!TryComp<MindComponent>(mindId, out var mind))
+ return roleInfo;
+
+ foreach (var role in mind.MindRoles)
+ {
+ var valid = false;
+ var name = "game-ticker-unknown-role";
+ var prototype = "";
+ string? playTimeTracker = null;
+
+ var comp = Comp<MindRoleComponent>(role);
+ if (comp.AntagPrototype is not null)
+ {
+ prototype = comp.AntagPrototype;
+ }
+
+ if (comp.JobPrototype is not null && comp.AntagPrototype is null)
+ {
+ prototype = comp.JobPrototype;
+ if (_prototypes.TryIndex(comp.JobPrototype, out var job))
+ {
+ playTimeTracker = job.PlayTimeTracker;
+ name = job.Name;
+ valid = true;
+ }
+ else
+ {
+ Log.Error($" Mind Role Prototype '{role.Id}' contains invalid Job prototype: '{comp.JobPrototype}'");
+ }
+ }
+ else if (comp.AntagPrototype is not null && comp.JobPrototype is null)
+ {
+ prototype = comp.AntagPrototype;
+ if (_prototypes.TryIndex(comp.AntagPrototype, out var antag))
+ {
+ name = antag.Name;
+ valid = true;
+ }
+ else
+ {
+ Log.Error($" Mind Role Prototype '{role.Id}' contains invalid Antagonist prototype: '{comp.AntagPrototype}'");
+ }
+ }
+ else if (comp.JobPrototype is not null && comp.AntagPrototype is not null)
+ {
+ Log.Error($" Mind Role Prototype '{role.Id}' contains both Job and Antagonist prototypes");
+ }
+
+ if (valid)
+ roleInfo.Add(new RoleInfo(name, comp.Antag || comp.ExclusiveAntag , playTimeTracker, prototype));
+ }
+ return roleInfo;
+ }
+
+ /// <summary>
+ /// Does this mind possess an antagonist role
+ /// </summary>
+ /// <param name="mindId">The mind entity</param>
+ /// <returns>True if the mind possesses any antag roles</returns>
public bool MindIsAntagonist(EntityUid? mindId)
{
- if (mindId == null)
+ if (mindId is null)
+ {
+ Log.Warning($"Antagonist status of mind entity {mindId} could not be determined - mind entity not found");
return false;
+ }
- DebugTools.Assert(HasComp<MindComponent>(mindId));
- var ev = new MindIsAntagonistEvent();
- RaiseLocalEvent(mindId.Value, ref ev);
- return ev.IsAntagonist;
+ return CheckAntagonistStatus(mindId.Value).Item1;
}
/// <summary>
/// Does this mind possess an exclusive antagonist role
/// </summary>
/// <param name="mindId">The mind entity</param>
- /// <returns>True if the mind possesses an exclusive antag role</returns>
+ /// <returns>True if the mind possesses any exclusive antag roles</returns>
public bool MindIsExclusiveAntagonist(EntityUid? mindId)
{
- if (mindId == null)
+ if (mindId is null)
+ {
+ Log.Warning($"Antagonist status of mind entity {mindId} could not be determined - mind entity not found");
return false;
+ }
- var ev = new MindIsAntagonistEvent();
- RaiseLocalEvent(mindId.Value, ref ev);
- return ev.IsExclusiveAntagonist;
+ return CheckAntagonistStatus(mindId.Value).Item2;
}
- public bool IsAntagonistRole<T>()
- {
- return _antagTypes.Contains(typeof(T));
- }
+ private (bool, bool) CheckAntagonistStatus(EntityUid mindId)
+ {
+ if (!TryComp<MindComponent>(mindId, out var mind))
+ {
+ Log.Warning($"Antagonist status of mind entity {mindId} could not be determined - mind component not found");
+ return (false, false);
+ }
- public bool IsAntagonistRole(Type component)
- {
- return _antagTypes.Contains(component);
+ var antagonist = false;
+ var exclusiveAntag = false;
+ foreach (var role in mind.MindRoles)
+ {
+ var roleComp = Comp<MindRoleComponent>(role);
+ if (roleComp.Antag || exclusiveAntag)
+ antagonist = true;
+ if (roleComp.ExclusiveAntag)
+ exclusiveAntag = true;
+ }
+
+ return (antagonist, exclusiveAntag);
}
/// <summary>
[DataField] public string[]? Components;
// TODO yaml validation
+ /// <summary>
+ /// Mind Role Prototype names that are allowed in the whitelist.
+ /// </summary>
+ [DataField] public string[]? MindRoles;
+ // TODO yaml validation
+
/// <summary>
/// Item sizes that are allowed in the whitelist.
/// </summary>
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Item;
+using Content.Shared.Roles;
using Content.Shared.Tag;
namespace Content.Shared.Whitelist;
public sealed class EntityWhitelistSystem : EntitySystem
{
[Dependency] private readonly IComponentFactory _factory = default!;
+ [Dependency] private readonly SharedRoleSystem _roles = default!;
[Dependency] private readonly TagSystem _tag = default!;
private EntityQuery<ItemComponent> _itemQuery;
public bool IsValid(EntityWhitelist list, EntityUid uid)
{
if (list.Components != null)
- EnsureRegistrations(list);
+ {
+ var regs = StringsToRegs(list.Components);
+
+ list.Registrations ??= new List<ComponentRegistration>();
+ list.Registrations.AddRange(regs);
+ }
+
+ if (list.MindRoles != null)
+ {
+ var regs = StringsToRegs(list.MindRoles);
+
+ foreach (var role in regs)
+ {
+ if ( _roles.MindHasRole(uid, role.Type, out _))
+ {
+ if (!list.RequireAll)
+ return true;
+ }
+ else if (list.RequireAll)
+ return false;
+ }
+ }
- if (list.Registrations != null)
+ if (list.Registrations != null && list.Registrations.Count > 0)
{
foreach (var reg in list.Registrations)
{
return IsWhitelistPassOrNull(blacklist, uid);
}
- /// <summary>
+ /// <summary>
/// Helper function to determine if Blacklist is either null or the entity is not on the list
/// Duplicate of equivalent Whitelist function
/// </summary>
return IsWhitelistFailOrNull(blacklist, uid);
}
- private void EnsureRegistrations(EntityWhitelist list)
+ private List<ComponentRegistration> StringsToRegs(string[]? input)
{
- if (list.Components == null)
- return;
+ var list = new List<ComponentRegistration>();
- list.Registrations = new List<ComponentRegistration>();
- foreach (var name in list.Components)
+ if (input == null || input.Length == 0)
+ return list;
+
+ foreach (var name in input)
{
var availability = _factory.GetComponentAvailability(name);
if (_factory.TryGetRegistration(name, out var registration)
&& availability == ComponentAvailability.Available)
{
- list.Registrations.Add(registration);
+ list.Add(registration);
}
else if (availability == ComponentAvailability.Unknown)
{
- Log.Warning($"Unknown component name {name} passed to EntityWhitelist!");
+ Log.Error($"StringsToRegs failed: Unknown component name {name} passed to EntityWhitelist!");
}
}
+
+ return list;
}
}
nukeops-welcome =
You are a nuclear operative. Your goal is to blow up {$station}, and ensure that it is nothing but a pile of rubble. Your bosses, the Syndicate, have provided you with the tools you'll need for the task.
Operation {$name} is a go ! Death to Nanotrasen!
+nukeops-briefing = Your objectives are simple. Deliver the payload and make sure it detonates. Begin mission.
nukeops-opsmajor = [color=crimson]Syndicate major victory![/color]
nukeops-opsminor = [color=crimson]Syndicate minor victory![/color]
min: 1
max: 1
pickPlayer: false
- mindComponents:
- - type: DragonRole
- prototype: Dragon
+ mindRoles:
+ - MindRoleDragon
- type: entity
parent: BaseGameRule
nameSegments:
- names_ninja_title
- names_ninja
- mindComponents:
- - type: NinjaRole
- prototype: SpaceNinja
+ mindRoles:
+ - MindRoleNinja
- type: entity
parent: BaseGameRule
- type: ZombifyOnDeath
- type: IncurableZombie
- type: InitialInfected
- mindComponents:
- - type: InitialInfectedRole
- prototype: InitialInfected
+ mindRoles:
+ - MindRoleInitialInfected
- type: entity
parent: BaseNukeopsRule
startingGear: SyndicateLoneOperativeGearFull
roleLoadout:
- RoleSurvivalNukie
-
components:
- type: NukeOperative
- type: RandomMetadata
- type: NpcFactionMember
factions:
- Syndicate
- mindComponents:
- - type: NukeopsRole
- prototype: Nukeops
+ mindRoles:
+ - MindRoleNukeops
- type: entity
parent: BaseTraitorRule
blacklist:
components:
- AntagImmune
- mindComponents:
- - type: TraitorRole
- prototype: TraitorSleeper
+ mindRoles:
+ - MindRoleTraitorSleeper
- type: entity
id: MassHallucinations
startingGear: ThiefGear
components:
- type: Pacified
- mindComponents:
- - type: ThiefRole
- prototype: Thief
+ mindRoles:
+ - MindRoleThief
briefing:
sound: "/Audio/Misc/thief_greeting.ogg"
- type: NpcFactionMember
factions:
- Syndicate
- mindComponents:
- - type: NukeopsRole
- prototype: NukeopsCommander
+ mindRoles:
+ - MindRoleNukeopsCommander
- prefRoles: [ NukeopsMedic ]
fallbackRoles: [ Nukeops, NukeopsCommander ]
spawnerPrototype: SpawnPointNukeopsMedic
- type: NpcFactionMember
factions:
- Syndicate
- mindComponents:
- - type: NukeopsRole
- prototype: NukeopsMedic
+ mindRoles:
+ - MindRoleNukeopsMedic
- prefRoles: [ Nukeops ]
fallbackRoles: [ NukeopsCommander, NukeopsMedic ]
spawnerPrototype: SpawnPointNukeopsOperative
- type: NpcFactionMember
factions:
- Syndicate
- mindComponents:
- - type: NukeopsRole
- prototype: Nukeops
+ mindRoles:
+ - MindRoleNukeops
- type: entity
abstract: true
components:
- AntagImmune
lateJoinAdditional: true
- mindComponents:
- - type: TraitorRole
- prototype: Traitor
+ mindRoles:
+ - MindRoleTraitor
- type: entity
id: Revolutionary
components:
- type: Revolutionary
- type: HeadRevolutionary
- mindComponents:
- - type: RevolutionaryRole
- prototype: HeadRev
+ mindRoles:
+ - MindRoleHeadRevolutionary
- type: entity
id: Sandbox
- type: ZombifyOnDeath
- type: IncurableZombie
- type: InitialInfected
- mindComponents:
- - type: InitialInfectedRole
- prototype: InitialInfected
+ mindRoles:
+ - MindRoleInitialInfected
# event schedulers
issuer: objective-issuer-dragon
- type: RoleRequirement
roles:
- components:
+ mindRoles:
- DragonRole
- type: entity
issuer: objective-issuer-spiderclan
- type: RoleRequirement
roles:
- components:
+ mindRoles:
- NinjaRole
- type: entity
issuer: objective-issuer-thief
- type: RoleRequirement
roles:
- components:
+ mindRoles:
- ThiefRole
- type: entity
issuer: objective-issuer-syndicate
- type: RoleRequirement
roles:
- components:
+ mindRoles:
- TraitorRole
- type: entity
--- /dev/null
+- type: entity
+ id: BaseMindRole
+ name: Mind Role
+ description: Mind Role entity
+ abstract: true
+ components:
+ - type: MindRole
+
+- type: entity
+ parent: BaseMindRole
+ id: BaseMindRoleAntag
+ abstract: true
+ components:
+ - type: MindRole
+ antag: true
+
+#Observer
+- type: entity
+ parent: BaseMindRole
+ id: MindRoleObserver
+ name: Observer Role
+ components:
+ - type: ObserverRole
+
+#Ghostrole Marker
+- type: entity
+ parent: BaseMindRole
+ id: MindRoleGhostMarker
+ name: Ghost Role
+ components:
+ - type: GhostRoleMarkerRole
+
+# The Job MindRole holds the mob's Job prototype
+- type: entity
+ parent: BaseMindRole
+ id: MindRoleJob
+ name: Job Role
+# description:
+ # MindRoleComponent.JobPrototype is filled by SharedJobSystem
+
+# Subverted Silicon
+- type: entity
+ parent: BaseMindRoleAntag
+ id: MindRoleSubvertedSilicon
+ name: Subverted Silicon Role
+ description:
+ components:
+ - type: SubvertedSiliconRole
+
+# Dragon
+- type: entity
+ parent: BaseMindRoleAntag
+ id: MindRoleDragon
+ name: Dragon Role
+# description:
+ components:
+ - type: MindRole
+ antagPrototype: Dragon
+ exclusiveAntag: true
+ - type: DragonRole
+ - type: RoleBriefing
+ briefing: dragon-role-briefing
+
+# Ninja
+- type: entity
+ parent: BaseMindRoleAntag
+ id: MindRoleNinja
+ name: Space Ninja Role
+# description: mind-role-ninja-description
+ components:
+ - type: MindRole
+ antagPrototype: SpaceNinja
+ exclusiveAntag: true
+ - type: NinjaRole
+
+# Nukies
+- type: entity
+ parent: BaseMindRoleAntag
+ id: MindRoleNukeops
+ name: Nukeops Operative Role
+# description: mind-role-nukeops-description
+ components:
+ - type: MindRole
+ exclusiveAntag: true
+ antagPrototype: Nukeops
+ - type: NukeopsRole
+
+- type: entity
+ parent: MindRoleNukeops
+ id: MindRoleNukeopsMedic
+ name: Nukeops Medic Role
+# description: mind-role-nukeops-medic-description
+ components:
+ - type: MindRole
+ antagPrototype: NukeopsMedic
+
+- type: entity
+ parent: MindRoleNukeops
+ id: MindRoleNukeopsCommander
+ name: Nukeops Commander Role
+# description: mind-role-nukeops-commander-description
+ components:
+ - type: MindRole
+ antagPrototype: NukeopsCommander
+
+# Revolutionaries
+- type: entity
+ parent: BaseMindRoleAntag
+ id: MindRoleHeadRevolutionary
+ name: Head Revolutionary Role
+# description: mind-role-head-revolutionary-description
+ components:
+ - type: MindRole
+ antagPrototype: HeadRev
+ exclusiveAntag: true
+ - type: RevolutionaryRole
+
+- type: entity
+ parent: MindRoleHeadRevolutionary
+ id: MindRoleRevolutionary
+ name: Revolutionary Role
+# description: mind-role-revolutionary-description
+ components:
+ - type: MindRole
+ antagPrototype: Rev
+
+# Thief
+- type: entity
+ parent: BaseMindRoleAntag
+ id: MindRoleThief
+ name: Thief Role
+# description: mind-role-thief-description
+ components:
+ - type: MindRole
+ antagPrototype: Thief
+ - type: ThiefRole
+
+# Traitors
+- type: entity
+ parent: BaseMindRoleAntag
+ id: MindRoleTraitor
+ name: Traitor Role
+# description: mind-role-traitor-description
+ components:
+ - type: MindRole
+ antagPrototype: Traitor
+ exclusiveAntag: true
+ - type: TraitorRole
+
+- type: entity
+ parent: MindRoleTraitor
+ id: MindRoleTraitorSleeper
+ name: Sleeper Agent Role
+# description: mind-role-traitor-sleeper-description
+ components:
+ - type: MindRole
+ antagPrototype: TraitorSleeper
+
+# Zombie Squad
+- type: entity
+ parent: BaseMindRoleAntag
+ id: MindRoleInitialInfected
+ name: Initial Infected Role
+# description: mind-role-initial-infected-description
+ components:
+ - type: MindRole
+ antagPrototype: InitialInfected
+ exclusiveAntag: true
+ - type: InitialInfectedRole
+
+- type: entity
+ parent: BaseMindRoleAntag
+ id: MindRoleZombie
+ name: Zombie Role
+# description: mind-role-zombie-description
+ components:
+ - type: MindRole
+ antagPrototype: Zombie
+ exclusiveAntag: true
+ - type: ZombieRole