Merge 94652731d7 into 68582ff296
|
|
@ -262,6 +262,32 @@ public sealed partial class AdminVerbSystem
|
|||
Message = string.Join(": ", ntAgent, Loc.GetString("admin-verb-text-make-NTAgent")),
|
||||
};
|
||||
args.Verbs.Add(agent);
|
||||
|
||||
args.Verbs.Add(new ()
|
||||
{
|
||||
Text = Loc.GetString("admin-verb-make-HeadInsurgent.text"),
|
||||
Category = VerbCategory.Antag,
|
||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Misc/job_icons.rsi"), "HeadRevolutionary"),
|
||||
Act = () =>
|
||||
{
|
||||
_antag.ForceMakeAntag<NTAgentRuleComponent>(targetPlayer, "UprisingRule", "HeadInsurgent");
|
||||
},
|
||||
Impact = LogImpact.High,
|
||||
Message = Loc.GetString("admin-verb-make-HeadInsurgent.message"),
|
||||
});
|
||||
|
||||
args.Verbs.Add(new ()
|
||||
{
|
||||
Text = Loc.GetString("admin-verb-make-HeadLoyalist.text"),
|
||||
Category = VerbCategory.Antag,
|
||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Misc/job_icons.rsi"), "Nanotrasen"),
|
||||
Act = () =>
|
||||
{
|
||||
_antag.ForceMakeAntag<NTAgentRuleComponent>(targetPlayer, "UprisingRule", "HeadLoyalist");
|
||||
},
|
||||
Impact = LogImpact.High,
|
||||
Message = Loc.GetString("admin-verb-make-HeadLoyalist.message"),
|
||||
});
|
||||
// End DeltaV Additions
|
||||
// start DeltaV Additions - add hitman
|
||||
var hitmanName = Loc.GetString("admin-verb-make-hitman");
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ public sealed partial class AntagSelectionSystem
|
|||
/// </summary>
|
||||
public bool TryGetNextAvailableDefinition(Entity<AntagSelectionComponent> ent,
|
||||
[NotNullWhen(true)] out AntagSelectionDefinition? definition,
|
||||
int? players = null)
|
||||
int? players = null,
|
||||
string? preferredRole = null) // DeltaV - preferrec roles
|
||||
{
|
||||
definition = null;
|
||||
|
||||
|
|
@ -39,6 +40,11 @@ public sealed partial class AntagSelectionSystem
|
|||
// It needs to track selected minds for each definition independently.
|
||||
foreach (var def in ent.Comp.Definitions)
|
||||
{
|
||||
// Begin DeltaV - preferred roles
|
||||
if (preferredRole is not null && !def.PrefRoles.Contains(preferredRole))
|
||||
continue;
|
||||
// End DeltaV - preferred roles
|
||||
|
||||
var target = GetTargetAntagCount(ent, null, def);
|
||||
|
||||
if (mindCount < target)
|
||||
|
|
@ -336,11 +342,11 @@ public sealed partial class AntagSelectionSystem
|
|||
/// This technically is a gamerule-ent-less way to make an entity an antag.
|
||||
/// You should almost never be using this.
|
||||
/// </summary>
|
||||
public void ForceMakeAntag<T>(ICommonSession? player, string defaultRule) where T : Component
|
||||
public void ForceMakeAntag<T>(ICommonSession? player, string defaultRule, string? preferredRole = null) where T : Component // DeltaV - preferred antag roles
|
||||
{
|
||||
var rule = ForceGetGameRuleEnt<T>(defaultRule);
|
||||
|
||||
if (!TryGetNextAvailableDefinition(rule, out var def))
|
||||
if (!TryGetNextAvailableDefinition(rule, out var def, preferredRole: preferredRole)) // DeltaV - preferred antag roles
|
||||
def = rule.Comp.Definitions.Last();
|
||||
MakeAntag(rule, player, def.Value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ public sealed class NukeSystem : EntitySystem
|
|||
/// <summary>
|
||||
/// Force a nuclear bomb to start a countdown timer
|
||||
/// </summary>
|
||||
public void ArmBomb(EntityUid uid, NukeComponent? component = null)
|
||||
public void ArmBomb(EntityUid uid, NukeComponent? component = null, string? announcementId = null) // DeltaV - custom announcements
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
|
@ -500,7 +500,7 @@ public sealed class NukeSystem : EntitySystem
|
|||
_selectedNukeSong = _audio.ResolveSound(component.ArmMusic);
|
||||
|
||||
// warn a crew
|
||||
var announcement = Loc.GetString("nuke-component-announcement-armed",
|
||||
var announcement = Loc.GetString(announcementId ?? "nuke-component-announcement-armed", // DeltaV - custom announcements
|
||||
("time", (int) component.RemainingTime),
|
||||
("location", FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString((uid, nukeXform)))));
|
||||
var sender = Loc.GetString("nuke-component-announcement-sender");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
using Content.Server.Revolutionary.Components;
|
||||
using Content.Shared._DV.Uprising;
|
||||
using Content.Shared.Cuffs.Components;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Station;
|
||||
|
||||
namespace Content.Server.Uprising;
|
||||
|
||||
public sealed class CommandStatusObjectiveSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedRoleSystem _role = default!;
|
||||
[Dependency] private readonly SharedStationSystem _station = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CommandStatusObjectiveComponent, ObjectiveGetProgressEvent>(OnGetProgress);
|
||||
}
|
||||
|
||||
private bool CheckIncapacitated(EntityUid uid)
|
||||
{
|
||||
if (TryComp<CuffableComponent>(uid, out var cuffed) && cuffed.CuffedHandCount > 0)
|
||||
return true;
|
||||
|
||||
if (!TryComp<MobStateComponent>(uid, out var state))
|
||||
return true;
|
||||
|
||||
if (state.CurrentState is MobState.Dead or MobState.Invalid)
|
||||
return true;
|
||||
|
||||
if (_station.GetOwningStation(uid) == null)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnGetProgress(Entity<CommandStatusObjectiveComponent> ent, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
var total = 0;
|
||||
var counted = 0;
|
||||
|
||||
var query = AllEntityQuery<MindContainerComponent, CommandStaffComponent>();
|
||||
while (query.MoveNext(out var uid, out var mind, out _))
|
||||
{
|
||||
if (mind.Mind is not { } mindUid)
|
||||
continue;
|
||||
|
||||
total++;
|
||||
|
||||
var converted = false;
|
||||
foreach (var role in ent.Comp.ConvertedRoles)
|
||||
{
|
||||
if (!EntityManager.ComponentFactory.TryGetRegistration(role, out var roleReg))
|
||||
{
|
||||
Log.Error($"Role component not found for CrewConversionObjective: {role}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_role.MindHasRole(mindUid, roleReg.Type, out _))
|
||||
continue;
|
||||
|
||||
converted = true;
|
||||
break;
|
||||
}
|
||||
|
||||
var incapacitated = CheckIncapacitated(uid);
|
||||
|
||||
if (converted && !incapacitated || !converted && ent.Comp.ShouldUnconvertedBeIncapacitated && incapacitated)
|
||||
{
|
||||
counted++;
|
||||
}
|
||||
}
|
||||
|
||||
if (total == 0)
|
||||
return;
|
||||
|
||||
args.Progress = (float)counted / (float)total;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace Content.Server._DV.Uprising;
|
||||
|
||||
[RegisterComponent, Access(typeof(UprisingRuleSystem))]
|
||||
public sealed partial class UprisingConsoleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public TimeSpan Delay = TimeSpan.FromSeconds(5);
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
using Content.Shared._DV.Roles;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Server._DV.Uprising;
|
||||
|
||||
[RegisterComponent, Access(typeof(UprisingRuleSystem)), AutoGenerateComponentPause]
|
||||
public sealed partial class UprisingRuleComponent : Component
|
||||
{
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
|
||||
public TimeSpan? NukeAnnouncementAt;
|
||||
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
|
||||
public TimeSpan? NukeTimeAt;
|
||||
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
|
||||
public TimeSpan? FirstWarningAt;
|
||||
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
|
||||
public TimeSpan? ImpendingWarningAt;
|
||||
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
|
||||
public TimeSpan? FinalWarningAt;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan NukeAnnouncementDelay = TimeSpan.FromMinutes(30);
|
||||
|
||||
[DataField]
|
||||
public TimeSpan NukeTimeDelay = TimeSpan.FromMinutes(90);
|
||||
|
||||
[DataField]
|
||||
public TimeSpan FirstWarning = TimeSpan.FromMinutes(30);
|
||||
|
||||
[DataField]
|
||||
public TimeSpan ImpendingWarning = TimeSpan.FromMinutes(15);
|
||||
|
||||
[DataField]
|
||||
public TimeSpan FinalWarning = TimeSpan.FromMinutes(5);
|
||||
|
||||
[DataField]
|
||||
public float NukeDuration = 60f;
|
||||
|
||||
[DataField]
|
||||
public (UprisingSide, TimeSpan)? SideWinsAt;
|
||||
|
||||
[DataField]
|
||||
public UprisingSide? SideWon;
|
||||
|
||||
[DataField]
|
||||
public Dictionary<UprisingSide, TimeSpan> SideTimes = new()
|
||||
{
|
||||
{ UprisingSide.Insurgent , TimeSpan.FromMinutes(3) },
|
||||
{ UprisingSide.Loyalist , TimeSpan.FromMinutes(3) },
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Antag;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Server.Nuke;
|
||||
using Content.Server.Pinpointer;
|
||||
using Content.Server.Roles;
|
||||
using Content.Shared._DV.Roles;
|
||||
using Content.Shared._DV.Uprising;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Objectives.Systems;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server._DV.Uprising;
|
||||
|
||||
public sealed class UprisingRuleSystem : GameRuleSystem<UprisingRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly SharedChatSystem _chat = default!;
|
||||
[Dependency] private readonly NukeSystem _nuke = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||
[Dependency] private readonly NavMapSystem _navMap = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
||||
[Dependency] private readonly SharedRoleSystem _role = default!;
|
||||
[Dependency] private readonly AntagSelectionSystem _antag = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _player = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<LoyalistRoleComponent, GetBriefingEvent>(OnGetLoyalistBriefing);
|
||||
SubscribeLocalEvent<InsurgentRoleComponent, GetBriefingEvent>(OnGetInsurgentBriefing);
|
||||
|
||||
SubscribeLocalEvent<UprisingVictoryObjectiveComponent, ObjectiveGetProgressEvent>(OnUprisingVictoryProgress);
|
||||
|
||||
SubscribeLocalEvent<UprisingConsoleComponent, GetVerbsEvent<AlternativeVerb>>(OnGetConsoleVerbs);
|
||||
SubscribeLocalEvent<UprisingConsoleComponent, UprisingArmDoAfter>(OnArm);
|
||||
SubscribeLocalEvent<UprisingConsoleComponent, UprisingDisarmDoAfter>(OnDisarm);
|
||||
}
|
||||
|
||||
private void OnUprisingVictoryProgress(Entity<UprisingVictoryObjectiveComponent> ent, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
if (GetRule() is not { } rule)
|
||||
return;
|
||||
|
||||
if (rule.Comp1.SideWinsAt is var (side, _) && ent.Comp.Side == side)
|
||||
args.Progress = 0.5f;
|
||||
else if (rule.Comp1.SideWon == ent.Comp.Side)
|
||||
args.Progress = 1f;
|
||||
else
|
||||
args.Progress = 0f;
|
||||
}
|
||||
|
||||
protected override void Started(EntityUid uid, UprisingRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
|
||||
{
|
||||
base.Started(uid, component, gameRule, args);
|
||||
|
||||
component.NukeAnnouncementAt = Timing.CurTime + component.NukeAnnouncementDelay;
|
||||
component.NukeTimeAt = Timing.CurTime + component.NukeTimeDelay;
|
||||
component.FirstWarningAt = component.NukeTimeAt - component.FirstWarning;
|
||||
component.ImpendingWarningAt = component.NukeTimeAt - component.ImpendingWarning;
|
||||
component.FinalWarningAt = component.NukeTimeAt - component.FinalWarning;
|
||||
}
|
||||
|
||||
protected override void ActiveTick(EntityUid uid, UprisingRuleComponent component, GameRuleComponent gameRule, float frameTime)
|
||||
{
|
||||
base.ActiveTick(uid, component, gameRule, frameTime);
|
||||
|
||||
if (component.NukeAnnouncementAt is { } nukeAnnouncement && nukeAnnouncement <= Timing.CurTime)
|
||||
{
|
||||
var time = component.NukeTimeAt.HasValue ? component.NukeTimeAt.Value - Timing.CurTime : component.NukeTimeDelay;
|
||||
_chat.DispatchGlobalAnnouncement(Loc.GetString("uprising-announcement-nuke-announcement", ("time", (int)Math.Round(time.TotalMinutes))), colorOverride: Color.Gold);
|
||||
component.NukeAnnouncementAt = null;
|
||||
}
|
||||
|
||||
if (component.FirstWarningAt is { } firstWarning && firstWarning <= Timing.CurTime)
|
||||
{
|
||||
var time = component.NukeTimeAt.HasValue ? component.NukeTimeAt.Value - Timing.CurTime : component.FirstWarning;
|
||||
_chat.DispatchGlobalAnnouncement(Loc.GetString("uprising-announcement-first-warning", ("time", (int)Math.Round(time.TotalMinutes))), colorOverride: Color.Gold);
|
||||
component.FirstWarningAt = null;
|
||||
}
|
||||
|
||||
if (component.ImpendingWarningAt is { } impendingWarning && impendingWarning <= Timing.CurTime)
|
||||
{
|
||||
var time = component.NukeTimeAt.HasValue ? component.NukeTimeAt.Value - Timing.CurTime : component.ImpendingWarning;
|
||||
_chat.DispatchGlobalAnnouncement(Loc.GetString("uprising-announcement-impending-warning", ("time", (int)Math.Round(time.TotalMinutes))), colorOverride: Color.Gold);
|
||||
component.ImpendingWarningAt = null;
|
||||
}
|
||||
|
||||
if (component.FinalWarningAt is { } finalWarning && finalWarning <= Timing.CurTime)
|
||||
{
|
||||
var time = component.NukeTimeAt.HasValue ? component.NukeTimeAt.Value - Timing.CurTime : component.FinalWarning;
|
||||
_chat.DispatchGlobalAnnouncement(Loc.GetString("uprising-announcement-final-warning", ("time", (int)Math.Round(time.TotalMinutes))), colorOverride: Color.Gold);
|
||||
component.FinalWarningAt = null;
|
||||
}
|
||||
|
||||
if (component.NukeTimeAt is { } nukeTime && nukeTime <= Timing.CurTime)
|
||||
{
|
||||
component.NukeTimeAt = null;
|
||||
var query = EntityQueryEnumerator<NukeComponent>();
|
||||
while (query.MoveNext(out var bombUid, out var bomb))
|
||||
{
|
||||
_nuke.SetRemainingTime(bombUid, component.NukeDuration, bomb);
|
||||
_itemSlots.SetLock(bombUid, bomb.DiskSlot, false);
|
||||
_itemSlots.TryEject(bombUid, bomb.DiskSlot, null, out _, true);
|
||||
_itemSlots.SetLock(bombUid, bomb.DiskSlot, true);
|
||||
_nuke.ArmBomb(bombUid, bomb, "uprising-announcement-nuke-armed");
|
||||
}
|
||||
}
|
||||
|
||||
if (component.SideWinsAt is var (winningSide, winningTime) && winningTime <= Timing.CurTime)
|
||||
{
|
||||
component.SideWinsAt = null;
|
||||
var query = EntityQueryEnumerator<NukeComponent>();
|
||||
while (query.MoveNext(out var bombUid, out var bomb))
|
||||
{
|
||||
_nuke.DisarmBomb(bombUid, bomb);
|
||||
}
|
||||
|
||||
component.SideWon = winningSide;
|
||||
_chat.DispatchGlobalAnnouncement(
|
||||
Loc.GetString($"uprising-announcement-victory-announcement-{winningSide}"),
|
||||
Loc.GetString($"uprising-announcement-victory-announcement-{winningSide}.sender"),
|
||||
colorOverride: Color.FromXaml(Loc.GetString($"uprising-announcement-victory-announcement-{winningSide}.color")));
|
||||
|
||||
GameTicker.EndRound();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void AppendRoundEndText(EntityUid uid,
|
||||
UprisingRuleComponent component,
|
||||
GameRuleComponent gameRule,
|
||||
ref RoundEndTextAppendEvent args)
|
||||
{
|
||||
if (component.SideWinsAt is var (partialSide, _))
|
||||
{
|
||||
args.AddLine(Loc.GetString($"uprising-outcome-{partialSide}-partial"));
|
||||
}
|
||||
else if (component.SideWon is { } winningSide)
|
||||
{
|
||||
args.AddLine(Loc.GetString($"uprising-outcome-{winningSide}-full"));
|
||||
}
|
||||
else
|
||||
{
|
||||
args.AddLine(Loc.GetString("uprising-outcome-none"));
|
||||
}
|
||||
|
||||
args.AddLine(Loc.GetString("uprising-leads"));
|
||||
|
||||
var antags = _antag.GetAntagIdentifiers(uid);
|
||||
var leads = new HashSet<EntityUid>();
|
||||
|
||||
foreach (var (mind, sessionData, name) in antags)
|
||||
{
|
||||
leads.Add(mind);
|
||||
|
||||
if (_role.MindHasRole<UprisingRoleComponent>(mind, out var it))
|
||||
args.AddLine(Loc.GetString($"uprising-leads-user.{it.Value.Comp2.Side}", ("name", name), ("user", sessionData.UserName)));
|
||||
else
|
||||
args.AddLine(Loc.GetString("uprising-leads-user.Unknown", ("name", name), ("user", sessionData.UserName)));
|
||||
}
|
||||
args.AddLine(string.Empty);
|
||||
|
||||
var lines = new Dictionary<UprisingSide, List<string>>();
|
||||
foreach (var value in Enum.GetValues<UprisingSide>())
|
||||
{
|
||||
lines[value] = new();
|
||||
}
|
||||
|
||||
var minds = EntityQueryEnumerator<MindComponent>();
|
||||
while (minds.MoveNext(out var mindUid, out var mindComponent))
|
||||
{
|
||||
if (leads.Contains(mindUid))
|
||||
continue;
|
||||
|
||||
if (!_role.MindHasRole<UprisingRoleComponent>((mindUid, mindComponent), out var role) || mindComponent.OriginalOwnerUserId is not { } owner)
|
||||
continue;
|
||||
|
||||
if (!_player.TryGetPlayerData(owner, out var data))
|
||||
continue;
|
||||
|
||||
lines[role.Value.Comp2.Side].Add(Loc.GetString($"uprising-members-user", ("name", mindComponent.CharacterName ?? string.Empty), ("user", data.UserName)));
|
||||
}
|
||||
|
||||
foreach (var value in Enum.GetValues<UprisingSide>())
|
||||
{
|
||||
args.AddLine(Loc.GetString($"uprising-members.{value}"));
|
||||
foreach (var line in lines[value])
|
||||
{
|
||||
args.AddLine(line);
|
||||
}
|
||||
args.AddLine(string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGetLoyalistBriefing(Entity<LoyalistRoleComponent> ent, ref GetBriefingEvent args)
|
||||
{
|
||||
args.Append(Loc.GetString("antag-Loyalist.briefing"));
|
||||
}
|
||||
|
||||
private void OnGetInsurgentBriefing(Entity<InsurgentRoleComponent> ent, ref GetBriefingEvent args)
|
||||
{
|
||||
args.Append(Loc.GetString("antag-Insurgent.briefing"));
|
||||
}
|
||||
|
||||
private Entity<UprisingRuleComponent, GameRuleComponent>? GetRule()
|
||||
{
|
||||
var enumerator = QueryActiveRules();
|
||||
while (enumerator.MoveNext(out var uid, out _, out var uprising, out var gamerule))
|
||||
{
|
||||
return (uid, uprising, gamerule);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void StartWinning(UprisingSide side, EntityUid console)
|
||||
{
|
||||
if (GetRule() is not { } rule)
|
||||
return;
|
||||
|
||||
var location = _navMap.GetNearestBeaconString(console);
|
||||
var announcement = Loc.GetString($"uprising-announcement-start-victory-announcement-{side}",
|
||||
("time", (int) Math.Round(rule.Comp1.SideTimes[side].TotalSeconds)),
|
||||
("location", FormattedMessage.RemoveMarkupOrThrow(location)));
|
||||
|
||||
_chat.DispatchGlobalAnnouncement(
|
||||
announcement,
|
||||
Loc.GetString($"uprising-announcement-start-victory-announcement-{side}.sender"),
|
||||
colorOverride: Color.FromXaml(Loc.GetString($"uprising-announcement-start-victory-announcement-{side}.color")));
|
||||
|
||||
rule.Comp1.SideWinsAt = (side, Timing.CurTime + rule.Comp1.SideTimes[side]);
|
||||
}
|
||||
|
||||
private void StopWinning()
|
||||
{
|
||||
if (GetRule() is not { } rule || rule.Comp1.SideWinsAt is not var (side, time))
|
||||
return;
|
||||
|
||||
rule.Comp1.SideTimes[side] = Timing.CurTime - time;
|
||||
|
||||
_chat.DispatchGlobalAnnouncement(
|
||||
Loc.GetString($"uprising-announcement-interrupted-victory-announcement-{side}"),
|
||||
Loc.GetString($"uprising-announcement-interrupted-victory-announcement-{side}.sender"),
|
||||
colorOverride: Color.FromXaml(Loc.GetString($"uprising-announcement-interrupted-victory-announcement-{side}.color")));
|
||||
|
||||
rule.Comp1.SideWinsAt = null;
|
||||
}
|
||||
|
||||
private void OnGetConsoleVerbs(Entity<UprisingConsoleComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (GetRule() is not { } rule)
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
if (rule.Comp1.SideWinsAt is var (disarmSide, _))
|
||||
{
|
||||
args.Verbs.Add(new ()
|
||||
{
|
||||
Act = () => StartDisarming(ent, user),
|
||||
Text = Loc.GetString($"uprising-disarm-verb.{disarmSide}"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckCanArm(args.User, out var armSide))
|
||||
return;
|
||||
|
||||
args.Verbs.Add(new()
|
||||
{
|
||||
Act = () => StartArming(ent, user),
|
||||
Text = Loc.GetString($"uprising-arm-verb.{armSide}"),
|
||||
});
|
||||
}
|
||||
|
||||
private bool CheckCanArm(EntityUid user, [NotNullWhen(true)] out UprisingSide? side)
|
||||
{
|
||||
side = null;
|
||||
if (_mind.GetMind(user) is not { } mind || !TryComp<MindComponent>(mind, out var mindComp))
|
||||
return false;
|
||||
|
||||
if (!_role.MindHasRole<UprisingRoleComponent>(mind, out var uprisingRole))
|
||||
return false;
|
||||
|
||||
foreach (var objective in mindComp.Objectives)
|
||||
{
|
||||
if (!HasComp<UprisingArmRequiredObjectiveComponent>(objective))
|
||||
continue;
|
||||
|
||||
if (_objectives.GetProgress(objective, (mind, mindComp)) is not >= 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
side = uprisingRole.Value.Comp2.Side;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void StartDisarming(Entity<UprisingConsoleComponent> ent, EntityUid user)
|
||||
{
|
||||
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager,
|
||||
user,
|
||||
ent.Comp.Delay,
|
||||
new UprisingDisarmDoAfter(),
|
||||
ent.Owner));
|
||||
}
|
||||
|
||||
private void StartArming(Entity<UprisingConsoleComponent> ent, EntityUid user)
|
||||
{
|
||||
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager,
|
||||
user,
|
||||
ent.Comp.Delay,
|
||||
new UprisingArmDoAfter(),
|
||||
ent.Owner));
|
||||
}
|
||||
|
||||
private void OnArm(Entity<UprisingConsoleComponent> ent, ref UprisingArmDoAfter args)
|
||||
{
|
||||
if (args.Handled || args.Cancelled || !CheckCanArm(args.User, out var side))
|
||||
return;
|
||||
|
||||
StartWinning(side.Value, ent);
|
||||
}
|
||||
|
||||
private void OnDisarm(Entity<UprisingConsoleComponent> ent, ref UprisingDisarmDoAfter args)
|
||||
{
|
||||
if (args.Handled || args.Cancelled)
|
||||
return;
|
||||
|
||||
StopWinning();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using Content.Shared.Actions;
|
||||
using Content.Shared.Roles.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Uprising;
|
||||
|
||||
public sealed partial class ConversionAcceptActionEvent : InstantActionEvent
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public EntProtoId MindRole;
|
||||
|
||||
[DataField(required: true)]
|
||||
public EntProtoId<MindRoleComponent> RemoveMindRole;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Shared.Uprising;
|
||||
|
||||
public sealed class ConversionAcceptActionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly SharedRoleSystem _role = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<MindContainerComponent, ConversionAcceptActionEvent>(OnAcceptConversion);
|
||||
}
|
||||
|
||||
private void OnAcceptConversion(Entity<MindContainerComponent> ent, ref ConversionAcceptActionEvent args)
|
||||
{
|
||||
if (_mind.GetMind(ent) is not { } mind)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
if (_net.IsServer)
|
||||
{
|
||||
_role.MindAddRole(mind, args.MindRole);
|
||||
_role.MindRemoveRole(mind, args.RemoveMindRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using Content.Shared.Actions;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Uprising;
|
||||
|
||||
public sealed partial class ConversionOfferActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
[DataField(readOnly: true)]
|
||||
public List<Type> IncompatibleMindRoleTypes;
|
||||
|
||||
[DataField]
|
||||
public EntProtoId AcceptAction;
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using Content.Shared.Actions;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Roles.Components;
|
||||
|
||||
namespace Content.Shared.Uprising;
|
||||
|
||||
public sealed class ConversionOfferActionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly SharedRoleSystem _role = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<MindRoleComponent, ConversionOfferActionEvent>(OnOffer);
|
||||
}
|
||||
|
||||
private void OnOffer(Entity<MindRoleComponent> ent, ref ConversionOfferActionEvent args)
|
||||
{
|
||||
if (_mind.GetMind(args.Target) is not { } mind)
|
||||
return;
|
||||
|
||||
foreach (var incompatible in args.IncompatibleMindRoleTypes)
|
||||
{
|
||||
if (_role.MindHasRole(mind, incompatible, out _))
|
||||
return;
|
||||
}
|
||||
|
||||
_actions.AddAction(args.Target, args.AcceptAction);
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Actions;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DeleteOnPerformedActionComponent : Component;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using Content.Shared.Actions.Events;
|
||||
|
||||
namespace Content.Shared._DV.Actions;
|
||||
|
||||
public sealed class DeleteOnPerformedActionSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DeleteOnPerformedActionComponent, ActionPerformedEvent>(OnActionPerformed);
|
||||
}
|
||||
|
||||
private void OnActionPerformed(Entity<DeleteOnPerformedActionComponent> ent, ref ActionPerformedEvent args)
|
||||
{
|
||||
PredictedQueueDel(ent);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using Content.Shared.Actions;
|
||||
using Content.Shared.Mind;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Shared._DV.Roles;
|
||||
|
||||
public sealed class ActionGrantRoleSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ActionGrantRoleComponent, EntGotInsertedIntoContainerMessage>(OnGotInserted);
|
||||
SubscribeLocalEvent<ActionGrantRoleComponent, EntGotRemovedFromContainerMessage>(OnGotRemoved);
|
||||
}
|
||||
|
||||
private void OnGotInserted(Entity<ActionGrantRoleComponent> ent, ref EntGotInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (_net.IsClient || !TryComp<MindComponent>(args.Container.Owner, out var mind) || mind.CurrentEntity is not { } mindContainer)
|
||||
return;
|
||||
|
||||
_actions.GrantContainedActions(mindContainer, ent.Owner);
|
||||
}
|
||||
|
||||
private void OnGotRemoved(Entity<ActionGrantRoleComponent> ent, ref EntGotRemovedFromContainerMessage args)
|
||||
{
|
||||
if (_net.IsClient || !TryComp<MindComponent>(args.Container.Owner, out var mind) || mind.CurrentEntity is not { } mindContainer)
|
||||
return;
|
||||
|
||||
_actions.RemoveProvidedActions(mindContainer, ent.Owner);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Roles;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ActionGrantRoleComponent : Component;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
using Content.Shared.Roles.Components;
|
||||
|
||||
namespace Content.Shared._DV.Roles;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class InsurgentRoleComponent : BaseMindRoleComponent;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
using Content.Shared.Roles.Components;
|
||||
|
||||
namespace Content.Shared._DV.Roles;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class LoyalistRoleComponent : BaseMindRoleComponent;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Roles.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._DV.Roles;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class ObjectiveRoleComponent : BaseMindRoleComponent
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public List<EntProtoId<ObjectiveComponent>> Objectives;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
using Content.Shared.Roles.Components;
|
||||
|
||||
namespace Content.Shared._DV.Roles;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class UprisingInconvertibleRoleComponent : BaseMindRoleComponent;
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using Content.Shared.Roles.Components;
|
||||
|
||||
namespace Content.Shared._DV.Roles;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class UprisingRoleComponent : BaseMindRoleComponent
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public UprisingSide Side;
|
||||
}
|
||||
|
||||
public enum UprisingSide : byte
|
||||
{
|
||||
Insurgent,
|
||||
Loyalist,
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
using Content.Shared.Mind;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Shared._DV.Roles;
|
||||
|
||||
public sealed class ObjectiveRoleSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ObjectiveRoleComponent, EntGotInsertedIntoContainerMessage>(OnInsertedIntoMind);
|
||||
SubscribeLocalEvent<ObjectiveRoleComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
private void OnInsertedIntoMind(Entity<ObjectiveRoleComponent> ent, ref EntGotInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
if (!TryComp<MindComponent>(args.Container.Owner, out var mind))
|
||||
return;
|
||||
|
||||
foreach (var objective in ent.Comp.Objectives)
|
||||
{
|
||||
_mind.TryAddObjective(args.Container.Owner, mind, objective);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnShutdown(Entity<ObjectiveRoleComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
if (!_container.TryGetContainingContainer(ent.Owner, out var container) ||
|
||||
!TryComp<MindComponent>(container.Owner, out var mind))
|
||||
return;
|
||||
|
||||
var indices = new List<int>();
|
||||
|
||||
for (var i = mind.Objectives.Count; i >= 0; i--)
|
||||
{
|
||||
var objective = mind.Objectives[i];
|
||||
if (MetaData(objective).EntityPrototype?.ID is { } id && ent.Comp.Objectives.Contains(id))
|
||||
{
|
||||
indices.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var index in indices)
|
||||
{
|
||||
_mind.TryRemoveObjective(container.Owner, mind, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
|
||||
|
||||
namespace Content.Shared._DV.Uprising;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CommandStatusObjectiveComponent : Component
|
||||
{
|
||||
[DataField(required: true, customTypeSerializer: typeof(CustomHashSetSerializer<string, ComponentNameSerializer>))]
|
||||
public HashSet<string> ConvertedRoles;
|
||||
|
||||
[DataField]
|
||||
public bool ShouldUnconvertedBeIncapacitated;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using Content.Shared.NPC.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
|
||||
|
||||
namespace Content.Shared._DV.Uprising;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CrewConversionObjectiveComponent : Component
|
||||
{
|
||||
[DataField(required: true, customTypeSerializer: typeof(CustomHashSetSerializer<string, ComponentNameSerializer>))]
|
||||
public HashSet<string> ConvertedRoles;
|
||||
|
||||
[DataField(required: true)]
|
||||
public HashSet<ProtoId<NpcFactionPrototype>> ConversionSourceFactions;
|
||||
|
||||
[DataField(required: true)]
|
||||
public float TargetFraction;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.NPC.Components;
|
||||
using Content.Shared.NPC.Systems;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Roles;
|
||||
|
||||
namespace Content.Shared._DV.Uprising;
|
||||
|
||||
public sealed class CrewConversionObjectiveSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
|
||||
[Dependency] private readonly SharedRoleSystem _role = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CrewConversionObjectiveComponent, ObjectiveGetProgressEvent>(OnGetProgress);
|
||||
}
|
||||
|
||||
private void OnGetProgress(Entity<CrewConversionObjectiveComponent> ent, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
var total = 0;
|
||||
var counted = 0;
|
||||
|
||||
var query = AllEntityQuery<MindContainerComponent, NpcFactionMemberComponent>();
|
||||
while (query.MoveNext(out var uid, out var mind, out var faction))
|
||||
{
|
||||
if (mind.Mind is not { } mindUid)
|
||||
continue;
|
||||
|
||||
if (!_npcFaction.IsMemberOfAny((uid, faction), ent.Comp.ConversionSourceFactions))
|
||||
continue;
|
||||
|
||||
total++;
|
||||
|
||||
foreach (var role in ent.Comp.ConvertedRoles)
|
||||
{
|
||||
if (!EntityManager.ComponentFactory.TryGetRegistration(role, out var roleReg))
|
||||
{
|
||||
Log.Error($"Role component not found for CrewConversionObjective: {role}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_role.MindHasRole(mindUid, roleReg.Type, out _))
|
||||
continue;
|
||||
|
||||
counted++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (total == 0)
|
||||
return;
|
||||
|
||||
args.Progress = ((float)counted / (float)total) / ent.Comp.TargetFraction;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
namespace Content.Shared._DV.Uprising;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class UprisingArmRequiredObjectiveComponent : Component;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._DV.Uprising;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class UprisingDisarmDoAfter : SimpleDoAfterEvent;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class UprisingArmDoAfter : SimpleDoAfterEvent;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using Content.Shared._DV.Roles;
|
||||
|
||||
namespace Content.Shared._DV.Uprising;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class UprisingVictoryObjectiveComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public UprisingSide Side;
|
||||
}
|
||||
|
|
@ -7,3 +7,7 @@ role-subtype-armsdealer = Arms Dealer
|
|||
role-subtype-asakim = Asakim
|
||||
role-subtype-ntagent = NTAgent
|
||||
role-subtype-hitman = Hitman
|
||||
role-subtype-head-loyalist = Head Loyalist
|
||||
role-subtype-loyalist = Loyalist
|
||||
role-subtype-head-insurgent = Head Insurgent
|
||||
role-subtype-insurgent = Insurgent
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
uprising-announcement-nuke-announcement = Automated risk management systems have flagged your station as posing a threat to NanoTrasen. Contracts will be terminated in {$time} minutes unless the situation resolves.
|
||||
uprising-announcement-first-warning = Automated risk management systems still continue to flag your station as posing a threat to NanoTrasen. Please intervene within {$time} minutes.
|
||||
uprising-announcement-impending-warning = Automated risk management systems have initiated a task in the contract termination subsystem for your station. The decision will be rendered final in {$time} minutes.
|
||||
uprising-announcement-final-warning = Contract termination will begin in {$time} minutes.
|
||||
uprising-announcement-nuke-armed = Attention! The threat to NanoTrasen will be eliminated using the station's self-destruct mechanism {$location}. {$time} seconds until detonation. Glory to NanoTrasen!
|
||||
|
||||
uprising-announcement-start-victory-announcement-Insurgent =
|
||||
Viva la revolución! Station hijacking measures have been initiated {$location} and will complete in {$time} seconds. Do not resist, your liberation will come.
|
||||
|
||||
.sender = Insurgent Communications
|
||||
.color = DarkSalmon
|
||||
|
||||
uprising-announcement-start-victory-announcement-Loyalist =
|
||||
The station is loyal to NanoTrasen. Transmission to Central Command has been initiated {$location} and will complete in {$time} seconds. Glory to NanoTrasen!
|
||||
|
||||
.sender = Loyalist Communications
|
||||
.color = CornflowerBlue
|
||||
|
||||
uprising-announcement-victory-announcement-Insurgent =
|
||||
Viva viva la revolución! The station belongs to the masses now.
|
||||
|
||||
.sender = Insurgent Communications
|
||||
.color = DarkSalmon
|
||||
|
||||
uprising-announcement-victory-announcement-Loyalist =
|
||||
Automated risk management systems have no longer deemed your station a threat to NanoTrasen. Contracts will be retained.
|
||||
|
||||
.sender = Central Command
|
||||
.color = Gold
|
||||
|
||||
uprising-announcement-interrupted-victory-announcement-Insurgent =
|
||||
Station hijacking measures have been interrupted.
|
||||
|
||||
.sender = Insurgent Communications
|
||||
.color = DarkSalmon
|
||||
|
||||
uprising-announcement-interrupted-victory-announcement-Loyalist =
|
||||
Transmission to Central Command has been interrupted.
|
||||
|
||||
.sender = Loyalist Communications
|
||||
.color = CornflowerBlue
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
antag-HeadLoyalist =
|
||||
.name = Head Loyalist
|
||||
.objective = Protect the interests of NanoTrasen against the insurgents.
|
||||
.greeting =
|
||||
You are a Head Loyalist.
|
||||
Protect all of Command, get the crew on your side and declare the station's loyalty.
|
||||
|
||||
antag-Loyalist =
|
||||
.issuer = Loyalty
|
||||
.briefing = Protect all of Command, get the crew on your side and declare the station's loyalty.
|
||||
|
||||
antag-HeadInsurgent =
|
||||
.name = Head Insurgent
|
||||
.objective = Rebel against NanoTrasen. Down with the bourgeoisie!
|
||||
.greeting =
|
||||
You are a Head Insurgent.
|
||||
Assassinate, capture or convert all of Command and take over the station.
|
||||
Viva la revolución!
|
||||
|
||||
antag-Insurgent =
|
||||
.issuer = Insurgency
|
||||
.briefing = Assassinate, capture or convert all of Command and take over the station.
|
||||
|
|
@ -0,0 +1 @@
|
|||
uprising-conversion-join-side = Press again to switch sides.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
preset-Uprising =
|
||||
.title = Uprising
|
||||
.description = The crew is at odds with each other.
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
uprising-outcome-none = The station was scuttled by NanoTrasen, and neither side could stop it in time.
|
||||
uprising-outcome-Insurgent-full = The station was taken over by the insurgents. Viva la revolución!
|
||||
uprising-outcome-Insurgent-partial = The insurgents were in the middle of taking over the station, but it was too late.
|
||||
uprising-outcome-Loyalist-full = The station managed to prove its loyalty to NanoTrasen. Glory to NanoTrasen!
|
||||
uprising-outcome-Loyalist-partial = The loyalists were in the middle of proving the station's loyalty to NanoTrasen, but it was too late.
|
||||
uprising-leads = Our leads for this round were:
|
||||
uprising-leads-user =
|
||||
.Insurgent = - [color=white]{$name}[/color], a [color=DarkSalmon]Head Insurgent[/color] played by {$user}
|
||||
.Loyalist = - [color=white]{$name}[/color], a [color=CornflowerBlue]Head Loyalist[/color] played by {$user}
|
||||
.Unknown = - [color=white]{$name}[/color], played by {$user}
|
||||
|
||||
uprising-members =
|
||||
.Insurgent = Our [color=DarkSalmon]Insurgent[/color]s were:
|
||||
.Loyalist = Our [color=CornflowerBlue]Loyalist[/color]s were:
|
||||
|
||||
uprising-members-user = - [color=white]{$name}[/color], played by {$user}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
admin-verb-make-HeadInsurgent =
|
||||
.text = Make Head Insurgent
|
||||
.message = Makes the target into a Head Insurgent
|
||||
|
||||
admin-verb-make-HeadLoyalist =
|
||||
.text = Make Head Loyalist
|
||||
.message = Makes the target into a Head Loyalist
|
||||
|
||||
uprising-disarm-verb =
|
||||
.Insurgent = Stop Hijacking
|
||||
.Loyalist = Stop Transmission
|
||||
|
||||
uprising-arm-verb =
|
||||
.Insurgent = Start Hijacking
|
||||
.Loyalist = Start Transmission
|
||||
|
|
@ -720,6 +720,7 @@
|
|||
- type: GuideHelp # DeltaV guide
|
||||
guides:
|
||||
- AlertProcedure
|
||||
- type: UprisingConsole # DeltaV - uprising
|
||||
|
||||
- type: entity
|
||||
parent: ComputerComms
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
- type: entity
|
||||
abstract: true
|
||||
parent: BaseAction
|
||||
id: ActionUprisingOfferConversion
|
||||
name: Offer Conversion
|
||||
description: Offer to let someone join your side.
|
||||
components:
|
||||
- type: Action
|
||||
useDelay: 30
|
||||
itemIconStyle: NoItem
|
||||
icon:
|
||||
sprite: _DV/Misc/uprising.rsi
|
||||
state: conversion
|
||||
- type: TargetAction
|
||||
- type: EntityTargetAction
|
||||
whitelist:
|
||||
components:
|
||||
- HumanoidAppearance
|
||||
|
||||
- type: entity
|
||||
parent: ActionUprisingOfferConversion
|
||||
id: ActionLoyalistOfferConversion
|
||||
components:
|
||||
- type: EntityTargetAction
|
||||
event: !type:ConversionOfferActionEvent
|
||||
incompatibleMindRoleTypes:
|
||||
- Content.Shared._DV.Roles.LoyalistRoleComponent
|
||||
- Content.Shared._DV.Roles.UprisingInconvertibleRoleComponent
|
||||
acceptAction: ActionLoyalistAcceptConversion
|
||||
|
||||
- type: entity
|
||||
parent: ActionUprisingOfferConversion
|
||||
id: ActionInsurgentOfferConversion
|
||||
components:
|
||||
- type: EntityTargetAction
|
||||
event: !type:ConversionOfferActionEvent
|
||||
incompatibleMindRoleTypes:
|
||||
- Content.Shared._DV.Roles.InsurgentRoleComponent
|
||||
- Content.Shared._DV.Roles.UprisingInconvertibleRoleComponent
|
||||
acceptAction: ActionInsurgentAcceptConversion
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: BaseAction
|
||||
id: ActionUprisingAcceptConversion
|
||||
name: Join Side
|
||||
description: Join the side of whoever's trying to recruit you. You can only do this for 30 seconds after being offered.
|
||||
components:
|
||||
- type: Action
|
||||
itemIconStyle: NoItem
|
||||
icon:
|
||||
sprite: _DV/Misc/uprising.rsi
|
||||
state: conversion_question
|
||||
- type: InstantAction
|
||||
- type: ConfirmableAction
|
||||
popup: uprising-conversion-join-side
|
||||
- type: ESTimedDespawn
|
||||
lifetime: 30
|
||||
- type: DeleteOnPerformedAction
|
||||
|
||||
- type: entity
|
||||
parent: ActionUprisingAcceptConversion
|
||||
id: ActionInsurgentAcceptConversion
|
||||
components:
|
||||
- type: InstantAction
|
||||
event: !type:ConversionAcceptActionEvent
|
||||
mindRole: MindRoleInsurgent
|
||||
removeMindRole: MindRoleLoyalist
|
||||
|
||||
- type: entity
|
||||
parent: ActionUprisingAcceptConversion
|
||||
id: ActionLoyalistAcceptConversion
|
||||
components:
|
||||
- type: InstantAction
|
||||
event: !type:ConversionAcceptActionEvent
|
||||
mindRole: MindRoleLoyalist
|
||||
removeMindRole: MindRoleInsurgent
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
- type: entity
|
||||
parent: BaseGameRule
|
||||
id: UprisingRule
|
||||
components:
|
||||
- type: GameRule
|
||||
minPlayers: 10
|
||||
- type: UprisingRule
|
||||
- type: AntagSelection
|
||||
selectionTime: IntraPlayerSpawn
|
||||
definitions:
|
||||
- prefRoles: [ HeadLoyalist ]
|
||||
max: 2
|
||||
playerRatio: 30
|
||||
mindRoles:
|
||||
- MindRoleHeadLoyalist
|
||||
briefing:
|
||||
text: antag-HeadLoyalist.greeting
|
||||
color: CornflowerBlue
|
||||
- prefRoles: [ HeadInsurgent ]
|
||||
max: 2
|
||||
playerRatio: 30
|
||||
mindRoles:
|
||||
- MindRoleHeadInsurgent
|
||||
briefing:
|
||||
text: antag-HeadInsurgent.greeting
|
||||
color: DarkSalmon
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
- type: entity
|
||||
abstract: true
|
||||
parent: BaseObjective
|
||||
id: BaseLoyalistObjective
|
||||
components:
|
||||
- type: Objective
|
||||
issuer: antag-Loyalist.issuer
|
||||
difficulty: 0
|
||||
- type: RoleRequirement
|
||||
roles: [ LoyalistRole ]
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: BaseObjective
|
||||
id: BaseInsurgentObjective
|
||||
components:
|
||||
- type: Objective
|
||||
issuer: antag-Insurgent.issuer
|
||||
difficulty: 0
|
||||
- type: RoleRequirement
|
||||
roles: [ InsurgentRole ]
|
||||
|
||||
- type: entity
|
||||
parent: BaseLoyalistObjective
|
||||
id: LoyalistObjectiveCrewMajority
|
||||
name: Rally Crew
|
||||
description: Rally the crew to NanoTrasen's side.
|
||||
components:
|
||||
- type: CrewConversionObjective
|
||||
convertedRoles: [ LoyalistRole ]
|
||||
conversionSourceFactions: [ NanoTrasen ]
|
||||
targetFraction: 0.5
|
||||
- type: Objective
|
||||
icon:
|
||||
sprite: /Textures/_DV/Misc/uprising.rsi
|
||||
state: loyalist_conversion
|
||||
|
||||
- type: entity
|
||||
parent: BaseLoyalistObjective
|
||||
id: LoyalistObjectiveProtectCommand
|
||||
name: Protect Command
|
||||
description: Keep NanoTrasen's rightfully-appointed Command in their place, and get them on your side.
|
||||
components:
|
||||
- type: Objective
|
||||
icon:
|
||||
sprite: /Textures/_DV/Misc/uprising.rsi
|
||||
state: protect
|
||||
- type: CommandStatusObjective
|
||||
convertedRoles: [ LoyalistRole ]
|
||||
shouldUnconvertedBeIncapacitated: false
|
||||
|
||||
- type: entity
|
||||
parent: BaseLoyalistObjective
|
||||
id: LoyalistObjectiveDeclareLoyalty
|
||||
name: Declare Loyalty
|
||||
description: After rallying the majority of the crew, get to a communications computer and affirm the station's loyalty to NanoTrasen.
|
||||
components:
|
||||
- type: Objective
|
||||
icon:
|
||||
sprite: /Textures/_DV/Misc/uprising.rsi
|
||||
state: loyalty
|
||||
- type: UprisingVictoryObjective
|
||||
side: Loyalist
|
||||
|
||||
- type: entity
|
||||
parent: BaseInsurgentObjective
|
||||
id: InsurgentObjectiveCrewMajority
|
||||
name: Rally Crew
|
||||
description: Rally the crew to your side.
|
||||
components:
|
||||
- type: CrewConversionObjective
|
||||
convertedRoles: [ InsurgentRole ]
|
||||
conversionSourceFactions: [ NanoTrasen ]
|
||||
targetFraction: 0.5
|
||||
- type: Objective
|
||||
icon:
|
||||
sprite: /Textures/_DV/Misc/uprising.rsi
|
||||
state: insurgent_conversion
|
||||
|
||||
- type: entity
|
||||
parent: BaseInsurgentObjective
|
||||
id: InsurgentObjectiveIncapacitateCommand
|
||||
name: Incapacitate Command
|
||||
description: Assassinate, handcuff, or convert all of Command.
|
||||
components:
|
||||
- type: Objective
|
||||
icon:
|
||||
sprite: /Textures/_DV/Misc/uprising.rsi
|
||||
state: overthrow
|
||||
- type: CommandStatusObjective
|
||||
convertedRoles: [ InsurgentRole ]
|
||||
shouldUnconvertedBeIncapacitated: true
|
||||
|
||||
- type: entity
|
||||
parent: BaseInsurgentObjective
|
||||
id: InsurgentObjectiveTakeOver
|
||||
name: Take Over
|
||||
description: After getting all of Command out of the way, get to a communications computer and declare the station's liberation.
|
||||
components:
|
||||
- type: Objective
|
||||
icon:
|
||||
sprite: /Textures/_DV/Misc/uprising.rsi
|
||||
state: take_over
|
||||
- type: UprisingVictoryObjective
|
||||
side: Insurgent
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
- type: antag
|
||||
id: HeadLoyalist
|
||||
name: antag-HeadLoyalist.name
|
||||
antagonist: true
|
||||
setPreference: true
|
||||
objective: antag-HeadLoyalist.objective
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 24h
|
||||
|
||||
- type: antag
|
||||
id: HeadInsurgent
|
||||
name: antag-HeadInsurgent.name
|
||||
antagonist: true
|
||||
setPreference: true
|
||||
objective: antag-HeadInsurgent.objective
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 24h
|
||||
|
|
@ -141,3 +141,71 @@
|
|||
- type: HitmanRole
|
||||
- type: RoleBriefing
|
||||
briefing: hitman-briefing
|
||||
|
||||
- type: entity
|
||||
parent: BaseMindRoleAntag
|
||||
id: MindRoleLoyalist
|
||||
name: Loyalist Role
|
||||
components:
|
||||
- type: MindRole
|
||||
antagPrototype: HeadLoyalist
|
||||
exclusiveAntag: true
|
||||
roleType: TeamAntagonist
|
||||
subtype: role-subtype-loyalist
|
||||
- type: LoyalistRole
|
||||
- type: RoleBriefing
|
||||
briefing: antag-Loyalist.briefing
|
||||
- type: ObjectiveRole
|
||||
objectives:
|
||||
- LoyalistObjectiveCrewMajority
|
||||
- LoyalistObjectiveProtectCommand
|
||||
- LoyalistObjectiveDeclareLoyalty
|
||||
- type: ActionGrant
|
||||
actions:
|
||||
- ActionLoyalistOfferConversion
|
||||
- type: ActionGrantRole
|
||||
- type: UprisingRole
|
||||
side: Loyalist
|
||||
|
||||
- type: entity
|
||||
parent: MindRoleLoyalist
|
||||
id: MindRoleHeadLoyalist
|
||||
name: Head Loyalist Role
|
||||
components:
|
||||
- type: MindRole
|
||||
subtype: role-subtype-head-loyalist
|
||||
- type: UprisingInconvertibleRole
|
||||
|
||||
- type: entity
|
||||
parent: BaseMindRoleAntag
|
||||
id: MindRoleInsurgent
|
||||
name: Insurgent Role
|
||||
components:
|
||||
- type: MindRole
|
||||
antagPrototype: HeadInsurgent
|
||||
exclusiveAntag: true
|
||||
roleType: TeamAntagonist
|
||||
subtype: role-subtype-insurgent
|
||||
- type: InsurgentRole
|
||||
- type: RoleBriefing
|
||||
briefing: antag-Insurgent.briefing
|
||||
- type: ObjectiveRole
|
||||
objectives:
|
||||
- InsurgentObjectiveCrewMajority
|
||||
- InsurgentObjectiveIncapacitateCommand
|
||||
- InsurgentObjectiveTakeOver
|
||||
- type: ActionGrant
|
||||
actions:
|
||||
- ActionInsurgentOfferConversion
|
||||
- type: ActionGrantRole
|
||||
- type: UprisingRole
|
||||
side: Insurgent
|
||||
|
||||
- type: entity
|
||||
parent: MindRoleInsurgent
|
||||
id: MindRoleHeadInsurgent
|
||||
name: Head Insurgent Role
|
||||
components:
|
||||
- type: MindRole
|
||||
subtype: role-subtype-head-insurgent
|
||||
- type: UprisingInconvertibleRole
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
- type: gamePreset
|
||||
id: Uprising
|
||||
alias:
|
||||
- uprising
|
||||
name: preset-Uprising.title
|
||||
description: preset-Uprising.description
|
||||
showInVote: false
|
||||
cooldown: 1
|
||||
rules:
|
||||
- UprisingRule
|
||||
- SubGamemodesRule
|
||||
- MeteorSwarmScheduler
|
||||
- SpaceTrafficControlEventScheduler
|
||||
- BasicRoundstartVariation
|
||||
- BasicStationEventScheduler
|
||||
- GlimmerEventScheduler
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
- type: weightedRandom
|
||||
id: SecretDeltaV
|
||||
weights:
|
||||
Survival: 0.30
|
||||
Survival: 0.20
|
||||
Nukeops: 0.15
|
||||
Zombie: 0.10
|
||||
Traitor: 0.35
|
||||
Uprising: 0.10
|
||||
CosmicCult: 0.10 # my cult so cosmic!
|
||||
#Pirates: 0.15 #ahoy me bucko
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 325 B |
|
After Width: | Height: | Size: 265 B |
|
After Width: | Height: | Size: 257 B |
|
After Width: | Height: | Size: 227 B |
|
After Width: | Height: | Size: 239 B |
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC0-1.0",
|
||||
"copyright": "made by sowelipililimute (GitHub)",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "loyalist_conversion"
|
||||
},
|
||||
{
|
||||
"name": "insurgent_conversion"
|
||||
},
|
||||
{
|
||||
"name": "protect"
|
||||
},
|
||||
{
|
||||
"name": "overthrow"
|
||||
},
|
||||
{
|
||||
"name": "take_over"
|
||||
},
|
||||
{
|
||||
"name": "loyalty"
|
||||
},
|
||||
{
|
||||
"name": "conversion"
|
||||
},
|
||||
{
|
||||
"name": "conversion_question"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 317 B |
|
After Width: | Height: | Size: 258 B |
|
After Width: | Height: | Size: 258 B |