Skip to content

Commit

Permalink
fugitives redux (#1413)
Browse files Browse the repository at this point in the history
* add fugitive rule logic

* add fugitive role

* add fugitive event

* remove nyano spawner and make midround antag spawner work real

* fix announcement logic

* fix the funny bug i think

* fix crimes

* fix crime count

* 1 less min crime

* fix sex (real)

* thief bag unhardcode MaxSelectedSets

* :trollface:

* :trollface:

* add fugitive stash

* fix

* add misc stuff and fugitive stash

* m

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
  • Loading branch information
deltanedas authored Jun 30, 2024
1 parent 78cc693 commit 540febc
Show file tree
Hide file tree
Showing 20 changed files with 500 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Content.Client/Thief/ThiefBackpackMenu.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
MinSize="700 700">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<!-- First Informational panel -->
<Label Text="{Loc 'thief-backpack-window-description'}" Margin="5 5"/>
<Label Name="Description" Margin="5 5"/>
<controls:HLine Color="#404040" Thickness="2" Margin="0 5"/>
<Label Name="SelectedSets" Text="{Loc 'thief-backpack-window-selected'}" Margin="5 5"/>

Expand Down
1 change: 1 addition & 0 deletions Content.Client/Thief/ThiefBackpackMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public void UpdateState(ThiefBackpackBoundUserInterfaceState state)
selectedNumber++;
}

Description.Text = Loc.GetString("thief-backpack-window-description", ("maxCount", state.MaxSelectedSets));
SelectedSets.Text = Loc.GetString("thief-backpack-window-selected", ("selectedCount", selectedNumber), ("maxCount", state.MaxSelectedSets));
ApproveButton.Disabled = selectedNumber == state.MaxSelectedSets ? false : true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using Content.Shared.Dataset;
using Content.Server.StationEvents.Events;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.Utility;

namespace Content.Server.StationEvents.Components;

/// <summary>
/// Makes a GALPOL announcement and creates a report some time after an antag spawns.
/// Removed after this is done.
/// </summary>
[RegisterComponent, Access(typeof(FugitiveRule))]
[AutoGenerateComponentPause]
public sealed partial class FugitiveRuleComponent : Component
{
[DataField]
public LocId Announcement = "station-event-fugitive-hunt-announcement";

[DataField]
public LocId Sender = "fugitive-announcement-GALPOL";

[DataField]
public Color Color = Color.Yellow;

/// <summary>
/// Report paper to spawn. Its content is generated from the fugitive.
/// </summary>
[DataField]
public EntProtoId ReportPaper = "PaperFugitiveReport";

/// <summary>
/// How long to wait after the antag spawns before announcing it.
/// </summary>
[DataField]
public TimeSpan AnnounceDelay = TimeSpan.FromMinutes(5);

/// <summary>
/// Station to give the report to.
/// </summary>
[DataField]
public EntityUid? Station;

/// <summary>
/// The report generated for the spawned fugitive.
/// </summary>
[DataField]
public string Report = string.Empty;

/// <summary>
/// When the announcement will be made, if an antag has spawned yet.
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
public TimeSpan? NextAnnounce;

/// <summary>
/// Dataset to pick crimes on the report from.
/// </summary>
[DataField]
public ProtoId<LocalizedDatasetPrototype> CrimesDataset = "FugitiveCrimes";

/// <summary>
/// Max number of unique crimes they can be charged with.
/// Does not affect the counts of each crime.
/// </summary>
[DataField]
public int MinCrimes = 2;

/// <summary>
/// Min number of unique crimes they can be charged with.
/// Does not affect the counts of each crime.
/// </summary>
[DataField]
public int MaxCrimes = 7;

/// <summary>
/// Min counts of each crime that can be rolled.
/// </summary>
[DataField]
public int MinCounts = 1;

/// <summary>
/// Max counts of each crime that can be rolled.
/// </summary>
[DataField]
public int MaxCounts = 4;
}
129 changes: 129 additions & 0 deletions Content.Server/DeltaV/StationEvents/Events/FugitiveRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using Content.Server.Antag;
using Content.Server.Communications;
using Content.Server.GameTicking.Components; // TODO: Shared when upstream merged
using Content.Server.Paper;
using Content.Server.StationEvents.Components;
using Content.Shared.Ghost;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Popups;
using Content.Shared.Random.Helpers;
using Robust.Shared.Physics.Components;
using Robust.Shared.Utility;

namespace Content.Server.StationEvents.Events;

public sealed class FugitiveRule : StationEventSystem<FugitiveRuleComponent>
{
[Dependency] private readonly PaperSystem _paper = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<FugitiveRuleComponent, AfterAntagEntitySelectedEvent>(OnEntitySelected);
}

