From: Ed <96445749+TheShuEd@users.noreply.github.com>
Date: Sun, 24 Dec 2023 09:58:28 +0000 (+0300)
Subject: New Thief minor antagonist (#21520)
X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=144af233c4f4135cccacfa5d50281fce44a1595e;p=space-station-14.git
New Thief minor antagonist (#21520)
* start working
* add right-click thief antagins
some architecture restruct
* add meh thief greeting audio
* add thief subgamemode to Traitors gamemode
* add late join thief (not tested yet)
add briefing
* add pacifism
* add Steal tasks to thief
* fix crash thief+traitor on person
* add new condition: collection steal
* add tracking of succes collection objective
* add stamp collection target
remove some boring steal target
add check pulling entity to collection target
* finalize first 2 group objective
* start merging stealing objective systems
* merging
* finish merging. Now traitor steal objective work better
* we don't check the items of pullable sentient entity
* clear naming, enable thief signle item objective start
* objective pack add
* finish with steal item objectives
* convert string to ProtoId<>
* some clean up
* add thieves to revolution game mode
* Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl
Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com>
* Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl
Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com>
* update pacifism: fix crashing, monkey-thief without pacified
* adaptive animal briefing, cleaning locales
* add structure steal objectives
* remove RCD target
* add thiefs to manifest, but bug with traitor duplications
* add escape objective
* add chat briefing
* setup animal objective group system
* add animal steal objectives
* add animal objectives notroleconditions
* add morty
* now thief mode has a chance of not launching Now there are a random number of thieves per round from 1 to 3
* 6 hours of trying to fix duplicate tasks. Failure
* added thief pinpointer (buggy)
* start thief backpack UI work
* revert pinpointer for scope reason
* UI continue work
* add thief starter kits content
* remove ERP kit :trollface:
* finally! giving starting items to thief. Now it playable, but still need more work
* clean up
* fix
* fox
* add merged items into thief
new Starting Kit (buggy)
* fix YES antag menu
* objection tweaks
* remove hearts objective, working on spawning things from toolbox
* smug
* fixes
* add race specifier objective condition LAMPS
* meh
* fix fix fix
* the alive
* Adding stamps
* Update backpack.ftl
* Revert1
* Revert ftl
* add voice mask to communicator kit
* Update Resources/Locale/en-US/administration/antag.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* Update Resources/Locale/en-US/thief/backpack.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* Update Resources/Locale/en-US/objectives/conditions/steal.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* Update Resources/Locale/en-US/thief/backpack.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* Update Resources/Locale/en-US/thief/backpack.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* Update Resources/Locale/en-US/thief/backpack.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* Update Resources/Locale/en-US/thief/backpack.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* Update Resources/Locale/en-US/prototypes/roles/antags.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* Update Resources/Locale/en-US/thief/backpack.ftl
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
* update
* fix
* more reusable function, add documentation
* fix doc
* faint fixes
---------
Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com>
Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
---
diff --git a/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs b/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs
new file mode 100644
index 0000000000..2d492c5e1b
--- /dev/null
+++ b/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs
@@ -0,0 +1,52 @@
+using Content.Shared.Thief;
+using JetBrains.Annotations;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Thief;
+
+[UsedImplicitly]
+public sealed class ThiefBackpackBoundUserInterface : BoundUserInterface
+{
+ private ThiefBackpackMenu? _window;
+
+ public ThiefBackpackBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _window = new ThiefBackpackMenu(this);
+ _window.OnClose += Close;
+ _window.OpenCentered();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing)
+ return;
+
+ _window?.Dispose();
+ _window = null;
+ }
+
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+
+ if (state is not ThiefBackpackBoundUserInterfaceState current)
+ return;
+
+ _window?.UpdateState(current);
+ }
+
+ public void SendChangeSelected(int setNumber)
+ {
+ SendMessage(new ThiefBackpackChangeSetMessage(setNumber));
+ }
+
+ public void SendApprove()
+ {
+ SendMessage(new ThiefBackpackApproveMessage());
+ }
+}
diff --git a/Content.Client/Thief/ThiefBackpackMenu.xaml b/Content.Client/Thief/ThiefBackpackMenu.xaml
new file mode 100644
index 0000000000..c1739eb321
--- /dev/null
+++ b/Content.Client/Thief/ThiefBackpackMenu.xaml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Thief/ThiefBackpackMenu.xaml.cs b/Content.Client/Thief/ThiefBackpackMenu.xaml.cs
new file mode 100644
index 0000000000..b2314cf3fe
--- /dev/null
+++ b/Content.Client/Thief/ThiefBackpackMenu.xaml.cs
@@ -0,0 +1,56 @@
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Thief;
+using Robust.Client.AutoGenerated;
+using Robust.Client.GameObjects;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client.Thief;
+
+[GenerateTypedNameReferences]
+public sealed partial class ThiefBackpackMenu : FancyWindow
+{
+ [Dependency] private readonly IEntitySystemManager _sysMan = default!;
+ private readonly SpriteSystem _spriteSystem;
+
+ private readonly ThiefBackpackBoundUserInterface _owner;
+
+ public ThiefBackpackMenu(ThiefBackpackBoundUserInterface owner)
+ {
+ RobustXamlLoader.Load(this);
+ IoCManager.InjectDependencies(this);
+ _spriteSystem = _sysMan.GetEntitySystem();
+
+ _owner = owner;
+
+ ApproveButton.OnButtonDown += (args) =>
+ {
+ _owner.SendApprove();
+ };
+ }
+
+ public void UpdateState(ThiefBackpackBoundUserInterfaceState state)
+ {
+ SetsGrid.RemoveAllChildren();
+ int count = 0;
+ int selectedNumber = 0;
+ foreach (var set in state.Sets)
+ {
+ var child = new ThiefBackpackSet(set.Value, _spriteSystem);
+
+ child.SetButton.OnButtonDown += (args) =>
+ {
+ _owner.SendChangeSelected(set.Key);
+ };
+
+ SetsGrid.AddChild(child);
+
+ count++;
+
+ if (set.Value.Selected)
+ selectedNumber++;
+ }
+
+ SelectedSets.Text = Loc.GetString("thief-backpack-window-selected", ("selectedCount", selectedNumber), ("maxCount", state.MaxSelectedSets));
+ ApproveButton.Disabled = selectedNumber == state.MaxSelectedSets ? false : true;
+ }
+}
diff --git a/Content.Client/Thief/ThiefBackpackSet.xaml b/Content.Client/Thief/ThiefBackpackSet.xaml
new file mode 100644
index 0000000000..0d8b5e24f7
--- /dev/null
+++ b/Content.Client/Thief/ThiefBackpackSet.xaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Thief/ThiefBackpackSet.xaml.cs b/Content.Client/Thief/ThiefBackpackSet.xaml.cs
new file mode 100644
index 0000000000..84be57daee
--- /dev/null
+++ b/Content.Client/Thief/ThiefBackpackSet.xaml.cs
@@ -0,0 +1,22 @@
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.XAML;
+using Content.Shared.Thief;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Thief;
+
+[GenerateTypedNameReferences]
+public sealed partial class ThiefBackpackSet : Control
+{
+ public ThiefBackpackSet(ThiefBackpackSetInfo set, SpriteSystem spriteSystem)
+ {
+ RobustXamlLoader.Load(this);
+
+ Icon.Texture = spriteSystem.Frame0(set.Sprite);
+ SetName.Text = Loc.GetString(set.Name);
+ SetDescription.Text = Loc.GetString(set.Description);
+ SetButton.Text = Loc.GetString(set.Selected ? "thief-backpack-button-deselect" : "thief-backpack-button-select");
+ SetButton.ModulateSelfOverride = set.Selected ? new Color(40, 84, 35) : new Color(68, 75, 103);
+ }
+}
diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs
index 76cb1e0da9..3adb2d5605 100644
--- a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs
+++ b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs
@@ -1,5 +1,6 @@
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules;
+using Content.Server.StationEvents.Events;
using Content.Server.Zombies;
using Content.Shared.Administration;
using Content.Shared.Database;
@@ -15,6 +16,7 @@ namespace Content.Server.Administration.Systems;
public sealed partial class AdminVerbSystem
{
[Dependency] private readonly ZombieSystem _zombie = default!;
+ [Dependency] private readonly ThiefRuleSystem _thief = default!;
[Dependency] private readonly TraitorRuleSystem _traitorRule = default!;
[Dependency] private readonly NukeopsRuleSystem _nukeopsRule = default!;
[Dependency] private readonly PiratesRuleSystem _piratesRule = default!;
@@ -119,5 +121,22 @@ public sealed partial class AdminVerbSystem
Message = Loc.GetString("admin-verb-make-head-rev"),
};
args.Verbs.Add(headRev);
+
+ Verb thief = new()
+ {
+ Text = Loc.GetString("admin-verb-text-make-thief"),
+ Category = VerbCategory.Antag,
+ Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Clothing/Hands/Gloves/ihscombat.rsi"), "icon"),
+ Act = () =>
+ {
+ if (!_minds.TryGetSession(targetMindComp.Mind, out var session))
+ return;
+
+ _thief.MakeThief(session);
+ },
+ Impact = LogImpact.High,
+ Message = Loc.GetString("admin-verb-make-thief"),
+ };
+ args.Verbs.Add(thief);
}
}
diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs
index b3b8a37508..6fbbd030d0 100644
--- a/Content.Server/Antag/AntagSelectionSystem.cs
+++ b/Content.Server/Antag/AntagSelectionSystem.cs
@@ -25,6 +25,7 @@ using Robust.Server.Audio;
using Robust.Server.Containers;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
+using Content.Server.Shuttles.Components;
namespace Content.Server.Antag;
@@ -149,6 +150,72 @@ public sealed class AntagSelectionSystem : GameRuleSystem
}
}
+ ///
+ /// The function walks through all players, checking their role and preferences to generate a list of players who can become antagonists.
+ ///
+ /// a list of players to check out
+ /// antagonist's code id
+ ///
+ public List FindPotentialAntags(in Dictionary candidates, string antagPreferenceId)
+ {
+ var list = new List();
+ var pendingQuery = GetEntityQuery();
+
+ foreach (var player in candidates.Keys)
+ {
+ // Role prevents antag.
+ if (!_jobs.CanBeAntag(player))
+ continue;
+
+ // Latejoin
+ if (player.AttachedEntity != null && pendingQuery.HasComponent(player.AttachedEntity.Value))
+ continue;
+
+ list.Add(player);
+ }
+
+ var prefList = new List();
+
+ foreach (var player in list)
+ {
+ //player preferences to play as this antag
+ var profile = candidates[player];
+ if (profile.AntagPreferences.Contains(antagPreferenceId))
+ {
+ prefList.Add(player);
+ }
+ }
+ if (prefList.Count == 0)
+ {
+ Log.Info($"Insufficient preferred antag:{antagPreferenceId}, picking at random.");
+ prefList = list;
+ }
+ return prefList;
+ }
+
+ ///
+ /// selects the specified number of players from the list
+ ///
+ /// how many players to take
+ /// a list of players from which to draw
+ ///
+ public List PickAntag(int antagCount, List prefList)
+ {
+ var results = new List(antagCount);
+ if (prefList.Count == 0)
+ {
+ Log.Info("Insufficient ready players to fill up with antags, stopping the selection.");
+ return results;
+ }
+
+ for (var i = 0; i < antagCount; i++)
+ {
+ results.Add(_random.PickAndTake(prefList));
+ Log.Info("Selected a preferred antag.");
+ }
+ return results;
+ }
+
///
/// Will take a group of entities and check if they are all alive or dead
///
diff --git a/Content.Server/GameTicking/Rules/Components/ThiefRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/ThiefRuleComponent.cs
new file mode 100644
index 0000000000..31ea30fc86
--- /dev/null
+++ b/Content.Server/GameTicking/Rules/Components/ThiefRuleComponent.cs
@@ -0,0 +1,54 @@
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+using Content.Shared.Roles;
+using Robust.Shared.Player;
+using Content.Shared.Preferences;
+
+namespace Content.Server.GameTicking.Rules.Components;
+
+///
+/// Stores data for .
+///
+[RegisterComponent, Access(typeof(ThiefRuleSystem))]
+public sealed partial class ThiefRuleComponent : Component
+{
+ ///
+ /// A chance for this mode to be added to the game.
+ ///
+ [DataField]
+ public float RuleChance = 1f;
+
+ [DataField]
+ public ProtoId ThiefPrototypeId = "Thief";
+
+ public Dictionary StartCandidates = new();
+
+ [DataField]
+ public float MaxObjectiveDifficulty = 2.5f;
+
+ [DataField]
+ public int MaxStealObjectives = 10;
+
+ ///
+ /// Things that will be given to thieves
+ ///
+ [DataField]
+ public List StarterItems = new List { "ToolboxThief", "ClothingHandsChameleonThief" }; //TO DO - replace to chameleon thieving gloves whem merg
+
+ ///
+ /// All Thiefes created by this rule
+ ///
+ public readonly List ThiefMinds = new();
+
+ ///
+ /// Max Thiefs created by rule on roundstart
+ ///
+ [DataField]
+ public int MaxAllowThief = 3;
+
+ ///
+ /// Sound played when making the player a thief via antag control or ghost role
+ ///
+ [DataField]
+ public SoundSpecifier? GreetingSound = new SoundPathSpecifier("/Audio/Misc/thief_greeting.ogg");
+}
diff --git a/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs b/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs
new file mode 100644
index 0000000000..d0f7888706
--- /dev/null
+++ b/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs
@@ -0,0 +1,194 @@
+using Content.Server.Chat.Managers;
+using Content.Server.GameTicking.Rules.Components;
+using Content.Server.Mind;
+using Content.Server.Objectives;
+using Content.Server.Shuttles.Components;
+using Content.Server.Roles;
+using Content.Shared.Mind;
+using Content.Shared.Objectives.Components;
+using Content.Shared.Preferences;
+using Content.Shared.Roles;
+using Content.Shared.Roles.Jobs;
+using Robust.Shared.Player;
+using Robust.Shared.Random;
+using Robust.Shared.Prototypes;
+using System.Linq;
+using Content.Shared.Humanoid;
+using Content.Server.Antag;
+using Robust.Server.Audio;
+
+namespace Content.Server.GameTicking.Rules;
+
+public sealed class ThiefRuleSystem : GameRuleSystem
+{
+ [Dependency] private readonly IChatManager _chatManager = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly AntagSelectionSystem _antagSelection = default!;
+ [Dependency] private readonly AudioSystem _audio = default!;
+ [Dependency] private readonly MindSystem _mindSystem = default!;
+ [Dependency] private readonly SharedRoleSystem _roleSystem = default!;
+ [Dependency] private readonly SharedJobSystem _jobs = default!;
+ [Dependency] private readonly ObjectivesSystem _objectives = default!;
+
+ const string bigObjectiveGroup = "ThiefBigObjectiveGroups";
+ const string smallObjectiveGroup = "ThiefObjectiveGroups";
+ const string escapeObjectiveGroup = "ThiefEscapeObjectiveGroups";
+
+ private const float BigObjectiveChance = 0.7f;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnPlayersSpawned);
+
+ SubscribeLocalEvent(OnGetBriefing);
+ SubscribeLocalEvent(OnObjectivesTextGetInfo);
+ }
+
+ private void OnPlayersSpawned(RulePlayerJobsAssignedEvent ev)
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var thief, out var gameRule))
+ {
+ //Chance to not lauch gamerule
+ if (!_random.Prob(thief.RuleChance))
+ {
+ RemComp(uid);
+ continue;
+ }
+
+ if (!GameTicker.IsGameRuleAdded(uid, gameRule))
+ continue;
+
+ foreach (var player in ev.Players)
+ {
+ if (!ev.Profiles.ContainsKey(player.UserId))
+ continue;
+
+ thief.StartCandidates[player] = ev.Profiles[player.UserId];
+ }
+ DoThiefStart(thief);
+ }
+ }
+
+ private void DoThiefStart(ThiefRuleComponent component)
+ {
+ if (!component.StartCandidates.Any())
+ {
+ Log.Error("There are no players who can become thieves.");
+ return;
+ }
+
+ var startThiefCount = Math.Min(component.MaxAllowThief, component.StartCandidates.Count);
+ var thiefPool = _antagSelection.FindPotentialAntags(component.StartCandidates, component.ThiefPrototypeId);
+ //TO DO: When voxes specifies are added, increase their chance of becoming a thief by 4 times >:)
+ var selectedThieves = _antagSelection.PickAntag(_random.Next(1, startThiefCount), thiefPool);
+
+ foreach(var thief in selectedThieves)
+ {
+ MakeThief(thief);
+ }
+ }
+
+ public bool MakeThief(ICommonSession thief)
+ {
+ var thiefRule = EntityQuery().FirstOrDefault();
+ if (thiefRule == null)
+ {
+ GameTicker.StartGameRule("Thief", out var ruleEntity);
+ thiefRule = Comp(ruleEntity);
+ }
+
+ //checks
+ if (!_mindSystem.TryGetMind(thief, out var mindId, out var mind))
+ {
+ Log.Info("Failed getting mind for picked thief.");
+ return false;
+ }
+ if (HasComp(mindId))
+ {
+ Log.Error($"Player {thief.Name} is already a thief.");
+ return false;
+ }
+ if (mind.OwnedEntity is not { } entity)
+ {
+ Log.Error("Mind picked for thief did not have an attached entity.");
+ return false;
+ }
+
+ // Assign thief roles
+ _roleSystem.MindAddRole(mindId, new ThiefRoleComponent
+ {
+ PrototypeId = thiefRule.ThiefPrototypeId
+ });
+
+ // Notificate player about new role assignment
+ if (_mindSystem.TryGetSession(mindId, out var session))
+ {
+ _audio.PlayGlobal(thiefRule.GreetingSound, session);
+ _chatManager.DispatchServerMessage(session, MakeBriefing(mind.OwnedEntity.Value));
+ }
+
+ // Give thieves their objectives
+ var difficulty = 0f;
+
+ if (_random.Prob(BigObjectiveChance)) // 70% chance to 1 big objective (structure or animal)
+ {
+ var objective = _objectives.GetRandomObjective(mindId, mind, bigObjectiveGroup);
+ if (objective != null)
+ {
+ _mindSystem.AddObjective(mindId, mind, objective.Value);
+ difficulty += Comp(objective.Value).Difficulty;
+ }
+ }
+
+ for (var i = 0; i < thiefRule.MaxStealObjectives && thiefRule.MaxObjectiveDifficulty > difficulty; i++) // Many small objectives
+ {
+ var objective = _objectives.GetRandomObjective(mindId, mind, smallObjectiveGroup);
+ if (objective == null)
+ continue;
+
+ _mindSystem.AddObjective(mindId, mind, objective.Value);
+ difficulty += Comp(objective.Value).Difficulty;
+ }
+
+ //Escape target
+ var escapeObjective = _objectives.GetRandomObjective(mindId, mind, escapeObjectiveGroup);
+ if (escapeObjective != null)
+ _mindSystem.AddObjective(mindId, mind, escapeObjective.Value);
+
+ // Give starting items
+ _antagSelection.GiveAntagBagGear(mind.OwnedEntity.Value, thiefRule.StarterItems);
+
+ thiefRule.ThiefMinds.Add(mindId);
+ return true;
+ }
+
+ //Add mind briefing
+ private void OnGetBriefing(Entity thief, ref GetBriefingEvent args)
+ {
+ if (!TryComp(thief.Owner, out var mind) || mind.OwnedEntity == null)
+ return;
+
+ args.Append(MakeBriefing(mind.OwnedEntity.Value));
+ }
+
+ private string MakeBriefing(EntityUid thief)
+ {
+ var isHuman = HasComp(thief);
+ var briefing = "\n";
+ briefing = isHuman
+ ? Loc.GetString("thief-role-greeting-human")
+ : Loc.GetString("thief-role-greeting-animal");
+
+ briefing += "\n \n" + Loc.GetString("thief-role-greeting-equipment") + "\n";
+ return briefing;
+ }
+
+ private void OnObjectivesTextGetInfo(Entity thiefs, ref ObjectivesTextGetInfoEvent args)
+ {
+ args.Minds = thiefs.Comp.ThiefMinds;
+ args.AgentName = Loc.GetString("thief-round-end-agent-name");
+ }
+}
diff --git a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs
index 60a35d704b..26125a6da7 100644
--- a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs
+++ b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using Content.Server.Antag;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
@@ -30,6 +31,7 @@ namespace Content.Server.GameTicking.Rules;
public sealed class TraitorRuleSystem : GameRuleSystem
{
+ [Dependency] private readonly AntagSelectionSystem _antagSelection = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
@@ -117,8 +119,8 @@ public sealed class TraitorRuleSystem : GameRuleSystem
}
var numTraitors = MathHelper.Clamp(component.StartCandidates.Count / PlayersPerTraitor, 1, MaxTraitors);
- var traitorPool = FindPotentialTraitors(component.StartCandidates, component);
- var selectedTraitors = PickTraitors(numTraitors, traitorPool);
+ var traitorPool = _antagSelection.FindPotentialAntags(component.StartCandidates, component.TraitorPrototypeId);
+ var selectedTraitors = _antagSelection.PickAntag(numTraitors, traitorPool);
foreach (var traitor in selectedTraitors)
{
@@ -153,61 +155,6 @@ public sealed class TraitorRuleSystem : GameRuleSystem
}
}
- private List FindPotentialTraitors(in Dictionary candidates, TraitorRuleComponent component)
- {
- var list = new List();
- var pendingQuery = GetEntityQuery();
-
- foreach (var player in candidates.Keys)
- {
- // Role prevents antag.
- if (!_jobs.CanBeAntag(player))
- {
- continue;
- }
-
- // Latejoin
- if (player.AttachedEntity != null && pendingQuery.HasComponent(player.AttachedEntity.Value))
- continue;
-
- list.Add(player);
- }
-
- var prefList = new List();
-
- foreach (var player in list)
- {
- var profile = candidates[player];
- if (profile.AntagPreferences.Contains(component.TraitorPrototypeId))
- {
- prefList.Add(player);
- }
- }
- if (prefList.Count == 0)
- {
- Log.Info("Insufficient preferred traitors, picking at random.");
- prefList = list;
- }
- return prefList;
- }
-
- private List PickTraitors(int traitorCount, List prefList)
- {
- var results = new List(traitorCount);
- if (prefList.Count == 0)
- {
- Log.Info("Insufficient ready players to fill up with traitors, stopping the selection.");
- return results;
- }
-
- for (var i = 0; i < traitorCount; i++)
- {
- results.Add(_random.PickAndTake(prefList));
- Log.Info("Selected a preferred traitor.");
- }
- return results;
- }
-
public bool MakeTraitor(ICommonSession traitor, bool giveUplink = true, bool giveObjectives = true)
{
var traitorRule = EntityQuery().FirstOrDefault();
diff --git a/Content.Server/Objectives/Components/SpeciesRequirmentComponent.cs b/Content.Server/Objectives/Components/SpeciesRequirmentComponent.cs
new file mode 100644
index 0000000000..9324ba4c09
--- /dev/null
+++ b/Content.Server/Objectives/Components/SpeciesRequirmentComponent.cs
@@ -0,0 +1,15 @@
+using Content.Server.Objectives.Systems;
+using Content.Shared.Humanoid.Prototypes;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Objectives.Components;
+
+///
+/// Requires that the player's species matches a whitelist.
+///
+[RegisterComponent, Access(typeof(SpeciesRequirementSystem))]
+public sealed partial class SpeciesRequirementComponent : Component
+{
+ [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
+ public List> AllowedSpecies = new();
+}
diff --git a/Content.Server/Objectives/Components/StealConditionComponent.cs b/Content.Server/Objectives/Components/StealConditionComponent.cs
index b52ac9cbe8..4da028de25 100644
--- a/Content.Server/Objectives/Components/StealConditionComponent.cs
+++ b/Content.Server/Objectives/Components/StealConditionComponent.cs
@@ -1,28 +1,64 @@
using Content.Server.Objectives.Systems;
+using Content.Shared.Objectives;
using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Objectives.Components;
///
-/// Requires that you steal a certain item.
+/// Requires that you steal a certain item (or several)
///
[RegisterComponent, Access(typeof(StealConditionSystem))]
public sealed partial class StealConditionComponent : Component
{
///
- /// The id of the item to steal.
+ /// A group of items to be stolen
///
- ///
- /// Works by prototype id not tags or anything so it has to be the exact item.
- ///
- [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)]
- public string Prototype = string.Empty;
+ [DataField(required: true)]
+ public ProtoId StealGroup;
+
+ ///
+ /// When enabled, disables generation of this target if there is no entity on the map (disable for objects that can be created mid-round).
+ ///
+ [DataField]
+ public bool VerifyMapExistance = true;
+
+ ///
+ /// If the target may be alive but has died, it will not be counted
+ ///
+ [DataField]
+ public bool CheckAlive = false;
+ ///
+ /// The minimum number of items you need to steal to fulfill a objective
+ ///
+ [DataField]
+ public int MinCollectionSize = 1;
+
+ ///
+ /// The maximum number of items you need to steal to fulfill a objective
+ ///
+ [DataField]
+ public int MaxCollectionSize = 1;
+
+ ///
+ /// Target collection size after calculation
+ ///
+ [DataField]
+ public int CollectionSize;
///
/// Help newer players by saying e.g. "steal the chief engineer's advanced magboots"
/// instead of "steal advanced magboots. Should be a loc string.
///
- [DataField("owner"), ViewVariables(VVAccess.ReadWrite)]
+ [DataField("owner")]
public string? OwnerText;
+
+ // All this need to be loc string
+ [DataField(required: true)]
+ public LocId ObjectiveText;
+ [DataField(required: true)]
+ public LocId ObjectiveNoOwnerText;
+ [DataField(required: true)]
+ public LocId DescriptionText;
+ [DataField(required: true)]
+ public LocId DescriptionMultiplyText;
}
diff --git a/Content.Server/Objectives/Components/StealTargetComponent.cs b/Content.Server/Objectives/Components/StealTargetComponent.cs
new file mode 100644
index 0000000000..25fb9d3a70
--- /dev/null
+++ b/Content.Server/Objectives/Components/StealTargetComponent.cs
@@ -0,0 +1,18 @@
+using Content.Server.Objectives.Systems;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Server.Objectives.Components.Targets;
+
+///
+/// Allows an object to become the target of a StealCollection objection
+///
+[RegisterComponent]
+public sealed partial class StealTargetComponent : Component
+{
+ ///
+ /// The theft group to which this item belongs.
+ ///
+ [DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
+ public string StealGroup;
+}
diff --git a/Content.Server/Objectives/ObjectivesSystem.cs b/Content.Server/Objectives/ObjectivesSystem.cs
index bf5fe1d4d4..f59066ff99 100644
--- a/Content.Server/Objectives/ObjectivesSystem.cs
+++ b/Content.Server/Objectives/ObjectivesSystem.cs
@@ -129,6 +129,9 @@ public sealed class ObjectivesSystem : SharedObjectivesSystem
foreach (var objectiveGroup in objectives.GroupBy(o => Comp(o).Issuer))
{
+ //TO DO:
+ //check for the right group here. Getting the target issuer is easy: objectiveGroup.Key
+ //It should be compared to the type of the group's issuer.
result += "\n" + Loc.GetString($"objective-issuer-{objectiveGroup.Key}");
foreach (var objective in objectiveGroup)
diff --git a/Content.Server/Objectives/Systems/SpeciesRequirementSystem.cs b/Content.Server/Objectives/Systems/SpeciesRequirementSystem.cs
new file mode 100644
index 0000000000..ab2d1d4370
--- /dev/null
+++ b/Content.Server/Objectives/Systems/SpeciesRequirementSystem.cs
@@ -0,0 +1,34 @@
+using Content.Server.Objectives.Components;
+using Content.Shared.Humanoid;
+using Content.Shared.Objectives.Components;
+
+namespace Content.Server.Objectives.Systems;
+
+///
+/// Handles species requirement for objectives that require a certain species.
+///
+public sealed class SpeciesRequirementSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnCheck);
+ }
+
+ private void OnCheck(Entity requirement, ref RequirementCheckEvent args)
+ {
+ if (args.Cancelled)
+ return;
+
+ if (!TryComp(args.Mind.OwnedEntity, out var appearance)) {
+ args.Cancelled = true;
+ return;
+ }
+ if (!requirement.Comp.AllowedSpecies.Contains(appearance.Species))
+ {
+ args.Cancelled = true;
+ return;
+ }
+ }
+}
diff --git a/Content.Server/Objectives/Systems/StealConditionSystem.cs b/Content.Server/Objectives/Systems/StealConditionSystem.cs
index 28ab164e0d..2b552285ad 100644
--- a/Content.Server/Objectives/Systems/StealConditionSystem.cs
+++ b/Content.Server/Objectives/Systems/StealConditionSystem.cs
@@ -1,76 +1,136 @@
using Content.Server.Objectives.Components;
+using Content.Server.Objectives.Components.Targets;
using Content.Shared.Mind;
using Content.Shared.Objectives.Components;
using Content.Shared.Objectives.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
-using Robust.Shared.Utility;
+using Robust.Shared.Random;
+using Content.Shared.Pulling.Components;
+using Content.Shared.Objectives;
+using Content.Shared.Mind.Components;
+using Content.Shared.Mobs.Systems;
+using Content.Shared.Mobs.Components;
namespace Content.Server.Objectives.Systems;
public sealed class StealConditionSystem : EntitySystem
{
+ [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
+ [Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
- private EntityQuery containerQuery;
- private EntityQuery metaQuery;
+ private EntityQuery _containerQuery;
+ private EntityQuery _metaQuery;
public override void Initialize()
{
base.Initialize();
- containerQuery = GetEntityQuery();
- metaQuery = GetEntityQuery();
+ _containerQuery = GetEntityQuery();
+ _metaQuery = GetEntityQuery();
SubscribeLocalEvent(OnAssigned);
SubscribeLocalEvent(OnAfterAssign);
SubscribeLocalEvent(OnGetProgress);
}
- private void OnAssigned(EntityUid uid, StealConditionComponent comp, ref ObjectiveAssignedEvent args)
+ /// start checks of target acceptability, and generation of start values.
+ private void OnAssigned(Entity condition, ref ObjectiveAssignedEvent args)
{
- // cancel if the item to steal doesn't exist
- args.Cancelled |= !_proto.HasIndex(comp.Prototype);
+ List targetList = new();
+
+ // cancel if invalid TargetStealName
+ var group = _proto.Index(condition.Comp.StealGroup);
+ if (group == null)
+ {
+ args.Cancelled = true;
+ Log.Error("StealTargetGroup invalid prototype!");
+ return;
+ }
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var target))
+ {
+ if (condition.Comp.StealGroup != target.StealGroup)
+ continue;
+
+ targetList.Add(target);
+ }
+
+ // cancel if the required items do not exist
+ if (targetList.Count == 0 && condition.Comp.VerifyMapExistance)
+ {
+ args.Cancelled = true;
+ return;
+ }
+
+ //setup condition settings
+ var maxSize = condition.Comp.VerifyMapExistance
+ ? Math.Min(targetList.Count, condition.Comp.MaxCollectionSize)
+ : condition.Comp.MaxCollectionSize;
+ var minSize = condition.Comp.VerifyMapExistance
+ ? Math.Min(targetList.Count, condition.Comp.MinCollectionSize)
+ : condition.Comp.MinCollectionSize;
+
+ condition.Comp.CollectionSize = _random.Next(minSize, maxSize);
}
- private void OnAfterAssign(EntityUid uid, StealConditionComponent comp, ref ObjectiveAfterAssignEvent args)
+ //Set the visual, name, icon for the objective.
+ private void OnAfterAssign(Entity condition, ref ObjectiveAfterAssignEvent args)
{
- var proto = _proto.Index(comp.Prototype);
- var title = comp.OwnerText == null
- ? Loc.GetString("objective-condition-steal-title-no-owner", ("itemName", proto.Name))
- : Loc.GetString("objective-condition-steal-title", ("owner", Loc.GetString(comp.OwnerText)), ("itemName", proto.Name));
- var description = Loc.GetString("objective-condition-steal-description", ("itemName", proto.Name));
-
- _metaData.SetEntityName(uid, title, args.Meta);
- _metaData.SetEntityDescription(uid, description, args.Meta);
- _objectives.SetIcon(uid, new SpriteSpecifier.EntityPrototype(comp.Prototype), args.Objective);
- }
+ var group = _proto.Index(condition.Comp.StealGroup);
- private void OnGetProgress(EntityUid uid, StealConditionComponent comp, ref ObjectiveGetProgressEvent args)
+ var title =condition.Comp.OwnerText == null
+ ? Loc.GetString(condition.Comp.ObjectiveNoOwnerText, ("itemName", group.Name))
+ : Loc.GetString(condition.Comp.ObjectiveText, ("owner", Loc.GetString(condition.Comp.OwnerText)), ("itemName", group.Name));
+
+ var description = condition.Comp.CollectionSize > 1
+ ? Loc.GetString(condition.Comp.DescriptionMultiplyText, ("itemName", group.Name), ("count", condition.Comp.CollectionSize))
+ : Loc.GetString(condition.Comp.DescriptionText, ("itemName", group.Name));
+
+ _metaData.SetEntityName(condition.Owner, title, args.Meta);
+ _metaData.SetEntityDescription(condition.Owner, description, args.Meta);
+ _objectives.SetIcon(condition.Owner, group.Sprite, args.Objective);
+ }
+ private void OnGetProgress(Entity condition, ref ObjectiveGetProgressEvent args)
{
- args.Progress = GetProgress(args.Mind, comp.Prototype);
+ args.Progress = GetProgress(args.Mind, condition);
}
- private float GetProgress(MindComponent mind, string prototype)
+ private float GetProgress(MindComponent mind, StealConditionComponent condition)
{
- // TODO make this a container system function
- // or: just iterate through transform children, instead of containers?
-
- if (!metaQuery.TryGetComponent(mind.OwnedEntity, out var meta))
+ if (!_metaQuery.TryGetComponent(mind.OwnedEntity, out var meta))
+ return 0;
+ if (!_containerQuery.TryGetComponent(mind.OwnedEntity, out var currentManager))
return 0;
- // who added this check bruh
- if (meta.EntityPrototype?.ID == prototype)
- return 1;
+ var stack = new Stack();
+ var count = 0;
- if (!containerQuery.TryGetComponent(mind.OwnedEntity, out var currentManager))
- return 0;
+ //check pulling object
+ if (TryComp(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition
+ {
+ var pullid = pull.Pulling;
+ if (pullid != null)
+ {
+ // check if this is the item
+ if (CheckStealTarget(pullid.Value, condition)) count++;
+
+ //we don't check the inventories of sentient entity
+ if (!TryComp(pullid, out var pullMind))
+ {
+ // if it is a container check its contents
+ if (_containerQuery.TryGetComponent(pullid, out var containerManager))
+ stack.Push(containerManager);
+ }
+ }
+ }
// recursively check each container for the item
// checks inventory, bag, implants, etc.
- var stack = new Stack();
do
{
foreach (var container in currentManager.Containers.Values)
@@ -78,16 +138,38 @@ public sealed class StealConditionSystem : EntitySystem
foreach (var entity in container.ContainedEntities)
{
// check if this is the item
- if (metaQuery.GetComponent(entity).EntityPrototype?.ID == prototype)
- return 1;
+ if (CheckStealTarget(entity, condition)) count++; //To Do: add support for stackable items
// if it is a container check its contents
- if (containerQuery.TryGetComponent(entity, out var containerManager))
+ if (_containerQuery.TryGetComponent(entity, out var containerManager))
stack.Push(containerManager);
}
}
} while (stack.TryPop(out currentManager));
- return 0;
+ var result = (float) count / (float) condition.CollectionSize;
+ result = Math.Clamp(result, 0, 1);
+ return result;
+ }
+
+ private bool CheckStealTarget(EntityUid entity, StealConditionComponent condition)
+ {
+ // check if this is the target
+ if (!TryComp(entity, out var target))
+ return false;
+
+ if (target.StealGroup != condition.StealGroup)
+ return false;
+
+ // check if needed target alive
+ if (condition.CheckAlive)
+ {
+ if (TryComp(entity, out var state))
+ {
+ if (!_mobState.IsAlive(entity))
+ return false;
+ }
+ }
+ return true;
}
}
diff --git a/Content.Server/Roles/RoleSystem.cs b/Content.Server/Roles/RoleSystem.cs
index 6ac0e24540..c53fa1cf9e 100644
--- a/Content.Server/Roles/RoleSystem.cs
+++ b/Content.Server/Roles/RoleSystem.cs
@@ -1,4 +1,4 @@
-using Content.Shared.Roles;
+using Content.Shared.Roles;
namespace Content.Server.Roles;
@@ -17,6 +17,7 @@ public sealed class RoleSystem : SharedRoleSystem
SubscribeAntagEvents();
SubscribeAntagEvents();
SubscribeAntagEvents();
+ SubscribeAntagEvents();
}
public string? MindGetBriefing(EntityUid? mindId)
diff --git a/Content.Server/Roles/ThiefRoleComponent.cs b/Content.Server/Roles/ThiefRoleComponent.cs
new file mode 100644
index 0000000000..82e350ef63
--- /dev/null
+++ b/Content.Server/Roles/ThiefRoleComponent.cs
@@ -0,0 +1,8 @@
+using Content.Shared.Roles;
+
+namespace Content.Server.Roles;
+
+[RegisterComponent]
+public sealed partial class ThiefRoleComponent : AntagonistRoleComponent
+{
+}
diff --git a/Content.Server/Thief/Components/ThiefUndeterminedBackpackComponent.cs b/Content.Server/Thief/Components/ThiefUndeterminedBackpackComponent.cs
new file mode 100644
index 0000000000..c39807414a
--- /dev/null
+++ b/Content.Server/Thief/Components/ThiefUndeterminedBackpackComponent.cs
@@ -0,0 +1,25 @@
+using Content.Shared.Thief;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Thief.Components;
+
+///
+/// This component stores the possible contents of the backpack,
+/// which can be selected via the interface.
+///
+[RegisterComponent]
+public sealed partial class ThiefUndeterminedBackpackComponent : Component
+{
+ ///
+ /// List of sets available for selection
+ ///
+ [DataField]
+ public List> PossibleSets = new();
+
+ [DataField]
+ public List SelectedSets = new();
+
+ [DataField]
+ public SoundSpecifier ApproveSound = new SoundPathSpecifier("/Audio/Effects/rustle1.ogg");
+}
diff --git a/Content.Server/Thief/Systems/ThiefUndeterminedBackpackSystem.cs b/Content.Server/Thief/Systems/ThiefUndeterminedBackpackSystem.cs
new file mode 100644
index 0000000000..99cbcfa07c
--- /dev/null
+++ b/Content.Server/Thief/Systems/ThiefUndeterminedBackpackSystem.cs
@@ -0,0 +1,79 @@
+using Content.Server.Thief.Components;
+using Content.Shared.Item;
+using Content.Shared.Thief;
+using Robust.Server.GameObjects;
+using Robust.Server.Audio;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Thief.Systems;
+public sealed class ThiefUndeterminedBackpackSystem : EntitySystem
+{
+ [Dependency] private readonly AudioSystem _audio = default!;
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly UserInterfaceSystem _ui = default!;
+
+ private const int MaxSelectedSets = 2;
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnUIOpened);
+ SubscribeLocalEvent(OnApprove);
+ SubscribeLocalEvent(OnChangeSet);
+ }
+
+ private void OnUIOpened(Entity backpack, ref BoundUIOpenedEvent args)
+ {
+ UpdateUI(backpack.Owner, backpack.Comp);
+ }
+
+ private void OnApprove(Entity backpack, ref ThiefBackpackApproveMessage args)
+ {
+ if (backpack.Comp.SelectedSets.Count != MaxSelectedSets)
+ return;
+
+ foreach (var i in backpack.Comp.SelectedSets)
+ {
+ var set = _proto.Index(backpack.Comp.PossibleSets[i]);
+ foreach (var item in set.Content)
+ {
+ var ent = Spawn(item, _transform.GetMapCoordinates(backpack.Owner));
+ if (TryComp(ent, out var itemComponent))
+ _transform.DropNextTo(ent, backpack.Owner);
+ }
+ }
+ _audio.PlayPvs(backpack.Comp.ApproveSound, backpack.Owner);
+ QueueDel(backpack); //hehe
+ }
+ private void OnChangeSet(Entity backpack, ref ThiefBackpackChangeSetMessage args)
+ {
+ //Swith selecting set
+ if (!backpack.Comp.SelectedSets.Remove(args.SetNumber))
+ backpack.Comp.SelectedSets.Add(args.SetNumber);
+
+ UpdateUI(backpack.Owner, backpack.Comp);
+ }
+
+ private void UpdateUI(EntityUid uid, ThiefUndeterminedBackpackComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return;
+
+ Dictionary data = new();
+
+ for (int i = 0; i < component.PossibleSets.Count; i++)
+ {
+ var set = _proto.Index(component.PossibleSets[i]);
+ var selected = component.SelectedSets.Contains(i);
+ var info = new ThiefBackpackSetInfo(
+ set.Name,
+ set.Description,
+ set.Sprite,
+ selected);
+ data.Add(i, info);
+ }
+
+ _ui.TrySetUiState(uid, ThiefBackpackUIKey.Key, new ThiefBackpackBoundUserInterfaceState(data, MaxSelectedSets));
+ }
+}
diff --git a/Content.Shared/Objectives/Prototypes/StealTargetGroupPrototype.cs b/Content.Shared/Objectives/Prototypes/StealTargetGroupPrototype.cs
new file mode 100644
index 0000000000..2730acb9ac
--- /dev/null
+++ b/Content.Shared/Objectives/Prototypes/StealTargetGroupPrototype.cs
@@ -0,0 +1,15 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+
+namespace Content.Shared.Objectives;
+
+///
+/// General data about a group of items, such as icon, description, name. Used for Steal objective
+///
+[Prototype("stealTargetGroup")]
+public sealed partial class StealTargetGroupPrototype : IPrototype
+{
+ [IdDataField] public string ID { get; private set; } = default!;
+ [DataField] public string Name { get; private set; } = string.Empty;
+ [DataField] public SpriteSpecifier Sprite { get; private set; } = SpriteSpecifier.Invalid;
+}
diff --git a/Content.Shared/Thief/Components/ThiefBackpackUI.cs b/Content.Shared/Thief/Components/ThiefBackpackUI.cs
new file mode 100644
index 0000000000..c68bd4cb2f
--- /dev/null
+++ b/Content.Shared/Thief/Components/ThiefBackpackUI.cs
@@ -0,0 +1,63 @@
+using Robust.Shared.Serialization;
+using Robust.Shared.Utility;
+
+namespace Content.Shared.Thief;
+
+[Serializable, NetSerializable]
+public sealed class ThiefBackpackBoundUserInterfaceState : BoundUserInterfaceState
+{
+ public readonly Dictionary Sets;
+ public int MaxSelectedSets;
+
+ public ThiefBackpackBoundUserInterfaceState(Dictionary sets, int max)
+ {
+ Sets = sets;
+ MaxSelectedSets = max;
+ }
+}
+
+[Serializable, NetSerializable]
+public sealed class ThiefBackpackChangeSetMessage : BoundUserInterfaceMessage
+{
+ public readonly int SetNumber;
+
+ public ThiefBackpackChangeSetMessage(int setNumber)
+ {
+ SetNumber = setNumber;
+ }
+}
+
+[Serializable, NetSerializable]
+public sealed class ThiefBackpackApproveMessage : BoundUserInterfaceMessage
+{
+ public ThiefBackpackApproveMessage() { }
+}
+
+[Serializable, NetSerializable]
+public enum ThiefBackpackUIKey : byte
+{
+ Key
+};
+
+[Serializable, NetSerializable, DataDefinition]
+public partial struct ThiefBackpackSetInfo
+{
+ [DataField]
+ public string Name;
+
+ [DataField]
+ public string Description;
+
+ [DataField]
+ public SpriteSpecifier Sprite;
+
+ public bool Selected;
+
+ public ThiefBackpackSetInfo(string name, string desc, SpriteSpecifier sprite, bool selected)
+ {
+ Name = name;
+ Description = desc;
+ Sprite = sprite;
+ Selected = selected;
+ }
+}
diff --git a/Content.Shared/Thief/Prototypes/ThiefBackpackSetPrototype.cs b/Content.Shared/Thief/Prototypes/ThiefBackpackSetPrototype.cs
new file mode 100644
index 0000000000..571db09ebe
--- /dev/null
+++ b/Content.Shared/Thief/Prototypes/ThiefBackpackSetPrototype.cs
@@ -0,0 +1,18 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+
+namespace Content.Shared.Thief;
+
+///
+/// A prototype that defines a set of items and visuals in a specific starter set for the antagonist thief
+///
+[Prototype("thiefBackpackSet")]
+public sealed partial class ThiefBackpackSetPrototype : IPrototype
+{
+ [IdDataField] public string ID { get; private set; } = default!;
+ [DataField] public string Name { get; private set; } = string.Empty;
+ [DataField] public string Description { get; private set; } = string.Empty;
+ [DataField] public SpriteSpecifier Sprite { get; private set; } = SpriteSpecifier.Invalid;
+
+ [DataField] public List Content = new();
+}
diff --git a/Resources/Audio/Misc/attributions.yml b/Resources/Audio/Misc/attributions.yml
index 29cab4382a..2599cf8083 100644
--- a/Resources/Audio/Misc/attributions.yml
+++ b/Resources/Audio/Misc/attributions.yml
@@ -8,6 +8,11 @@
copyright: "Taken from TG station."
source: "https://github.com/tgstation/tgstation/blob/b02b93ce2ab891164511a973493cdf951b4120f7/sound/effects/ninja_greeting.ogg"
+- files: ["thief_greeting.ogg"]
+ license: "CC-BY-NC-4.0"
+ copyright: "Taken from SergeQuadrado via freesound.org, edit and mono by TheShuEd"
+ source: "https://freesound.org/people/SergeQuadrado/sounds/683504/"
+
- files: ["narsie_rises.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Taken from TG station."
diff --git a/Resources/Audio/Misc/thief_greeting.ogg b/Resources/Audio/Misc/thief_greeting.ogg
new file mode 100644
index 0000000000..826d48c7a3
Binary files /dev/null and b/Resources/Audio/Misc/thief_greeting.ogg differ
diff --git a/Resources/Locale/en-US/administration/antag.ftl b/Resources/Locale/en-US/administration/antag.ftl
index f3b3d91945..535659f27e 100644
--- a/Resources/Locale/en-US/administration/antag.ftl
+++ b/Resources/Locale/en-US/administration/antag.ftl
@@ -4,9 +4,11 @@ admin-verb-make-zombie = Zombifies the target immediately.
admin-verb-make-nuclear-operative = Make target into a lone Nuclear Operative.
admin-verb-make-pirate = Make the target into a pirate. Note this doesn't configure the game rule.
admin-verb-make-head-rev = Make the target into a Head Revolutionary.
+admin-verb-make-thief = Make the target into a thief.
admin-verb-text-make-traitor = Make Traitor
admin-verb-text-make-zombie = Make Zombie
admin-verb-text-make-nuclear-operative = Make Nuclear Operative
admin-verb-text-make-pirate = Make Pirate
admin-verb-text-make-head-rev = Make Head Rev
+admin-verb-text-make-thief = Make Thief
\ No newline at end of file
diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl
new file mode 100644
index 0000000000..4a037351ca
--- /dev/null
+++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl
@@ -0,0 +1,20 @@
+thief-role-greeting-human =
+ You are a criminal scum.
+ You want to add to your collection
+ some property of Nanotrasen station.
+ You're not a murderer.
+ You are forbidden to kill.
+
+thief-role-greeting-animal =
+ You are a kleptomaniaÑ animal.
+ Steal things you like.
+
+thief-role-greeting-equipment =
+ You have a toolbox of thief's
+ tools and chameleon thief's gloves.
+ Choose your starting equipment,
+ and do your work stealthily.
+
+objective-issuer-thief = [color=#746694]Criminal[/color]
+
+thief-round-end-agent-name = thief
\ No newline at end of file
diff --git a/Resources/Locale/en-US/objectives/conditions/steal.ftl b/Resources/Locale/en-US/objectives/conditions/steal.ftl
index 35095c2a2d..bce645da8e 100644
--- a/Resources/Locale/en-US/objectives/conditions/steal.ftl
+++ b/Resources/Locale/en-US/objectives/conditions/steal.ftl
@@ -1,6 +1,11 @@
objective-condition-steal-title-no-owner = Steal the {$itemName}.
+objective-condition-steal-title-alive-no-owner = Steal {$itemName}.
objective-condition-steal-title = Steal the {$owner}'s {$itemName}.
objective-condition-steal-description = We need you to steal {$itemName}. Don't get caught.
objective-condition-steal-station = station
objective-condition-steal-Ian = head of personnel's corgi
+
+objective-condition-thief-description = The {$itemName} would be a great addition to my collection!
+objective-condition-thief-animal-description = The {$itemName} would be a great addition to my collection! Most importantly, alive.
+objective-condition-thief-multiply-description = I need to get {$count} {$itemName} and take them with me.
\ No newline at end of file
diff --git a/Resources/Locale/en-US/prototypes/roles/antags.ftl b/Resources/Locale/en-US/prototypes/roles/antags.ftl
index f771b5d911..2848300c19 100644
--- a/Resources/Locale/en-US/prototypes/roles/antags.ftl
+++ b/Resources/Locale/en-US/prototypes/roles/antags.ftl
@@ -27,3 +27,6 @@ roles-antag-subverted-silicon-objective = Follow your new laws and do bad unto t
roles-antag-space-ninja-name = Space Ninja
roles-antag-space-ninja-objective = Use your stealth to sabotage the station, nom on electrical wires.
+
+roles-antag-thief-name = Thief
+roles-antag-thief-objective = Add some NT property to your personal collection without using violence.
\ No newline at end of file
diff --git a/Resources/Locale/en-US/thief/backpack.ftl b/Resources/Locale/en-US/thief/backpack.ftl
new file mode 100644
index 0000000000..bdc463fc2a
--- /dev/null
+++ b/Resources/Locale/en-US/thief/backpack.ftl
@@ -0,0 +1,62 @@
+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 up to two different sets from the list.
+
+thief-backpack-window-selected = Kits selected: ({$selectedCount}/{$maxCount})
+
+thief-backpack-window-approve-button = Approve
+thief-backpack-button-select = Select [ ]
+thief-backpack-button-deselect = Select [X]
+
+# Sets
+
+thief-backpack-category-chameleon-name = Chameleon's kit.
+thief-backpack-category-chameleon-description =
+ Includes a full set of clothing that contain
+ chameleon technology, allowing you to disguise
+ as pretty much anything on the station.
+
+thief-backpack-category-tools-name = Bearcatcher's kit
+thief-backpack-category-tools-description =
+ A set of tools for roughing up doors, walls, windows,
+ and anything else that for whatever reason doesn't
+ want to let you in where you need to go.
+ Includes two C4s, a multitool, jaws of life,
+ a pair of advanced welder meson glasses and some insulated gloves.
+
+thief-backpack-category-chemistry-name = Chemistry kit
+thief-backpack-category-chemistry-description =
+ A set for those who love to improve their body.
+ It includes a storage implanter,
+ a dna scrambler implanter,
+ and a set of chemicals for a rainy day.
+
+thief-backpack-category-syndie-name = Syndie kit
+thief-backpack-category-syndie-description =
+ A set of items from a syndicate agent you've robbed
+ in the past. Includes an Agent ID card, a syndicate pAI,
+ and some strange red crystals.
+
+thief-backpack-category-sleeper-name = Sleepwalker's kit
+thief-backpack-category-sleeper-description =
+ A set for those who like to sleep in,
+ or for everyone around you to sleep.
+ Includes a set of nocturine vials, a hypopen and
+ a tank of sleeping gas.
+
+thief-backpack-category-communicator-name = Communicator's kit
+thief-backpack-category-communicator-description =
+ A communication enthusiast's kit. Includes a master key
+ for all station channels, a radio jammer, a portable
+ crew monitor, a voice chameleon mask and lots of money for business deals.
+
+thief-backpack-category-smuggler-name = Smuggler's kit
+thief-backpack-category-smuggler-description =
+ A kit for those who like to have big pockets.
+ Includes a fulton beacon, ten fultons
+ and an invisible crate. You can't move in them,
+ but you can quickly hide or carry valuable loot.
+ This kit also has a cool void cloak to go along with it.
diff --git a/Resources/Prototypes/Catalog/thief_toolbox_sets.yml b/Resources/Prototypes/Catalog/thief_toolbox_sets.yml
new file mode 100644
index 0000000000..d879fd77eb
--- /dev/null
+++ b/Resources/Prototypes/Catalog/thief_toolbox_sets.yml
@@ -0,0 +1,107 @@
+- type: thiefBackpackSet
+ id: ChameleonSet
+ name: thief-backpack-category-chameleon-name
+ description: thief-backpack-category-chameleon-description
+ sprite:
+ sprite: /Textures/Clothing/OuterClothing/Misc/black_hoodie.rsi
+ state: icon
+ content:
+ - ClothingUniformJumpsuitChameleon
+ - ClothingOuterChameleon
+ - ClothingNeckChameleon
+ - ClothingMaskGasChameleon
+ - ClothingHeadHatChameleon
+ - ClothingEyesChameleon
+ - ClothingHeadsetChameleon
+ - ClothingShoesChameleon
+
+- type: thiefBackpackSet
+ id: ToolsSet
+ name: thief-backpack-category-tools-name
+ description: thief-backpack-category-tools-description
+ sprite:
+ sprite: Objects/Tools/jaws_of_life.rsi
+ state: jaws_pry
+ content:
+ - WelderIndustrialAdvanced
+ - ClothingEyesGlassesMeson
+ - ClothingHandsGlovesColorYellow
+ - JawsOfLife
+ - Multitool
+ - C4
+ - C4
+ - ClothingMaskClown
+
+- type: thiefBackpackSet
+ id: ChemistrySet
+ name: thief-backpack-category-chemistry-name
+ description: thief-backpack-category-chemistry-description
+ sprite:
+ sprite: Objects/Specific/Medical/implanter.rsi
+ state: implanter0
+ content:
+ - StorageImplanter
+ - DnaScramblerImplanter
+ - EphedrineChemistryBottle
+ - OmnizineChemistryBottle
+ - Syringe
+ - DrinkVodkaBottleFull
+
+- type: thiefBackpackSet
+ id: SyndieSet
+ name: thief-backpack-category-syndie-name
+ description: thief-backpack-category-syndie-description
+ sprite:
+ sprite: Objects/Specific/Syndicate/telecrystal.rsi
+ state: telecrystal
+ content:
+ - AgentIDCard
+ - SyndicatePersonalAI
+ - ClothingHeadHatSyndieMAA
+ - CigPackSyndicate
+ - Telecrystal10 #The thief cannot use them, but it may induce communication with traitors
+
+- type: thiefBackpackSet
+ id: SleeperSet
+ name: thief-backpack-category-sleeper-name
+ description: thief-backpack-category-sleeper-description
+ sprite:
+ sprite: Objects/Tanks/anesthetic.rsi
+ state: icon
+ content:
+ - ClothingHeadPyjamaSyndicateBlack
+ - ClothingUniformJumpsuitPyjamaSyndicateBlack
+ - NocturineChemistryBottle
+ - NocturineChemistryBottle
+ - NocturineChemistryBottle
+ - HypopenBox
+ - NitrousOxideTankFilled
+ - BedsheetSyndie
+
+- type: thiefBackpackSet
+ id: CommunicatorSet
+ name: thief-backpack-category-communicator-name
+ description: thief-backpack-category-communicator-description
+ sprite:
+ sprite: Objects/Tools/spy_device.rsi
+ state: icon
+ content:
+ - EncryptionKeyStationMaster
+ - RadioJammer
+ - SpyCrewMonitor
+ - BriefcaseSyndieLobbyingBundleFilled
+ - ClothingMaskGasVoiceChameleon
+ #- todo Chameleon Stamp
+
+- type: thiefBackpackSet
+ id: SmugglerSet
+ name: thief-backpack-category-smuggler-name
+ description: thief-backpack-category-smuggler-description
+ sprite:
+ sprite: Clothing/Neck/Cloaks/void.rsi
+ state: icon
+ content:
+ - InvisibleCrate
+ - ClothingNeckCloakVoid
+ - FultonBeacon
+ - Fulton
diff --git a/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml b/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml
index 7981fc2b9e..9dd72691b5 100644
--- a/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml
+++ b/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml
@@ -96,6 +96,8 @@
sprite: Clothing/Ears/Headsets/medical.rsi
- type: Clothing
sprite: Clothing/Ears/Headsets/medical.rsi
+ - type: StealTarget
+ stealGroup: ClothingHeadsetAltMedical
- type: entity
parent: ClothingHeadsetAlt
diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml
index 0cc37f0b56..18dc207a9e 100644
--- a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml
+++ b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml
@@ -43,6 +43,8 @@
- type: Clothing
sprite: Clothing/Eyes/Hud/beergoggles.rsi
- type: ShowThirstIcons
+ - type: StealTarget
+ stealGroup: ClothingEyesHudBeer
- type: SolutionScanner
- type: entity
diff --git a/Resources/Prototypes/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Entities/Clothing/Head/hats.yml
index df85596948..d3fa79511a 100644
--- a/Resources/Prototypes/Entities/Clothing/Head/hats.yml
+++ b/Resources/Prototypes/Entities/Clothing/Head/hats.yml
@@ -471,6 +471,8 @@
sprite: Clothing/Head/Hats/warden.rsi
- type: Clothing
sprite: Clothing/Head/Hats/warden.rsi
+ - type: StealTarget
+ stealGroup: ClothingHeadHatWarden
- type: entity
parent: ClothingHeadBase
diff --git a/Resources/Prototypes/Entities/Clothing/Neck/cloaks.yml b/Resources/Prototypes/Entities/Clothing/Neck/cloaks.yml
index 361ef65734..6d6e2fb8a8 100644
--- a/Resources/Prototypes/Entities/Clothing/Neck/cloaks.yml
+++ b/Resources/Prototypes/Entities/Clothing/Neck/cloaks.yml
@@ -6,6 +6,8 @@
components:
- type: Sprite
sprite: Clothing/Neck/Cloaks/cap.rsi
+ - type: StealTarget
+ stealGroup: HeadCloak
- type: entity
parent: ClothingNeckBase
@@ -15,6 +17,8 @@
components:
- type: Sprite
sprite: Clothing/Neck/Cloaks/hos.rsi
+ - type: StealTarget
+ stealGroup: HeadCloak
- type: entity
parent: ClothingNeckBase
@@ -24,6 +28,8 @@
components:
- type: Sprite
sprite: Clothing/Neck/Cloaks/ce.rsi
+ - type: StealTarget
+ stealGroup: HeadCloak
- type: entity
parent: ClothingNeckBase
@@ -33,6 +39,8 @@
components:
- type: Sprite
sprite: Clothing/Neck/Cloaks/cmo.rsi
+ - type: StealTarget
+ stealGroup: HeadCloak
- type: entity
parent: ClothingNeckBase
@@ -42,6 +50,8 @@
components:
- type: Sprite
sprite: Clothing/Neck/Cloaks/rd.rsi
+ - type: StealTarget
+ stealGroup: HeadCloak
- type: entity
parent: ClothingNeckBase
@@ -51,6 +61,8 @@
components:
- type: Sprite
sprite: Clothing/Neck/Cloaks/qm.rsi
+ - type: StealTarget
+ stealGroup: HeadCloak
- type: entity
parent: ClothingNeckBase
@@ -60,6 +72,8 @@
components:
- type: Sprite
sprite: Clothing/Neck/Cloaks/hop.rsi
+ - type: StealTarget
+ stealGroup: HeadCloak
- type: entity
parent: ClothingNeckBase
@@ -87,6 +101,8 @@
components:
- type: Sprite
sprite: Clothing/Neck/Cloaks/capcloakformal.rsi
+ - type: StealTarget
+ stealGroup: HeadCloak
- type: entity
parent: ClothingNeckBase
@@ -96,6 +112,8 @@
components:
- type: Sprite
sprite: Clothing/Neck/Cloaks/admin.rsi
+ - type: StealTarget
+ stealGroup: HeadCloak
- type: entity
parent: ClothingNeckBase
diff --git a/Resources/Prototypes/Entities/Clothing/Neck/medals.yml b/Resources/Prototypes/Entities/Clothing/Neck/medals.yml
index 3ac3fb126e..016258a6ed 100644
--- a/Resources/Prototypes/Entities/Clothing/Neck/medals.yml
+++ b/Resources/Prototypes/Entities/Clothing/Neck/medals.yml
@@ -20,6 +20,8 @@
sprite: Clothing/Neck/Medals/gold.rsi
- type: Clothing
sprite: Clothing/Neck/Medals/gold.rsi
+ - type: StealTarget
+ stealGroup: ClothingNeckGoldmedal
- type: entity
parent: ClothingNeckBase
@@ -86,3 +88,5 @@
sprite: Clothing/Neck/Medals/clownmedal.rsi
- type: Clothing
sprite: Clothing/Neck/Medals/clownmedal.rsi
+ - type: StealTarget
+ stealGroup: ClothingNeckClownmedal
diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml
index d73c8ab046..f88ad818ac 100644
--- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml
+++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml
@@ -371,6 +371,8 @@
clothingPrototype: ClothingHeadHelmetHardsuitRd
- type: StaticPrice
price: 750
+ - type: StealTarget
+ stealGroup: ClothingOuterHardsuitRd
#Head of Security's Hardsuit
- type: entity
diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml
index e46db13bd2..128d2db5fb 100644
--- a/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml
+++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml
@@ -115,3 +115,5 @@
Radiation: 0.75
Caustic: 0.5
- type: GroupExamine
+ - type: StealTarget
+ stealGroup: ClothingOuterHardsuitVoidParamed
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml
index 2b8f420273..38127f8a3e 100644
--- a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml
+++ b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml
@@ -53,6 +53,8 @@
- HighRiskItem
- type: StaticPrice
price: 750
+ - type: StealTarget
+ stealGroup: ClothingShoesBootsMagAdv
- type: entity
parent: ClothingShoesBootsMag
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
index 9e669d7646..f8d37e0db0 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml
@@ -34,6 +34,8 @@
tags:
- CannotSuicide
- VimPilot
+ - type: StealTarget
+ stealGroup: AnimalIan
- type: entity
name: Old Ian
@@ -238,6 +240,8 @@
tags:
- CannotSuicide
- VimPilot
+ - type: StealTarget
+ stealGroup: AnimalBingus
- type: entity
name: McGriff
@@ -301,6 +305,8 @@
tags:
- CannotSuicide
- VimPilot
+ - type: StealTarget
+ stealGroup: AnimalMcGriff
- type: entity
name: Paperwork
@@ -398,6 +404,8 @@
tags:
- CannotSuicide
- VimPilot
+ - type: StealTarget
+ stealGroup: AnimalWalter
- type: entity
name: Morty
@@ -420,6 +428,8 @@
tags:
- CannotSuicide
- VimPilot
+ - type: StealTarget
+ stealGroup: AnimalMorty
- type: entity
name: Morty
@@ -534,6 +544,8 @@
tags:
- CannotSuicide
- VimPilot
+ - type: StealTarget
+ stealGroup: AnimalRenault
- type: entity
name: Hamlet
@@ -574,6 +586,8 @@
- CannotSuicide
- Hamster
- VimPilot
+ - type: StealTarget
+ stealGroup: AnimalHamlet
- type: entity
name: Shiva
@@ -649,6 +663,8 @@
tags:
- CannotSuicide
- VimPilot
+ - type: StealTarget
+ stealGroup: AnimalShiva
- type: entity
name: Willow
@@ -747,6 +763,8 @@
attributes:
proper: true
gender: female
+ - type: StealTarget
+ stealGroup: AnimalSmile
- type: entity
name: Pun Pun
@@ -781,3 +799,5 @@
attributes:
proper: true
gender: male
+ - type: StealTarget
+ stealGroup: AnimalPunPun
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml
index a2db895c5c..ceafc12302 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml
@@ -307,6 +307,8 @@
Quantity: 20
- type: StaticPrice
price: 750
+ - type: StealTarget
+ stealGroup: FoodMeatCorgi
- type: entity
name: raw crab meat
diff --git a/Resources/Prototypes/Entities/Objects/Decoration/jackolantern.yml b/Resources/Prototypes/Entities/Objects/Decoration/jackolantern.yml
index 4dbcddb983..73c737ad7c 100644
--- a/Resources/Prototypes/Entities/Objects/Decoration/jackolantern.yml
+++ b/Resources/Prototypes/Entities/Objects/Decoration/jackolantern.yml
@@ -27,6 +27,8 @@
color: "#cc6600"
radius: 2.0
energy: 4.0
+ - type: StealTarget
+ stealGroup: LAMP
- type: entity
parent: CarvedPumpkin
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
index 8612f84197..e0d084cec5 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
@@ -61,6 +61,8 @@
requirements:
MatterBin: 1
Manipulator: 1
+ - type: StealTarget
+ stealGroup: AmmoTechFabCircuitboard
- type: entity
id: MedicalTechFabCircuitboard
@@ -80,6 +82,8 @@
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
+ - type: StealTarget
+ stealGroup: MedicalTechFabCircuitboard
- type: entity
id: CircuitImprinterMachineCircuitboard
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
index 13967b9df5..db15d9f629 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
@@ -124,6 +124,8 @@
state: cpu_supply
- type: ComputerBoard
prototype: ComputerSalvageExpedition
+ - type: StealTarget
+ stealGroup: SalvageExpeditionsComputerCircuitboard
- type: entity
parent: BaseComputerCircuitboard
@@ -133,6 +135,8 @@
components:
- type: ComputerBoard
prototype: ComputerShuttleCargo
+ - type: StealTarget
+ stealGroup: CargoShuttleConsoleCircuitboard
- type: entity
parent: BaseComputerCircuitboard
@@ -142,6 +146,8 @@
components:
- type: ComputerBoard
prototype: ComputerShuttleSalvage
+ - type: StealTarget
+ stealGroup: SalvageShuttleConsoleCircuitboard
- type: entity
parent: BaseComputerCircuitboard
diff --git a/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml b/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml
index 9ec14f6589..ae40b64514 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml
@@ -9,6 +9,8 @@
sprite: Objects/Devices/door_remote.rsi
- type: Access
- type: DoorRemote
+ - type: StealTarget
+ stealGroup: DoorRemote
- type: entity
parent: DoorRemoteDefault
diff --git a/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml b/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml
index a47d9c8d61..1408423c5c 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml
@@ -10,6 +10,8 @@
sprite: Objects/Devices/encryption_keys.rsi
- type: Sprite
sprite: Objects/Devices/encryption_keys.rsi
+ - type: StealTarget
+ stealGroup: EncryptionKey
- type: entity
parent: EncryptionKey
diff --git a/Resources/Prototypes/Entities/Objects/Devices/forensic_scanner.yml b/Resources/Prototypes/Entities/Objects/Devices/forensic_scanner.yml
index 21943bfaff..ebfba2f918 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/forensic_scanner.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/forensic_scanner.yml
@@ -26,6 +26,8 @@
- type: GuideHelp
guides:
- DNA
+ - type: StealTarget
+ stealGroup: ForensicScanner
- type: entity
name: forensic scanner report
diff --git a/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml b/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml
index 0acd4fbf19..deac20e05e 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml
@@ -12,3 +12,5 @@
- type: Tag
tags:
- HighRiskItem
+ - type: StealTarget
+ stealGroup: HandTeleporter
diff --git a/Resources/Prototypes/Entities/Objects/Devices/nuke.yml b/Resources/Prototypes/Entities/Objects/Devices/nuke.yml
index 878353f80f..63e28648c3 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/nuke.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/nuke.yml
@@ -67,6 +67,8 @@
- type: ContainerContainer
containers:
Nuke: !type:ContainerSlot
+ - type: StealTarget
+ stealGroup: NuclearBomb
- type: entity
parent: NuclearBomb
diff --git a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml
index 8d48573d65..a30f96b96b 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml
@@ -83,4 +83,4 @@
state: pinpointer-station
- type: Pinpointer
component: BecomesStation
- targetName: the station
+ targetName: the station
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Objects/Fun/figurines.yml b/Resources/Prototypes/Entities/Objects/Fun/figurines.yml
index 243d8eaea3..5f23dc4ff7 100644
--- a/Resources/Prototypes/Entities/Objects/Fun/figurines.yml
+++ b/Resources/Prototypes/Entities/Objects/Fun/figurines.yml
@@ -17,6 +17,8 @@
- type: Tag
tags:
- Figurine
+ - type: StealTarget
+ stealGroup: Figurines
- type: entity
parent: BaseFigurine
diff --git a/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml b/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml
index 2945c4f68e..3b9b51593e 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml
@@ -61,6 +61,8 @@
state: sheetcaptain
- type: Clothing
sprite: Clothing/Neck/Bedsheets/captain.rsi
+ - type: StealTarget
+ stealGroup: HeadBedsheet
- type: entity
id: BedsheetCE
@@ -72,6 +74,8 @@
state: sheetce
- type: Clothing
sprite: Clothing/Neck/Bedsheets/ce.rsi
+ - type: StealTarget
+ stealGroup: HeadBedsheet
- type: entity
id: BedsheetCentcom
@@ -83,6 +87,8 @@
state: sheetcentcom
- type: Clothing
sprite: Clothing/Neck/Bedsheets/centcom.rsi
+ - type: StealTarget
+ stealGroup: HeadBedsheet
- type: entity
id: BedsheetClown
@@ -105,6 +111,8 @@
state: sheetcmo
- type: Clothing
sprite: Clothing/Neck/Bedsheets/cmo.rsi
+ - type: StealTarget
+ stealGroup: HeadBedsheet
- type: entity
id: BedsheetCosmos
@@ -158,6 +166,8 @@
state: sheethop
- type: Clothing
sprite: Clothing/Neck/Bedsheets/hop.rsi
+ - type: StealTarget
+ stealGroup: HeadBedsheet
- type: entity
id: BedsheetHOS
@@ -169,6 +179,8 @@
state: sheethos
- type: Clothing
sprite: Clothing/Neck/Bedsheets/hos.rsi
+ - type: StealTarget
+ stealGroup: HeadBedsheet
- type: entity
id: BedsheetIan
@@ -242,6 +254,8 @@
state: sheetqm
- type: Clothing
sprite: Clothing/Neck/Bedsheets/qm.rsi
+ - type: StealTarget
+ stealGroup: HeadBedsheet
- type: entity
id: BedsheetRainbow
@@ -263,6 +277,8 @@
state: sheetrd
- type: Clothing
sprite: Clothing/Neck/Bedsheets/rd.rsi
+ - type: StealTarget
+ stealGroup: HeadBedsheet
- type: entity
id: BedsheetBrigmedic
diff --git a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml
index ec0b64ade2..e389bc6b37 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml
@@ -20,6 +20,8 @@
- type: Tag
tags:
- HighRiskItem
+ - type: StealTarget
+ stealGroup: NukeDisk
- type: entity
name: nuclear authentication disk
diff --git a/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml b/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml
index 1b925b5cb0..83701249d0 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml
@@ -49,6 +49,8 @@
- type: Appearance
- type: Physics
canCollide: false
+ - type: StealTarget
+ stealGroup: LAMP
- type: entity
name: lamp
diff --git a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml
index 69c0099825..705733aa61 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml
@@ -22,6 +22,8 @@
tags:
- DoorBumpOpener
- WhitelistChameleon
+ - type: StealTarget
+ stealGroup: IDCard
#IDs with layers
@@ -115,6 +117,8 @@
- DoorBumpOpener
- WhitelistChameleon
- HighRiskItem
+ - type: StealTarget
+ stealGroup: CaptainIDCard
- type: entity
parent: IDCardStandard
diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml
index 01a642ff60..2abec49138 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml
@@ -646,6 +646,8 @@
damage:
types:
Blunt: 10
+ - type: StealTarget
+ stealGroup: BoxFolderQmClipboard
# Stamps
- type: entity
@@ -669,6 +671,8 @@
state: stamp-mime
- type: Item
size: Tiny
+ - type: StealTarget
+ stealGroup: Stamp
- type: entity
name: alternate rubber stamp
diff --git a/Resources/Prototypes/Entities/Objects/Misc/secret_documents.yml b/Resources/Prototypes/Entities/Objects/Misc/secret_documents.yml
index 4f0289da4f..ae6238d87c 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/secret_documents.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/secret_documents.yml
@@ -12,3 +12,5 @@
tags:
- Book
- HighRiskItem
+ - type: StealTarget
+ stealGroup: BookSecretDocuments
diff --git a/Resources/Prototypes/Entities/Objects/Power/antimatter_part.yml b/Resources/Prototypes/Entities/Objects/Power/antimatter_part.yml
index b447795813..a3674178bf 100644
--- a/Resources/Prototypes/Entities/Objects/Power/antimatter_part.yml
+++ b/Resources/Prototypes/Entities/Objects/Power/antimatter_part.yml
@@ -18,3 +18,5 @@
- type: Tag
tags:
- DroneUsable
+ - type: StealTarget
+ stealGroup: AmePart
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml
index 6096de5c7c..75ce118d9f 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml
@@ -46,6 +46,8 @@
- type: Tag
tags:
- Book
+ - type: StealTarget
+ stealGroup: Bible
- type: entity
parent: Bible
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml
index 8e26898daa..e87fec22ac 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml
@@ -17,6 +17,8 @@
reagents:
- ReagentId: THC
Quantity: 15
+ - type: StealTarget
+ stealGroup: Cannabis
- type: entity
name: dried cannabis leaves
@@ -36,6 +38,8 @@
- type: Sprite
sprite: Objects/Specific/Hydroponics/tobacco.rsi
state: dried
+ - type: StealTarget
+ stealGroup: Cannabis
- type: entity
name: ground cannabis
@@ -64,6 +68,8 @@
- Smokable
- type: Item
size: Tiny
+ - type: StealTarget
+ stealGroup: Cannabis
- type: entity
name: tobacco leaves
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml
index 5827e832c8..ce29f10a5b 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml
@@ -52,7 +52,9 @@
- type: Item
sprite: Objects/Tools/spy_device.rsi
- type: PowerCellDraw
- useRate: 40 #Should be weaker than the original
+ useRate: 10
+ - type: StaticPrice
+ price: 750
- type: entity
id: SpyCrewMonitorEmpty
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml
index b9a6b08052..3d28487d68 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml
@@ -26,6 +26,8 @@
- type: Tag
tags:
- HighRiskItem
+ - type: StealTarget
+ stealGroup: Hypospray
- type: entity
name: gorlex hypospray
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Research/disk.yml b/Resources/Prototypes/Entities/Objects/Specific/Research/disk.yml
index 2b9d76b1b3..0cb605cee6 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Research/disk.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Research/disk.yml
@@ -59,6 +59,8 @@
- type: TechnologyDisk
- type: StaticPrice
price: 100
+ - type: StealTarget
+ stealGroup: TechnologyDisk
- type: entity
parent: TechnologyDisk
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_artifacts.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_artifacts.yml
index eb612a8bc0..ed4afd061f 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_artifacts.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_artifacts.yml
@@ -58,6 +58,8 @@
- type: GuideHelp
guides:
- Xenoarchaeology
+ - type: StealTarget
+ stealGroup: XenoArtifact
- type: entity
parent: BaseXenoArtifact
diff --git a/Resources/Prototypes/Entities/Objects/Tools/flashlights.yml b/Resources/Prototypes/Entities/Objects/Tools/flashlights.yml
index c43ffc830c..8e880c0bf5 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/flashlights.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/flashlights.yml
@@ -66,6 +66,8 @@
- type: Appearance
- type: StaticPrice
price: 40
+ - type: StealTarget
+ stealGroup: LAMP
- type: entity
name: seclite
diff --git a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml
index 15a16d99f6..f40f47115b 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml
@@ -158,6 +158,8 @@
- type: Tag
tags:
- HighRiskItem
+ - type: StealTarget
+ stealGroup: JetpackCaptainFilled
# Filled captain
- type: entity
diff --git a/Resources/Prototypes/Entities/Objects/Tools/lantern.yml b/Resources/Prototypes/Entities/Objects/Tools/lantern.yml
index 4d861ffd54..f4d6ea8364 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/lantern.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/lantern.yml
@@ -53,6 +53,8 @@
- type: ContainerContainer
containers:
cell_slot: !type:ContainerSlot {}
+ - type: StealTarget
+ stealGroup: LAMP
- type: entity
parent: Lantern
diff --git a/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml b/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml
index 30bcdf3739..2627bbeeda 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml
@@ -135,3 +135,30 @@
state: icon
- type: Item
sprite: Objects/Tools/Toolboxes/toolbox_gold.rsi
+
+- type: entity
+ id: ToolboxThief
+ name: thief undetermined toolbox
+ description: This is where your favorite thief's supplies lie. Try to remember which ones.
+ parent: BaseItem
+ components:
+ - type: Sprite
+ sprite: Objects/Tools/Toolboxes/toolbox_thief.rsi
+ state: icon
+ - type: ThiefUndeterminedBackpack
+ transformAfterSelect: AlwaysPoweredWallLight
+ possibleSets:
+ # - TO DO Thief pinpointer needed
+ - ChemistrySet
+ - ToolsSet
+ - ChameleonSet # - TO DO Chameleon stump PR needed
+ - SyndieSet
+ - SleeperSet
+ - CommunicatorSet
+ - SmugglerSet
+ - type: ActivatableUI
+ key: enum.ThiefBackpackUIKey.Key
+ - type: UserInterface
+ interfaces:
+ - key: enum.ThiefBackpackUIKey.Key
+ type: ThiefBackpackBoundUserInterface
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml b/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml
index 4f245c3f09..ccb5d36a0a 100644
--- a/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml
+++ b/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml
@@ -215,6 +215,8 @@
path: /Audio/Effects/Vehicle/vehiclestartup.ogg
params:
volume: -3
+ - type: StealTarget
+ stealGroup: VehicleSecway
- type: entity
parent: BaseVehicleRideable
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
index b4d3ce5b91..3c4dc98543 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
@@ -472,6 +472,8 @@
- Sidearm
- type: StaticPrice
price: 750
+ - type: StealTarget
+ stealGroup: WeaponAntiqueLaser
- type: entity
name: advanced laser pistol
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml
index 1a96d7d17b..b98cf7d1e4 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml
@@ -42,6 +42,8 @@
- type: Prying
- type: UseDelay
delay: 1
+ - type: StealTarget
+ stealGroup: FireAxe
- type: IgniteOnMeleeHit
fireStacks: -4
diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml b/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml
index f64bc4ce01..15e40f79c3 100644
--- a/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml
+++ b/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml
@@ -22,3 +22,5 @@
- type: GuideHelp
guides:
- Bartender
+ - type: StealTarget
+ stealGroup: BoozeDispenser
diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml
index fd39cf2a5e..916b2b748c 100644
--- a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml
+++ b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml
@@ -35,3 +35,5 @@
guides:
- Chemicals
- Chemist
+ - type: StealTarget
+ stealGroup: ChemDispenser
diff --git a/Resources/Prototypes/Entities/Structures/Furniture/altar.yml b/Resources/Prototypes/Entities/Structures/Furniture/altar.yml
index e51d31f571..d34030eb97 100644
--- a/Resources/Prototypes/Entities/Structures/Furniture/altar.yml
+++ b/Resources/Prototypes/Entities/Structures/Furniture/altar.yml
@@ -64,6 +64,8 @@
max: 3
- !type:DoActsBehavior
acts: [ "Destruction" ]
+ - type: StealTarget
+ stealGroup: AltarNanotrasen
- type: entity
id: AltarChaos
diff --git a/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml b/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml
index 72a445a8a4..0c0aa495dc 100644
--- a/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml
+++ b/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml
@@ -234,6 +234,8 @@
components:
- type: Sprite
state: plant-25
+ - type: StealTarget
+ stealGroup: PlantRD
- type: entity
id: PottedPlant26
diff --git a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml
index 89e1e695eb..8cec88d7e1 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml
@@ -105,3 +105,5 @@
- type: FaxMachine
name: "Captain's Office"
receiveNukeCodes: true
+ - type: StealTarget
+ stealGroup: FaxMachineCaptain
diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml
index 83fe7d206e..934c446eaf 100644
--- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml
+++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml
@@ -298,6 +298,8 @@
board: ThermomachineFreezerMachineCircuitBoard
- type: DeviceNetwork
prefix: device-address-prefix-freezer
+ - type: StealTarget
+ stealGroup: FreezerHeater
- type: entity
parent: GasThermoMachineFreezer
@@ -341,6 +343,8 @@
board: ThermomachineHeaterMachineCircuitBoard
- type: DeviceNetwork
prefix: device-address-prefix-heater
+ - type: StealTarget
+ stealGroup: FreezerHeater
- type: entity
parent: GasThermoMachineHeater
diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/teg.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/teg.yml
index af482b2dbb..9a378c26a4 100644
--- a/Resources/Prototypes/Entities/Structures/Power/Generation/teg.yml
+++ b/Resources/Prototypes/Entities/Structures/Power/Generation/teg.yml
@@ -98,6 +98,8 @@
path: /Audio/Ambience/Objects/vending_machine_hum.ogg
- type: GuideHelp
guides: [ TEG, Power ]
+ - type: StealTarget
+ stealGroup: Teg
- type: entity
id: TegCirculator
@@ -175,6 +177,8 @@
- type: AtmosUnsafeUnanchor
- type: TegCirculator
+ - type: StealTarget
+ stealGroup: Teg
- # Spawned by the client-side circulator examine code to indicate the inlet/outlet direction.
type: entity
diff --git a/Resources/Prototypes/GameRules/midround.yml b/Resources/Prototypes/GameRules/midround.yml
index d7dff95b51..241ee931bb 100644
--- a/Resources/Prototypes/GameRules/midround.yml
+++ b/Resources/Prototypes/GameRules/midround.yml
@@ -27,3 +27,11 @@
objectives:
- CarpRiftsObjective
- DragonSurviveObjective
+
+# need for admin panel antag create (because the rule doesn't have a roundstart entity like TraitorRule)
+- type: entity
+ id: Thief
+ parent: BaseGameRule
+ noSpawn: true
+ components:
+ - type: ThiefRule
\ No newline at end of file
diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml
index a0fc66bb81..066bf9b626 100644
--- a/Resources/Prototypes/GameRules/roundstart.yml
+++ b/Resources/Prototypes/GameRules/roundstart.yml
@@ -74,6 +74,8 @@
noSpawn: true
components:
- type: TraitorRule
+ - type: ThiefRule #the thieves come as an extension of another gamemode
+ ruleChance: 0.5
- type: entity
id: Revolutionary
@@ -81,6 +83,8 @@
noSpawn: true
components:
- type: RevolutionaryRule
+ - type: ThiefRule #the thieves come as an extension of another gamemode
+ ruleChance: 0.5
- type: entity
id: Sandbox
diff --git a/Resources/Prototypes/Objectives/base_objectives.yml b/Resources/Prototypes/Objectives/base_objectives.yml
index b4ce16a6f9..e24b26e6e8 100644
--- a/Resources/Prototypes/Objectives/base_objectives.yml
+++ b/Resources/Prototypes/Objectives/base_objectives.yml
@@ -91,6 +91,10 @@
id: BaseStealObjective
components:
- type: StealCondition
+ objectiveNoOwnerText: objective-condition-steal-title-no-owner
+ objectiveText: objective-condition-steal-title
+ descriptionText: objective-condition-steal-description
+ descriptionMultiplyText: objective-condition-thief-multiply-description
# requires that the player not die, ignores being on emergency shuttle or cuffed
- type: entity
diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml
index 7d6c9a48a3..95b1fb8593 100644
--- a/Resources/Prototypes/Objectives/objectiveGroups.yml
+++ b/Resources/Prototypes/Objectives/objectiveGroups.yml
@@ -41,4 +41,89 @@
RandomTraitorAliveObjective: 1
RandomTraitorProgressObjective: 1
+#Thief groups
+- type: weightedRandom
+ id: ThiefObjectiveGroups
+ weights:
+ ThiefObjectiveGroupCollection: 1
+ ThiefObjectiveGroupItem: 1
+
+- type: weightedRandom
+ id: ThiefBigObjectiveGroups
+ weights:
+ ThiefObjectiveGroupStructure: 1
+ ThiefObjectiveGroupAnimal: 2
+
+- type: weightedRandom
+ id: ThiefEscapeObjectiveGroups
+ weights:
+ ThiefObjectiveGroupEscape: 1
+
+
+
+- type: weightedRandom
+ id: ThiefObjectiveGroupCollection
+ weights:
+ HeadCloakStealCollectionObjective: 1 #command
+ HeadBedsheetStealCollectionObjective: 1
+ StampStealCollectionObjective: 1
+ DoorRemoteStealCollectionObjective: 1
+ TechnologyDiskStealCollectionObjective: 1 #rnd
+ FigurineStealCollectionObjective: 0.3 #service
+ IDCardsStealCollectionObjective: 1
+ EncryptionKeyStealCollectionObjective: 1
+ CannabisStealCollectionObjective: 1
+ LAMPStealCollectionObjective: 2 #only for moth
+
+- type: weightedRandom
+ id: ThiefObjectiveGroupItem
+ weights:
+ ForensicScannerStealObjective: 1 #sec
+ AmmoTechFabCircuitboardStealObjective: 1
+ ClothingHeadHatWardenStealObjective: 1
+ ClothingOuterHardsuitVoidParamedStealObjective: 1 #med
+ MedicalTechFabCircuitboardStealObjective: 1
+ ClothingHeadsetAltMedicalStealObjective: 1
+ FireAxeStealObjective: 1 #eng
+ AmePartStealObjective: 1
+ ExpeditionsCircuitboardStealObjective: 1 #sup
+ CargoShuttleCircuitboardStealObjective: 1
+ SalvageShuttleCircuitboardStealObjective: 1
+ ClothingEyesHudBeerStealObjective: 1 #srv
+ BibleStealObjective: 1
+ ClothingNeckGoldmedalStealObjective: 1 #other
+ ClothingNeckClownmedalStealObjective: 0.5
+
+- type: weightedRandom
+ id: ThiefObjectiveGroupStructure
+ weights:
+ NuclearBombStealObjective: 0.5
+ FaxMachineCaptainStealObjective: 1
+ VehicleSecwayStealObjective: 1
+ ChemDispenserStealObjective: 1
+ XenoArtifactStealObjective: 1
+ FreezerHeaterStealObjective: 1
+ TegStealObjective: 1
+ BoozeDispenserStealObjective: 1
+ AltarNanotrasenStealObjective: 1
+ PlantRDStealObjective: 1
+
+- type: weightedRandom
+ id: ThiefObjectiveGroupAnimal
+ weights:
+ IanStealObjective: 1
+ BingusStealObjective: 1
+ McGriffStealObjective: 1
+ WalterStealObjective: 1
+ MortyStealObjective: 1
+ RenaultStealObjective: 1
+ HamletStealObjective: 1
+ ShivaStealObjective: 1
+ SmileStealObjective: 1
+ PunPunStealObjective: 1
+
+- type: weightedRandom
+ id: ThiefObjectiveGroupEscape
+ weights:
+ EscapeThiefShuttleObjective: 1
#Changeling, crew, wizard, when you code it...
diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml
new file mode 100644
index 0000000000..712b773eb4
--- /dev/null
+++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml
@@ -0,0 +1,408 @@
+# Traitor single items
+
+- type: stealTargetGroup
+ id: Hypospray
+ name: hypospray
+ sprite:
+ sprite: Objects/Specific/Medical/hypospray.rsi
+ state: hypo
+
+- type: stealTargetGroup
+ id: ClothingOuterHardsuitRd
+ name: experimental research hardsuit
+ sprite:
+ sprite: Clothing/OuterClothing/Hardsuits/rd.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: HandTeleporter
+ name: hand teleporter
+ sprite:
+ sprite: Objects/Devices/hand_teleporter.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: BookSecretDocuments
+ name: "emergency security orders"
+ sprite:
+ sprite: Objects/Misc/bureaucracy.rsi
+ state: folder-sec-doc
+
+- type: stealTargetGroup
+ id: ClothingShoesBootsMagAdv
+ name: advanced magboots
+ sprite:
+ sprite: Clothing/Shoes/Boots/magboots-advanced.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: BoxFolderQmClipboard
+ name: requisition digi-board
+ sprite:
+ sprite: Objects/Misc/qm_clipboard.rsi
+ state: qm_clipboard
+
+- type: stealTargetGroup
+ id: FoodMeatCorgi
+ name: prime-cut corgi meat
+ sprite:
+ sprite: Objects/Consumable/Food/meat.rsi
+ state: corgi
+ #
+- type: stealTargetGroup
+ id: CaptainIDCard
+ name: captain ID card
+ sprite:
+ sprite: Objects/Misc/id_cards.rsi
+ state: ert_commander #no one will know the difference.
+
+- type: stealTargetGroup
+ id: JetpackCaptainFilled
+ name: captain's jetpack
+ sprite:
+ sprite: Objects/Tanks/Jetpacks/captain.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: WeaponAntiqueLaser
+ name: antique laser pistol
+ sprite:
+ sprite: Objects/Weapons/Guns/Battery/antiquelasergun.rsi
+ state: base
+
+- type: stealTargetGroup
+ id: NukeDisk
+ name: nuclear authentication disk
+ sprite:
+ sprite: Objects/Misc/nukedisk.rsi
+ state: icon
+
+# Thief Collection
+
+- type: stealTargetGroup
+ id: Figurines
+ name: figurines (any)
+ sprite:
+ sprite: Objects/Fun/figurines.rsi
+ state: figurine_spawner
+
+- type: stealTargetGroup
+ id: HeadCloak
+ name: head's cloaks (any)
+ sprite:
+ sprite: Clothing/Neck/Cloaks/cap.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: HeadBedsheet
+ name: head's bedsheets (any)
+ sprite:
+ sprite: Objects/Misc/bedsheets.rsi
+ state: sheetNT
+
+- type: stealTargetGroup
+ id: Stamp
+ name: stamps (any)
+ sprite:
+ sprite: Objects/Misc/bureaucracy.rsi
+ state: stamp-cap
+
+- type: stealTargetGroup
+ id: DoorRemote
+ name: door remotes (any)
+ sprite:
+ sprite: Objects/Devices/door_remote.rsi
+ state: door_remotebase
+
+- type: stealTargetGroup
+ id: EncryptionKey
+ name: encryption keys (any)
+ sprite:
+ sprite: Objects/Devices/encryption_keys.rsi
+ state: crypt_gray
+
+- type: stealTargetGroup
+ id: TechnologyDisk
+ name: technology disks
+ sprite:
+ sprite: Objects/Misc/module.rsi
+ state: datadisk_base
+
+- type: stealTargetGroup
+ id: IDCard
+ name: ID Cards (any)
+ sprite:
+ sprite: Objects/Misc/id_cards.rsi
+ state: default
+
+- type: stealTargetGroup
+ id: Cannabis
+ name: cannabis
+ sprite:
+ sprite: Objects/Specific/Hydroponics/cannabis.rsi
+ state: produce
+
+- type: stealTargetGroup
+ id: LAMP
+ name: LAMPS
+ sprite:
+ sprite: Objects/Tools/lantern.rsi
+ state: lantern
+
+# Thief single item
+
+- type: stealTargetGroup
+ id: ForensicScanner
+ name: forensic scanner
+ sprite:
+ sprite: Objects/Devices/forensic_scanner.rsi
+ state: forensicnew
+
+- type: stealTargetGroup
+ id: AmmoTechFabCircuitboard
+ name: ammo techfab circuit board
+ sprite:
+ sprite: Objects/Misc/module.rsi
+ state: security
+
+- type: stealTargetGroup
+ id: ClothingHeadHatWarden
+ name: warden's cap
+ sprite:
+ sprite: Clothing/Head/Hats/warden.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: ClothingOuterHardsuitVoidParamed
+ name: paramedic Void Suit
+ sprite:
+ sprite: Clothing/OuterClothing/Hardsuits/paramed.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: MedicalTechFabCircuitboard
+ name: medical techfab machine board
+ sprite:
+ sprite: Objects/Misc/module.rsi
+ state: medical
+
+- type: stealTargetGroup
+ id: ClothingHeadsetAltMedical
+ name: chief medical officer's over-ear headset
+ sprite:
+ sprite: Clothing/Ears/Headsets/medical.rsi
+ state: icon_alt
+
+- type: stealTargetGroup
+ id: ResearchAndDevelopmentServerMachineCircuitboard
+ name: R&D server machine board
+ sprite:
+ sprite: Objects/Misc/module.rsi
+ state: science
+
+- type: stealTargetGroup
+ id: FireAxe
+ name: fireaxe
+ sprite:
+ sprite: Objects/Weapons/Melee/fireaxe.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: AmePart
+ name: AME part
+ sprite:
+ sprite: Objects/Power/AME/ame_part.rsi
+ state: box
+
+- type: stealTargetGroup
+ id: SalvageExpeditionsComputerCircuitboard
+ name: salvage expeditions computer board
+ sprite:
+ sprite: Objects/Misc/module.rsi
+ state: cpu_supply
+
+- type: stealTargetGroup
+ id: CargoShuttleConsoleCircuitboard
+ name: cargo shuttle console board
+ sprite:
+ sprite: Objects/Misc/module.rsi
+ state: cpuboard
+
+- type: stealTargetGroup
+ id: SalvageShuttleConsoleCircuitboard
+ name: salvage shuttle console board
+ sprite:
+ sprite: Objects/Misc/module.rsi
+ state: cpuboard
+
+- type: stealTargetGroup
+ id: ClothingEyesHudBeer
+ name: beer goggles
+ sprite:
+ sprite: Clothing/Eyes/Hud/beergoggles.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: Bible
+ name: bible
+ sprite:
+ sprite: Objects/Specific/Chapel/bible.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: ClothingNeckGoldmedal
+ name: gold medal of crewmanship
+ sprite:
+ sprite: Clothing/Neck/Medals/gold.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: ClothingNeckClownmedal
+ name: clown medal
+ sprite:
+ sprite: Clothing/Neck/Medals/clownmedal.rsi
+ state: icon
+
+#Thief structures
+
+- type: stealTargetGroup
+ id: NuclearBomb
+ name: nuclear fission explosive
+ sprite:
+ sprite: Objects/Devices/nuke.rsi
+ state: nuclearbomb_base
+
+- type: stealTargetGroup
+ id: FaxMachineCaptain
+ name: captain long range fax machine
+ sprite:
+ sprite: Structures/Machines/fax_machine.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: VehicleSecway
+ name: secway
+ sprite:
+ sprite: Objects/Vehicles/secway.rsi
+ state: icon
+
+- type: stealTargetGroup
+ id: ChemDispenser
+ name: chemical dispenser
+ sprite:
+ sprite: Structures/dispensers.rsi
+ state: industrial-working
+
+- type: stealTargetGroup
+ id: XenoArtifact
+ name: big alien artifact
+ sprite:
+ sprite: Objects/Specific/Xenoarchaeology/xeno_artifacts.rsi
+ state: ano28
+
+- type: stealTargetGroup
+ id: FreezerHeater
+ name: freezer or heater
+ sprite:
+ sprite: Structures/Piping/Atmospherics/thermomachine.rsi
+ state: heaterOff
+
+- type: stealTargetGroup
+ id: Teg
+ name: teg generator part
+ sprite:
+ sprite: Structures/Power/Generation/teg.rsi
+ state: teg
+
+- type: stealTargetGroup
+ id: BoozeDispenser
+ name: booze dispenser
+ sprite:
+ sprite: Structures/smalldispensers.rsi
+ state: booze
+
+- type: stealTargetGroup
+ id: AltarNanotrasen
+ name: nanotrasen altar (any)
+ sprite:
+ sprite: Structures/Furniture/Altars/Gods/nanotrasen.rsi
+ state: nanotrasen
+
+- type: stealTargetGroup
+ id: PlantRD
+ name: RD's potted plant
+ sprite:
+ sprite: Structures/Furniture/potted_plants.rsi
+ state: plant-25
+
+# Thief Animal
+
+- type: stealTargetGroup
+ id: AnimalIan
+ name: Ian
+ sprite:
+ sprite: Mobs/Pets/corgi.rsi
+ state: ian
+
+- type: stealTargetGroup
+ id: AnimalBingus
+ name: Bingus
+ sprite:
+ sprite: Mobs/Pets/bingus.rsi
+ state: bingus
+
+- type: stealTargetGroup
+ id: AnimalMcGriff
+ name: McGriff
+ sprite:
+ sprite: Mobs/Pets/mcgriff.rsi
+ state: mcgriff
+
+- type: stealTargetGroup
+ id: AnimalWalter
+ name: Walter
+ sprite:
+ sprite: Mobs/Pets/walter.rsi
+ state: walter
+
+- type: stealTargetGroup
+ id: AnimalMorty
+ name: Morty
+ sprite:
+ sprite: Mobs/Animals/possum.rsi
+ state: possum
+
+- type: stealTargetGroup
+ id: AnimalRenault
+ name: Renault
+ sprite:
+ sprite: Mobs/Animals/fox.rsi
+ state: fox
+
+- type: stealTargetGroup
+ id: AnimalHamlet
+ name: Hamlet
+ sprite:
+ sprite: Mobs/Pets/hamlet.rsi
+ state: hamster-0
+
+- type: stealTargetGroup
+ id: AnimalShiva
+ name: Shiva
+ sprite:
+ sprite: Mobs/Pets/shiva.rsi
+ state: shiva
+
+- type: stealTargetGroup
+ id: AnimalSmile
+ name: Smile
+ sprite:
+ sprite: Mobs/Aliens/slimes.rsi
+ state: rainbow_baby_slime
+
+- type: stealTargetGroup
+ id: AnimalPunPun
+ name: Pun Pun
+ sprite:
+ sprite: Mobs/Animals/monkey.rsi
+ state: monkey
\ No newline at end of file
diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml
new file mode 100644
index 0000000000..3201a9957e
--- /dev/null
+++ b/Resources/Prototypes/Objectives/thief.yml
@@ -0,0 +1,620 @@
+- type: entity
+ abstract: true
+ parent: BaseObjective
+ id: BaseThiefObjective
+ components:
+ - type: Objective
+ issuer: thief
+ - type: RoleRequirement
+ roles:
+ components:
+ - ThiefRole
+
+- type: entity
+ abstract: true
+ parent: [BaseThiefObjective, BaseStealObjective]
+ id: BaseThiefStealObjective
+ components:
+ - type: StealCondition
+ verifyMapExistance: false
+ descriptionText: objective-condition-thief-description
+
+- type: entity
+ abstract: true
+ parent: [BaseThiefObjective, BaseStealObjective]
+ id: BaseThiefStealCollectionObjective
+ components:
+ - type: StealCondition
+ verifyMapExistance: true
+ descriptionText: objective-condition-thief-description
+
+- type: entity
+ abstract: true
+ parent: [BaseThiefObjective, BaseStealObjective]
+ id: BaseThiefStealStructureObjective
+ components:
+ - type: StealCondition
+ verifyMapExistance: true
+ descriptionText: objective-condition-thief-description
+ - type: Objective
+ difficulty: 2 # it's hard to hide
+
+- type: entity
+ abstract: true
+ parent: [BaseThiefObjective, BaseStealObjective]
+ id: BaseThiefStealAnimalObjective
+ components:
+ - type: StealCondition
+ verifyMapExistance: false
+ checkAlive: true
+ objectiveNoOwnerText: objective-condition-steal-title-alive-no-owner
+ descriptionText: objective-condition-thief-animal-description
+ - type: Objective
+ difficulty: 2 # it's hard to hide
+
+# Collections
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: FigurineStealCollectionObjective
+ components:
+ - type: StealCondition
+ stealGroup: Figurines
+ minCollectionSize: 10
+ maxCollectionSize: 50 #will be limited to the number of figures on the station anyway.
+ - type: Objective
+ difficulty: 0.25
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: HeadCloakStealCollectionObjective
+ components:
+ - type: StealCondition
+ stealGroup: HeadCloak
+ minCollectionSize: 3
+ maxCollectionSize: 6
+ - type: Objective
+ difficulty: 1.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: HeadBedsheetStealCollectionObjective
+ components:
+ - type: StealCondition
+ stealGroup: HeadBedsheet
+ minCollectionSize: 3
+ maxCollectionSize: 6
+ - type: Objective
+ difficulty: 1.0
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: StampStealCollectionObjective
+ components:
+ - type: StealCondition
+ stealGroup: Stamp
+ minCollectionSize: 5
+ maxCollectionSize: 15
+ - type: Objective
+ difficulty: 1.0
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: DoorRemoteStealCollectionObjective
+ components:
+ - type: StealCondition
+ stealGroup: DoorRemote
+ minCollectionSize: 2
+ maxCollectionSize: 5
+ - type: Objective
+ difficulty: 1.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: TechnologyDiskStealCollectionObjective
+ components:
+ - type: NotJobRequirement
+ job: Scientist
+ - type: StealCondition
+ stealGroup: TechnologyDisk
+ minCollectionSize: 10
+ maxCollectionSize: 20
+ verifyMapExistance: false
+ - type: Objective
+ difficulty: 0.8
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: IDCardsStealCollectionObjective
+ components:
+ - type: StealCondition
+ stealGroup: IDCard
+ minCollectionSize: 10
+ maxCollectionSize: 20
+ verifyMapExistance: false
+ - type: Objective
+ difficulty: 0.7
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: EncryptionKeyStealCollectionObjective
+ components:
+ - type: StealCondition
+ stealGroup: EncryptionKey
+ minCollectionSize: 5
+ maxCollectionSize: 25
+ - type: Objective
+ difficulty: 0.7
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: CannabisStealCollectionObjective
+ components:
+ - type: NotJobRequirement
+ job: Botanist
+ - type: StealCondition
+ stealGroup: Cannabis
+ minCollectionSize: 20
+ maxCollectionSize: 30
+ verifyMapExistance: false
+ - type: Objective
+ difficulty: 0.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealCollectionObjective
+ id: LAMPStealCollectionObjective
+ components:
+ - type: SpeciesRequirement
+ allowedSpecies:
+ - Moth
+ - type: StealCondition
+ stealGroup: LAMP
+ minCollectionSize: 1
+ maxCollectionSize: 30
+ verifyMapExistance: true
+ - type: Objective
+ difficulty: 0.5 # just for fun, collectings LAMP on Moth
+
+# steal item
+
+- type: entity #Security subgroup
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: ForensicScannerStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Detective
+ - type: StealCondition
+ stealGroup: ForensicScanner
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: AmmoTechFabCircuitboardStealObjective
+ components:
+ - type: StealCondition
+ stealGroup: AmmoTechFabCircuitboard
+ - type: Objective
+ difficulty: 1.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: ClothingHeadHatWardenStealObjective
+ components:
+ - type: StealCondition
+ stealGroup: ClothingHeadHatWarden
+ - type: Objective
+ difficulty: 1.2
+
+- type: entity #Medical subgroup
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: ClothingOuterHardsuitVoidParamedStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Paramedic
+ - type: StealCondition
+ stealGroup: ClothingOuterHardsuitVoidParamed
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: MedicalTechFabCircuitboardStealObjective
+ components:
+ - type: NotJobRequirement
+ job: MedicalDoctor
+ - type: StealCondition
+ stealGroup: MedicalTechFabCircuitboard
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: ClothingHeadsetAltMedicalStealObjective
+ components:
+ - type: NotJobRequirement
+ job: ChiefMedicalOfficer
+ - type: StealCondition
+ stealGroup: ClothingHeadsetAltMedical
+ - type: Objective
+ difficulty: 1
+
+- type: entity #Engineering subgroup
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: FireAxeStealObjective
+ components:
+ - type: NotJobRequirement
+ job: AtmosphericTechnician
+ - type: StealCondition
+ stealGroup: FireAxe
+ - type: Objective
+ difficulty: 0.8
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: AmePartStealObjective
+ components:
+ - type: NotJobRequirement
+ job: StationEngineer
+ - type: StealCondition
+ stealGroup: AmePart
+ - type: Objective
+ difficulty: 1
+
+- type: entity #Cargo subgroup
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: ExpeditionsCircuitboardStealObjective
+ components:
+ - type: NotJobRequirement
+ job: SalvageSpecialist
+ - type: StealCondition
+ stealGroup: SalvageExpeditionsComputerCircuitboard
+ - type: Objective
+ difficulty: 0.7
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: CargoShuttleCircuitboardStealObjective
+ components:
+ - type: NotJobRequirement
+ job: CargoTechnician
+ - type: StealCondition
+ stealGroup: CargoShuttleConsoleCircuitboard
+ - type: Objective
+ difficulty: 0.7
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: SalvageShuttleCircuitboardStealObjective
+ components:
+ - type: NotJobRequirement
+ job: SalvageSpecialist
+ - type: StealCondition
+ stealGroup: SalvageShuttleConsoleCircuitboard
+ - type: Objective
+ difficulty: 0.7
+
+- type: entity #Service subgroup
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: ClothingEyesHudBeerStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Bartender
+ - type: StealCondition
+ stealGroup: ClothingEyesHudBeer
+ - type: Objective
+ difficulty: 0.3
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: BibleStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Chaplain
+ - type: StealCondition
+ stealGroup: Bible
+ - type: Objective
+ difficulty: 0.4
+
+- type: entity #Other subgroup
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: ClothingNeckGoldmedalStealObjective
+ components:
+ - type: NotJobRequirement
+ job: HeadOfPersonnel
+ - type: StealCondition
+ stealGroup: ClothingNeckGoldmedal
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealObjective
+ id: ClothingNeckClownmedalStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Captain
+ - type: StealCondition
+ stealGroup: ClothingNeckClownmedal
+ - type: Objective
+ difficulty: 1
+
+# Structures
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: NuclearBombStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Captain
+ - type: StealCondition
+ stealGroup: NuclearBomb
+ - type: Objective
+ difficulty: 2.5 #Good luck
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: FaxMachineCaptainStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Captain
+ - type: StealCondition
+ stealGroup: FaxMachineCaptain
+ - type: Objective
+ difficulty: 2
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: VehicleSecwayStealObjective
+ components:
+ - type: NotJobRequirement
+ job: SecurityOfficer
+ - type: StealCondition
+ stealGroup: VehicleSecway
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: ChemDispenserStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Chemist
+ - type: StealCondition
+ stealGroup: ChemDispenser
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: XenoArtifactStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Scientist
+ - type: StealCondition
+ stealGroup: XenoArtifact
+ - type: Objective
+ difficulty: 0.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: FreezerHeaterStealObjective
+ components:
+ - type: NotJobRequirement
+ job: AtmosphericTechnician
+ - type: StealCondition
+ stealGroup: FreezerHeater
+ - type: Objective
+ difficulty: 0.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: TegStealObjective
+ components:
+ - type: NotJobRequirement
+ job: AtmosphericTechnician
+ - type: StealCondition
+ stealGroup: Teg
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: BoozeDispenserStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Bartender
+ - type: StealCondition
+ stealGroup: BoozeDispenser
+ - type: Objective
+ difficulty: 0.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: AltarNanotrasenStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Chaplain
+ - type: StealCondition
+ stealGroup: AltarNanotrasen
+ - type: Objective
+ difficulty: 0.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealStructureObjective
+ id: PlantRDStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Scientist
+ - type: StealCondition
+ stealGroup: PlantRD
+ - type: Objective
+ difficulty: 0.8
+
+# Animal
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: IanStealObjective
+ components:
+ - type: NotJobRequirement
+ job: HeadOfPersonnel
+ - type: StealCondition
+ stealGroup: AnimalIan
+ - type: Objective
+ difficulty: 2.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: BingusStealObjective
+ components:
+ - type: StealCondition
+ stealGroup: AnimalBingus
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: McGriffStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Detective
+ - type: StealCondition
+ stealGroup: AnimalMcGriff
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: WalterStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Chemist
+ - type: StealCondition
+ stealGroup: AnimalWalter
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: MortyStealObjective
+ components:
+ - type: StealCondition
+ stealGroup: AnimalMorty
+ - type: Objective
+ difficulty: 0.5
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: RenaultStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Captain
+ - type: StealCondition
+ stealGroup: AnimalRenault
+ - type: Objective
+ difficulty: 2
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: HamletStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Captain
+ - type: StealCondition
+ stealGroup: AnimalHamlet
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: ShivaStealObjective
+ components:
+ - type: NotJobRequirement
+ job: SecurityOfficer
+ - type: StealCondition
+ stealGroup: AnimalShiva
+ - type: Objective
+ difficulty: 2
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: SmileStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Scientist
+ - type: StealCondition
+ stealGroup: AnimalSmile
+ - type: Objective
+ difficulty: 1
+
+- type: entity
+ noSpawn: true
+ parent: BaseThiefStealAnimalObjective
+ id: PunPunStealObjective
+ components:
+ - type: NotJobRequirement
+ job: Bartender
+ - type: StealCondition
+ stealGroup: AnimalPunPun
+ - type: Objective
+ difficulty: 2
+
+# Escape
+
+- type: entity
+ noSpawn: true
+ parent: [BaseThiefObjective, BaseLivingObjective]
+ id: EscapeThiefShuttleObjective
+ name: Escape to centcom alive and unrestrained.
+ description: You don't want your illegal activities to be discovered by anyone, do you?
+ components:
+ - type: Objective
+ difficulty: 1.3
+ icon:
+ sprite: Structures/Furniture/chairs.rsi
+ state: shuttle
+ - type: EscapeShuttleCondition
diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml
index 840564a969..4684e2d343 100644
--- a/Resources/Prototypes/Objectives/traitor.yml
+++ b/Resources/Prototypes/Objectives/traitor.yml
@@ -26,6 +26,8 @@
parent: [BaseTraitorObjective, BaseStealObjective]
id: BaseTraitorStealObjective
components:
+ - type: StealCondition
+ verifyMapExistance: false
- type: Objective
difficulty: 2.75
@@ -150,36 +152,28 @@
- type: NotJobRequirement
job: ChiefMedicalOfficer
- type: StealCondition
- prototype: Hypospray
+ stealGroup: Hypospray
owner: job-name-cmo
## rd
-- type: entity
- abstract: true
- parent: BaseTraitorStealObjective
- id: BaseRDObjective
- components:
- - type: NotJobRequirement
- job: ResearchDirector
- - type: StealCondition
- owner: job-name-rd
-
- type: entity
noSpawn: true
- parent: BaseRDObjective
+ parent: BaseTraitorStealObjective
id: RDHardsuitStealObjective
components:
- type: StealCondition
- prototype: ClothingOuterHardsuitRd
+ stealGroup: ClothingOuterHardsuitRd
+ owner: job-name-rd
- type: entity
noSpawn: true
- parent: BaseRDObjective
+ parent: BaseTraitorStealObjective
id: HandTeleporterStealObjective
components:
- type: StealCondition
- prototype: HandTeleporter
+ stealGroup: HandTeleporter
+ owner: job-name-rd
## hos
@@ -194,7 +188,7 @@
- type: NotJobRequirement
job: HeadOfSecurity
- type: StealCondition
- prototype: BookSecretDocuments
+ stealGroup: BookSecretDocuments
owner: job-name-hos
## ce
@@ -207,7 +201,7 @@
- type: NotJobRequirement
job: ChiefEngineer
- type: StealCondition
- prototype: ClothingShoesBootsMagAdv
+ stealGroup: ClothingShoesBootsMagAdv
owner: job-name-ce
## qm
@@ -220,7 +214,7 @@
- type: NotJobRequirement
job: Quartermaster
- type: StealCondition
- prototype: BoxFolderQmClipboard
+ stealGroup: BoxFolderQmClipboard
owner: job-name-qm
## hop
@@ -233,7 +227,7 @@
- type: NotJobRequirement
job: HeadOfPersonnel
- type: StealCondition
- prototype: FoodMeatCorgi
+ stealGroup: FoodMeatCorgi
owner: objective-condition-steal-Ian
## cap
@@ -255,7 +249,7 @@
id: CaptainIDStealObjective
components:
- type: StealCondition
- prototype: CaptainIDCard
+ stealGroup: CaptainIDCard
- type: entity
noSpawn: true
@@ -263,7 +257,7 @@
id: CaptainJetpackStealObjective
components:
- type: StealCondition
- prototype: JetpackCaptainFilled
+ stealGroup: JetpackCaptainFilled
- type: entity
noSpawn: true
@@ -271,7 +265,7 @@
id: CaptainGunStealObjective
components:
- type: StealCondition
- prototype: WeaponAntiqueLaser
+ stealGroup: WeaponAntiqueLaser
owner: job-name-captain
- type: entity
@@ -286,5 +280,5 @@
difficulty: 4
- type: NotCommandRequirement
- type: StealCondition
- prototype: NukeDisk
+ stealGroup: NukeDisk
owner: objective-condition-steal-station
diff --git a/Resources/Prototypes/Roles/Antags/Thief.yml b/Resources/Prototypes/Roles/Antags/Thief.yml
new file mode 100644
index 0000000000..72ea68fe1d
--- /dev/null
+++ b/Resources/Prototypes/Roles/Antags/Thief.yml
@@ -0,0 +1,6 @@
+- type: antag
+ id: Thief
+ name: roles-antag-thief-name
+ antagonist: true
+ setPreference: true
+ objective: roles-antag-space-ninja-objective
\ No newline at end of file
diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/meta.json b/Resources/Textures/Objects/Devices/pinpointer.rsi/meta.json
index d827f509cf..796fb8c2aa 100644
--- a/Resources/Textures/Objects/Devices/pinpointer.rsi/meta.json
+++ b/Resources/Textures/Objects/Devices/pinpointer.rsi/meta.json
@@ -147,6 +147,9 @@
{
"name": "pinpointer-syndicate"
},
+ {
+ "name": "pinpointer_thief"
+ },
{
"name": "pinpointer-way"
},
diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_thief.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_thief.png
new file mode 100644
index 0000000000..745d26ac49
Binary files /dev/null and b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_thief.png differ
diff --git a/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/icon.png b/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/icon.png
new file mode 100644
index 0000000000..28c3121198
Binary files /dev/null and b/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/inhand-left.png b/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/inhand-left.png
new file mode 100644
index 0000000000..bba3c79b46
Binary files /dev/null and b/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/inhand-left.png differ
diff --git a/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/inhand-right.png b/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/inhand-right.png
new file mode 100644
index 0000000000..574d59a620
Binary files /dev/null and b/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/inhand-right.png differ
diff --git a/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/meta.json b/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/meta.json
new file mode 100644
index 0000000000..068495fb27
--- /dev/null
+++ b/Resources/Textures/Objects/Tools/Toolboxes/toolbox_thief.rsi/meta.json
@@ -0,0 +1,22 @@
+{
+ "version": 1,
+ "license": "CC0-1.0",
+ "copyright": "Created by TheShuEd(github) for ss14",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "inhand-left",
+ "directions": 4
+ },
+ {
+ "name": "inhand-right",
+ "directions": 4
+ },
+ {
+ "name": "icon"
+ }
+ ]
+}
diff --git a/Resources/Textures/Objects/Vehicles/secway.rsi/icon.png b/Resources/Textures/Objects/Vehicles/secway.rsi/icon.png
new file mode 100644
index 0000000000..cae639be07
Binary files /dev/null and b/Resources/Textures/Objects/Vehicles/secway.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json b/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json
index 853fbde3d9..27d17beb56 100644
--- a/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json
+++ b/Resources/Textures/Objects/Vehicles/secway.rsi/meta.json
@@ -35,6 +35,9 @@
},
{
"name": "keys"
+ },
+ {
+ "name": "icon"
}
]
}