protected override void ActiveTick(EntityUid uid, FugitiveRuleComponent comp, GameRuleComponent rule, float frameTime)
{
if (comp.NextAnnounce is not {} next || next > Timing.CurTime)
return;

var announcement = Loc.GetString(comp.Announcement);
var sender = Loc.GetString(comp.Sender);
ChatSystem.DispatchGlobalAnnouncement(announcement, sender: sender, colorOverride: comp.Color);

// send the report to every comms console on the station
var query = EntityQueryEnumerator<TransformComponent, CommunicationsConsoleComponent>();
var consoles = new List<TransformComponent>();
while (query.MoveNext(out var console, out var xform, out _))
{
if (StationSystem.GetOwningStation(console, xform) != comp.Station || HasComp<GhostComponent>(console))
continue;

consoles.Add(xform);
}

foreach (var xform in consoles)
{
var report = Spawn(comp.ReportPaper, xform.Coordinates);
_paper.SetContent(report, comp.Report);
}

// prevent any possible funnies
comp.NextAnnounce = null;

RemCompDeferred(uid, comp);
}

private void OnEntitySelected(Entity<FugitiveRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
{
if (ent.Comp.NextAnnounce != null)
{
Log.Error("Fugitive rule spawning multiple fugitives isn't supported, sorry.");
return;
}

var fugi = args.EntityUid;
ent.Comp.Report = GenerateReport(fugi, ent.Comp).ToMarkup();
ent.Comp.Station = StationSystem.GetOwningStation(fugi);
ent.Comp.NextAnnounce = Timing.CurTime + ent.Comp.AnnounceDelay;

_popup.PopupEntity(Loc.GetString("fugitive-spawn"), fugi, fugi);
}

private FormattedMessage GenerateReport(EntityUid uid, FugitiveRuleComponent rule)
{
var report = new FormattedMessage();
report.PushMarkup(Loc.GetString("fugitive-report-title", ("name", uid)));
report.PushNewline();
report.PushMarkup(Loc.GetString("fugitive-report-first-line", ("name", uid)));
report.PushNewline();

if (!TryComp<HumanoidAppearanceComponent>(uid, out var humanoid))
{
report.AddMarkup(Loc.GetString("fugitive-report-inhuman", ("name", uid)));
return report;
}

var species = PrototypeManager.Index(humanoid.Species);

report.PushMarkup(Loc.GetString("fugitive-report-morphotype", ("species", Loc.GetString(species.Name))));
report.PushMarkup(Loc.GetString("fugitive-report-age", ("age", humanoid.Age)));
report.PushMarkup(Loc.GetString("fugitive-report-sex", ("sex", humanoid.Sex.ToString())));

if (TryComp<PhysicsComponent>(uid, out var physics))
report.PushMarkup(Loc.GetString("fugitive-report-weight", ("weight", Math.Round(physics.FixturesMass))));

report.PushNewline();
report.PushMarkup(Loc.GetString("fugitive-report-crimes-header"));

// generate some random crimes to avoid this situation
// "officer what are my charges?"
// "uh i dunno a piece of paper said to arrest you thats it"
AddCharges(report, rule);

report.PushNewline();
report.AddMarkup(Loc.GetString("fugitive-report-last-line"));

return report;
}

private void AddCharges(FormattedMessage report, FugitiveRuleComponent rule)
{
var crimeTypes = PrototypeManager.Index(rule.CrimesDataset);
var crimes = new HashSet<LocId>();
var total = RobustRandom.Next(rule.MinCrimes, rule.MaxCrimes + 1);
while (crimes.Count < total)
{
crimes.Add(RobustRandom.Pick(crimeTypes));
}

foreach (var crime in crimes)
{
var count = RobustRandom.Next(rule.MinCounts, rule.MaxCounts + 1);
report.PushMarkup(Loc.GetString("fugitive-report-crime", ("crime", Loc.GetString(crime)), ("count", count)));
}
}
}
9 changes: 9 additions & 0 deletions Content.Server/Roles/FugitiveRoleComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Content.Shared.Roles;

namespace Content.Server.Roles;

/// <summary>
/// DeltaV - fugitive antag role
/// </summary>
[RegisterComponent, ExclusiveAntagonist]
public sealed partial class FugitiveRoleComponent : AntagonistRoleComponent;
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,10 @@ public sealed partial class ThiefUndeterminedBackpackComponent : Component

[DataField]
public SoundSpecifier ApproveSound = new SoundPathSpecifier("/Audio/Effects/rustle1.ogg");

/// <summary>
/// Max number of sets you can select.
/// </summary>
[DataField]
public int MaxSelectedSets = 2;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public sealed class ThiefUndeterminedBackpackSystem : EntitySystem
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;

private const int MaxSelectedSets = 2;
public override void Initialize()
{
base.Initialize();
Expand All @@ -35,7 +34,7 @@ private void OnUIOpened(Entity<ThiefUndeterminedBackpackComponent> backpack, ref

private void OnApprove(Entity<ThiefUndeterminedBackpackComponent> backpack, ref ThiefBackpackApproveMessage args)
{
if (backpack.Comp.SelectedSets.Count != MaxSelectedSets)
if (backpack.Comp.SelectedSets.Count != backpack.Comp.MaxSelectedSets)
return;

foreach (var i in backpack.Comp.SelectedSets)
Expand Down Expand Up @@ -79,6 +78,6 @@ private void UpdateUI(EntityUid uid, ThiefUndeterminedBackpackComponent? compone
data.Add(i, info);
}

_ui.SetUiState(uid, ThiefBackpackUIKey.Key, new ThiefBackpackBoundUserInterfaceState(data, MaxSelectedSets));
_ui.SetUiState(uid, ThiefBackpackUIKey.Key, new ThiefBackpackBoundUserInterfaceState(data, component.MaxSelectedSets));
}
}
24 changes: 24 additions & 0 deletions Resources/Locale/en-US/deltav/fugitive/sets.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
fugitive-set-hitman-name = hitman's kit
fugitive-set-hitman-description =
You've taken lives before and are prepared to do so again if necessary.
Comes with a loaded viper and a spare mag.
fugitive-set-saboteur-name = saboteur's kit
fugitive-set-saboteur-description =
Making engineers miserable is your life's mission.
Comes with EMP grenades and a brick of C4.
fugitive-set-ghost-name = ghost's kit
fugitive-set-ghost-description =
Disappear in the middle of a chase to secure your freedom!
Comes with 2 smoke grenades and a scram implanter that can teleport you.
fugitive-set-leverage-name = leverage kit
fugitive-set-leverage-description =
Your years in the clown college taught you to slip security very well.
Use a death adicifier on you or a "friend" to get what you want!
fugitive-set-infiltrator-name = infiltrator's kit
fugitive-set-infiltrator-description =
Use an Agent ID to steal access from others and go anywhere.
Your freedom implanter can be used as a plan B if all else fails.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
fugitive-round-end-agent-name = Fugitive
fugitive-spawn = You fall from the ceiling!
station-event-fugitive-hunt-announcement = Please check communications consoles for a sensitive message.
fugitive-announcement-GALPOL = GALPOL
fugitive-report-title = WANTED: {$name}
fugitive-report-first-line = Escaped fugitive {$name} has been spotted in the sector. They may be a stowaway on a station somewhere.
fugitive-report-inhuman = {CAPITALIZE(THE($name))} {CONJUGATE-BE($name)} inhuman. We have no further details.
fugitive-report-morphotype = MORPHOTYPE: {$species}
fugitive-report-age = AGE: {$age}
fugitive-report-sex = SEX: {$sex ->
[Male] M
[Female] F
*[none] N/A
}
fugitive-report-weight = WEIGHT: {$weight} kg
fugitive-report-crimes-header = The above individual is wanted across the sector for the following:
fugitive-report-crime = - {$count ->
[1] One count
*[other] {$count} counts
} of {$crime}
fugitive-report-last-line = GALPOL prefers the fugitive to be returned alive so they may face trial at Central Command.
# All (non erp) felonies and capital crimes in Space Law as of June 2024
fugitive-crime-1 = Murder
fugitive-crime-2 = Terrorism
fugitive-crime-3 = Grand Sabotage
fugitive-crime-4 = Decorporealisation
fugitive-crime-5 = Kidnapping
fugitive-crime-6 = Sedition
fugitive-crime-7 = Manslaughter
fugitive-crime-8 = Grand Theft
fugitive-crime-9 = Black Marketeering
fugitive-crime-10 = Sabotage
fugitive-crime-11 = Mindbreaking
fugitive-crime-12 = Assault
fugitive-crime-13 = Abuse of Power
fugitive-crime-14 = Possession
fugitive-crime-15 = Endangerment
fugitive-crime-16 = Breaking and Entering
fugitive-crime-17 = Rioting
fugitive-crime-18 = Contempt of Court
fugitive-crime-19 = Perjury
fugitive-crime-20 = False Report
fugitive-crime-21 = Obstruction of Justice
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ ghost-role-information-listeningop-rules = You are a Syndicate Operative tasked
ghost-role-information-paradox-anomaly-name = Paradox Anomaly
ghost-role-information-paradox-anomaly-description = Replace your double, or befriend them.
ghost-role-information-paradox-anomaly-rules = Try and replace your twin with this funny roleplay antag rather than plasma flooding the station or something. You can also just befriend them.
ghost-role-information-fugitive-name = Fugitive
ghost-role-information-fugitive-description = You're an escaped prisoner. Make it out alive.
ghost-role-information-fugitive-rules = You are the lightest of antags, focus on laying low rather than engaging security directly. Don't murderbone.
5 changes: 4 additions & 1 deletion Resources/Locale/en-US/thief/backpack.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ thief-backpack-window-title = thief toolbox
thief-backpack-window-description =
This toolbox is filled with unspecified contents.
Now you need to remember what you put in it.
Choose 2 different sets from the list.
Choose {$maxCount} different {$maxCount ->
[1] set
*[other] sets
} from the list.
thief-backpack-window-selected = Kits selected: ({$selectedCount}/{$maxCount})
Expand Down
Loading

0 comments on commit 540febc

Please sign in to comment.