diff --git a/Content.Server/Cargo/Components/CargoConsoleComponent.cs b/Content.Server/Cargo/Components/CargoConsoleComponent.cs
index 69689f565a..d72e786cda 100644
--- a/Content.Server/Cargo/Components/CargoConsoleComponent.cs
+++ b/Content.Server/Cargo/Components/CargoConsoleComponent.cs
@@ -1,3 +1,4 @@
+using Content.Server.Cargo.Systems;
using Content.Server.Power.Components;
using Content.Server.UserInterface;
using Content.Shared.Cargo;
diff --git a/Content.Server/Cargo/Components/CargoOrderDatabaseComponent.cs b/Content.Server/Cargo/Components/CargoOrderDatabaseComponent.cs
index 22e6f53739..10489ec406 100644
--- a/Content.Server/Cargo/Components/CargoOrderDatabaseComponent.cs
+++ b/Content.Server/Cargo/Components/CargoOrderDatabaseComponent.cs
@@ -1,3 +1,4 @@
+using Content.Server.Cargo.Systems;
using Content.Shared.Cargo.Components;
namespace Content.Server.Cargo.Components
diff --git a/Content.Server/Cargo/Components/CargoTelepadComponent.cs b/Content.Server/Cargo/Components/CargoTelepadComponent.cs
index 8b6ccbcd1c..4c0bd6f468 100644
--- a/Content.Server/Cargo/Components/CargoTelepadComponent.cs
+++ b/Content.Server/Cargo/Components/CargoTelepadComponent.cs
@@ -1,3 +1,4 @@
+using Content.Server.Cargo.Systems;
using Content.Shared.Cargo;
using Content.Shared.Cargo.Components;
using Content.Shared.MachineLinking;
diff --git a/Content.Server/Cargo/Components/MobPriceComponent.cs b/Content.Server/Cargo/Components/MobPriceComponent.cs
new file mode 100644
index 0000000000..895ef55aa8
--- /dev/null
+++ b/Content.Server/Cargo/Components/MobPriceComponent.cs
@@ -0,0 +1,26 @@
+namespace Content.Server.Cargo.Components;
+
+///
+/// This is used for calculating the price of mobs.
+///
+[RegisterComponent]
+public sealed class MobPriceComponent : Component
+{
+ ///
+ /// How much of a penalty per part there should be. This is a multiplier for a multiplier, the penalty for each body part is calculated from the total number of slots, and then multiplied by this.
+ ///
+ [DataField("missingBodyPartPenalty")]
+ public double MissingBodyPartPenalty = 1.0f;
+
+ ///
+ /// The base price this mob should fetch.
+ ///
+ [DataField("price", required: true)]
+ public double Price;
+
+ ///
+ /// The percentage of the actual price that should be granted should the appraised mob be dead.
+ ///
+ [DataField("deathPenalty")]
+ public double DeathPenalty = 0.2f;
+}
diff --git a/Content.Server/Cargo/Components/PriceGunComponent.cs b/Content.Server/Cargo/Components/PriceGunComponent.cs
new file mode 100644
index 0000000000..ca3d1d4770
--- /dev/null
+++ b/Content.Server/Cargo/Components/PriceGunComponent.cs
@@ -0,0 +1,10 @@
+namespace Content.Server.Cargo.Components;
+
+///
+/// This is used for the price gun, which calculates the price of any object it appraises.
+///
+[RegisterComponent]
+public sealed class PriceGunComponent : Component
+{
+
+}
diff --git a/Content.Server/Cargo/Components/StackPriceComponent.cs b/Content.Server/Cargo/Components/StackPriceComponent.cs
new file mode 100644
index 0000000000..f15532273a
--- /dev/null
+++ b/Content.Server/Cargo/Components/StackPriceComponent.cs
@@ -0,0 +1,14 @@
+namespace Content.Server.Cargo.Components;
+
+///
+/// This is used for pricing stacks of items.
+///
+[RegisterComponent]
+public sealed class StackPriceComponent : Component
+{
+ ///
+ /// The price of the object this component is on, per unit.
+ ///
+ [DataField("price", required: true)]
+ public double Price;
+}
diff --git a/Content.Server/Cargo/Components/StaticPriceComponent.cs b/Content.Server/Cargo/Components/StaticPriceComponent.cs
new file mode 100644
index 0000000000..07370d4793
--- /dev/null
+++ b/Content.Server/Cargo/Components/StaticPriceComponent.cs
@@ -0,0 +1,14 @@
+namespace Content.Server.Cargo.Components;
+
+///
+/// This is used for setting a static, unchanging price for an object.
+///
+[RegisterComponent]
+public sealed class StaticPriceComponent : Component
+{
+ ///
+ /// The price of the object this component is on.
+ ///
+ [DataField("price", required: true)]
+ public double Price;
+}
diff --git a/Content.Server/Cargo/CargoSystem.Console.cs b/Content.Server/Cargo/Systems/CargoSystem.Console.cs
similarity index 99%
rename from Content.Server/Cargo/CargoSystem.Console.cs
rename to Content.Server/Cargo/Systems/CargoSystem.Console.cs
index 11188c5173..3659d5f9b8 100644
--- a/Content.Server/Cargo/CargoSystem.Console.cs
+++ b/Content.Server/Cargo/Systems/CargoSystem.Console.cs
@@ -7,7 +7,7 @@ using Content.Shared.Access.Systems;
using Content.Shared.Cargo;
using Content.Shared.GameTicking;
-namespace Content.Server.Cargo
+namespace Content.Server.Cargo.Systems
{
public sealed partial class CargoSystem
{
diff --git a/Content.Server/Cargo/CargoSystem.Telepad.cs b/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs
similarity index 99%
rename from Content.Server/Cargo/CargoSystem.Telepad.cs
rename to Content.Server/Cargo/Systems/CargoSystem.Telepad.cs
index 90173bca97..4f4f44643e 100644
--- a/Content.Server/Cargo/CargoSystem.Telepad.cs
+++ b/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs
@@ -6,7 +6,7 @@ using Content.Shared.Cargo;
using Robust.Shared.Audio;
using Robust.Shared.Player;
-namespace Content.Server.Cargo;
+namespace Content.Server.Cargo.Systems;
public sealed partial class CargoSystem
{
diff --git a/Content.Server/Cargo/CargoSystem.cs b/Content.Server/Cargo/Systems/CargoSystem.cs
similarity index 93%
rename from Content.Server/Cargo/CargoSystem.cs
rename to Content.Server/Cargo/Systems/CargoSystem.cs
index 0ce77c7d49..fa5427e887 100644
--- a/Content.Server/Cargo/CargoSystem.cs
+++ b/Content.Server/Cargo/Systems/CargoSystem.cs
@@ -2,7 +2,7 @@ using Content.Shared.Cargo;
using Content.Shared.Containers.ItemSlots;
using Robust.Shared.Prototypes;
-namespace Content.Server.Cargo;
+namespace Content.Server.Cargo.Systems;
public sealed partial class CargoSystem : SharedCargoSystem
{
diff --git a/Content.Server/Cargo/Systems/PriceGunSystem.cs b/Content.Server/Cargo/Systems/PriceGunSystem.cs
new file mode 100644
index 0000000000..569e1bb0d4
--- /dev/null
+++ b/Content.Server/Cargo/Systems/PriceGunSystem.cs
@@ -0,0 +1,37 @@
+using Content.Server.Cargo.Components;
+using Content.Server.Popups;
+using Content.Shared.Interaction;
+using Content.Shared.Timing;
+using Robust.Shared.Player;
+
+namespace Content.Server.Cargo.Systems;
+
+///
+/// This handles...
+///
+public sealed class PriceGunSystem : EntitySystem
+{
+ [Dependency] private readonly UseDelaySystem _useDelay = default!;
+ [Dependency] private readonly PricingSystem _pricingSystem = default!;
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnAfterInteract);
+ }
+
+ private void OnAfterInteract(EntityUid uid, PriceGunComponent component, AfterInteractEvent args)
+ {
+ if (!args.CanReach || args.Target == null)
+ return;
+
+ if (TryComp(args.Used, out UseDelayComponent? useDelay) && useDelay.ActiveDelay)
+ return;
+
+ var price = _pricingSystem.GetPrice(args.Target.Value);
+
+ _popupSystem.PopupEntity(Loc.GetString("price-gun-pricing-result", ("object", args.Target.Value), ("price", $"{price:F2}")), args.User, Filter.Entities(args.User));
+ _useDelay.BeginDelay(uid, useDelay);
+ }
+}
diff --git a/Content.Server/Cargo/Systems/PricingSystem.cs b/Content.Server/Cargo/Systems/PricingSystem.cs
new file mode 100644
index 0000000000..8562437c01
--- /dev/null
+++ b/Content.Server/Cargo/Systems/PricingSystem.cs
@@ -0,0 +1,190 @@
+using System.Linq;
+using Content.Server.Administration;
+using Content.Server.Body.Components;
+using Content.Server.Cargo.Components;
+using Content.Server.Materials;
+using Content.Server.Stack;
+using Content.Shared.Administration;
+using Content.Shared.MobState.Components;
+using Robust.Shared.Console;
+using Robust.Shared.Containers;
+using Robust.Shared.Map;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Cargo.Systems;
+
+///
+/// This handles calculating the price of items, and implements two basic methods of pricing materials.
+///
+public sealed class PricingSystem : EntitySystem
+{
+ [Dependency] private readonly IConsoleHost _consoleHost = default!;
+ [Dependency] private readonly IMapManager _mapManager = default!;
+
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(CalculateStaticPrice);
+ SubscribeLocalEvent(CalculateStackPrice);
+ SubscribeLocalEvent(CalculateMobPrice);
+
+ _consoleHost.RegisterCommand("appraisegrid",
+ "Calculates the total value of the given grids.",
+ "appraisegrid ", AppraiseGridCommand);
+ }
+
+ [AdminCommand(AdminFlags.Debug)]
+ private void AppraiseGridCommand(IConsoleShell shell, string argstr, string[] args)
+ {
+ if (args.Length == 0)
+ {
+ shell.WriteError("Not enough arguments.");
+ return;
+ }
+
+ foreach (var gid in args)
+ {
+ if (!int.TryParse(gid, out var i) || i <= 0)
+ {
+ shell.WriteError($"Invalid grid ID \"{gid}\".");
+ continue;
+ }
+
+ var gridId = new GridId(i);
+
+ if (!_mapManager.TryGetGrid(gridId, out var mapGrid))
+ {
+ shell.WriteError($"Grid \"{i}\" doesn't exist.");
+ continue;
+ }
+
+ List<(double, EntityUid)> mostValuable = new();
+
+ var value = AppraiseGrid(mapGrid.GridEntityId, null, (uid, price) =>
+ {
+ mostValuable.Add((price, uid));
+ mostValuable.Sort((i1, i2) => i2.Item1.CompareTo(i1.Item1));
+ if (mostValuable.Count > 5)
+ mostValuable.Pop();
+ });
+
+ shell.WriteLine($"Grid {gid} appraised to {value} credits.");
+ shell.WriteLine($"The top most valuable items were:");
+ foreach (var (price, ent) in mostValuable)
+ {
+ shell.WriteLine($"- {ToPrettyString(ent)} @ {price} credits");
+ }
+ }
+ }
+
+ private void CalculateMobPrice(EntityUid uid, MobPriceComponent component, ref PriceCalculationEvent args)
+ {
+ if (!TryComp(uid, out var body) || !TryComp(uid, out var state))
+ {
+ Logger.ErrorS("pricing", $"Tried to get the mob price of {ToPrettyString(uid)}, which has no {nameof(BodyComponent)} and no {nameof(MobStateComponent)}.");
+ return;
+ }
+
+ var partList = body.Slots.ToList();
+ var totalPartsPresent = partList.Sum(x => x.Part != null ? 1 : 0);
+ var totalParts = partList.Count;
+
+ var partRatio = totalPartsPresent / (double) totalParts;
+ var partPenalty = component.Price * (1 - partRatio) * component.MissingBodyPartPenalty;
+
+ args.Price += (component.Price - partPenalty) * (state.IsAlive() ? 1.0 : component.DeathPenalty);
+ }
+
+ private void CalculateStackPrice(EntityUid uid, StackPriceComponent component, ref PriceCalculationEvent args)
+ {
+ if (!TryComp(uid, out var stack))
+ {
+ Logger.ErrorS("pricing", $"Tried to get the stack price of {ToPrettyString(uid)}, which has no {nameof(StackComponent)}.");
+ return;
+ }
+
+ args.Price += stack.Count * component.Price;
+ }
+
+ private void CalculateStaticPrice(EntityUid uid, StaticPriceComponent component, ref PriceCalculationEvent args)
+ {
+ args.Price += component.Price;
+ }
+
+ ///
+ /// Appraises an entity, returning it's price.
+ ///
+ /// The entity to appraise.
+ /// The price of the entity.
+ ///
+ /// This fires off an event to calculate the price.
+ /// Calculating the price of an entity that somehow contains itself will likely hang.
+ ///
+ public double GetPrice(EntityUid uid)
+ {
+ var ev = new PriceCalculationEvent();
+ RaiseLocalEvent(uid, ref ev);
+
+ //TODO: Add an OpaqueToAppraisal component or similar for blocking the recursive descent into containers, or preventing material pricing.
+
+ if (TryComp(uid, out var material) && !HasComp(uid))
+ {
+ if (TryComp(uid, out var stack))
+ ev.Price += stack.Count * material.Materials.Sum(x => x.Price * material._materials[x.ID]);
+ else
+ ev.Price += material.Materials.Sum(x => x.Price);
+ }
+
+ if (TryComp(uid, out var containers))
+ {
+ foreach (var container in containers.Containers)
+ {
+ foreach (var ent in container.Value.ContainedEntities)
+ {
+ ev.Price += GetPrice(ent);
+ }
+ }
+ }
+
+ return ev.Price;
+ }
+
+ ///
+ /// Appraises a grid, this is mainly meant to be used by yarrs.
+ ///
+ /// The grid to appraise.
+ /// An optional predicate that controls whether or not the entity is counted toward the total.
+ /// An optional predicate to run after the price has been calculated. Useful for high scores or similar.
+ /// The total value of the grid.
+ public double AppraiseGrid(EntityUid grid, Func? predicate = null, Action? afterPredicate = null)
+ {
+ var xform = Transform(grid);
+ var price = 0.0;
+
+ foreach (var child in xform.ChildEntities)
+ {
+ if (predicate is null || predicate(child))
+ {
+ var subPrice = GetPrice(child);
+ price += subPrice;
+ afterPredicate?.Invoke(child, subPrice);
+ }
+ }
+
+ return price;
+ }
+}
+
+///
+/// A directed by-ref event fired on an entity when something needs to know it's price. This value is not cached.
+///
+[ByRefEvent]
+public struct PriceCalculationEvent
+{
+ ///
+ /// The total price of the entity.
+ ///
+ public double Price = 0;
+
+ public PriceCalculationEvent() { }
+}
diff --git a/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs
new file mode 100644
index 0000000000..9392ce63aa
--- /dev/null
+++ b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs
@@ -0,0 +1,216 @@
+using System.Linq;
+using Content.Server.Cargo.Systems;
+using Content.Server.Chat.Managers;
+using Content.Server.RoundEnd;
+using Content.Server.Spawners.Components;
+using Content.Server.Station.Components;
+using Content.Server.Station.Systems;
+using Content.Shared.CCVar;
+using Content.Shared.CharacterAppearance;
+using Content.Shared.Roles;
+using Robust.Server.Maps;
+using Robust.Server.Player;
+using Robust.Shared.Configuration;
+using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using Robust.Shared.Utility;
+
+namespace Content.Server.GameTicking.Rules;
+
+///
+/// This handles the Pirates minor antag, which is designed to coincide with other modes on occasion.
+///
+public sealed class PiratesRuleSystem : GameRuleSystem
+{
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
+ [Dependency] private readonly IChatManager _chatManager = default!;
+ [Dependency] private readonly IMapLoader _mapLoader = default!;
+ [Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly StationSpawningSystem _stationSpawningSystem = default!;
+ [Dependency] private readonly StationSystem _stationSystem = default!;
+ [Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
+ [Dependency] private readonly PricingSystem _pricingSystem = default!;
+
+ private List _pirates = new();
+ private EntityUid _pirateShip = EntityUid.Invalid;
+ private double _initialShipValue;
+
+ public override string Prototype => "Pirates";
+
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnPlayerSpawningEvent);
+ SubscribeLocalEvent(OnRoundEndTextEvent);
+ }
+
+ private void OnRoundEndTextEvent(RoundEndTextAppendEvent ev)
+ {
+ if (!Enabled)
+ return;
+
+ if (Deleted(_pirateShip))
+ {
+ // Major loss, the ship somehow got annihilated.
+ ev.AddLine(Loc.GetString("pirates-no-ship"));
+ }
+ else
+ {
+
+ List<(double, EntityUid)> mostValuableThefts = new();
+
+ var finalValue = _pricingSystem.AppraiseGrid(_pirateShip, uid =>
+ {
+ foreach (var mind in _pirates)
+ {
+ if (mind.CurrentEntity == uid)
+ return false; // Don't appraise the pirates twice, we count them in separately.
+ }
+ return true;
+ }, (uid, price) =>
+ {
+ mostValuableThefts.Add((price, uid));
+ mostValuableThefts.Sort((i1, i2) => i2.Item1.CompareTo(i1.Item1));
+ if (mostValuableThefts.Count > 5)
+ mostValuableThefts.Pop();
+ });
+
+ foreach (var mind in _pirates)
+ {
+ if (mind.CurrentEntity is not null)
+ finalValue += _pricingSystem.GetPrice(mind.CurrentEntity.Value);
+ }
+
+ var score = finalValue - _initialShipValue;
+
+ ev.AddLine(Loc.GetString("pirates-final-score", ("finalPrice", $"{finalValue:F2}"),
+ ("score", $"{score:F2}")));
+ }
+
+ ev.AddLine(Loc.GetString("pirates-list-start"));
+ foreach (var pirates in _pirates)
+ {
+ ev.AddLine($"- {pirates.CharacterName} ({pirates.Session?.Name}");
+ }
+ }
+
+ public override void Started() { }
+
+ public override void Ended() { }
+
+ private void OnPlayerSpawningEvent(RulePlayerSpawningEvent ev)
+ {
+ // Forgive me for copy-pasting nukies.
+ if (!Enabled)
+ return;
+
+ _pirates.Clear();
+
+ // Between 1 and : needs at least n players per op.
+ var numOps = Math.Max(1,
+ (int)Math.Min(
+ Math.Floor((double)ev.PlayerPool.Count / _cfg.GetCVar(CCVars.PiratesPlayersPerOp)), _cfg.GetCVar(CCVars.PiratesMaxOps)));
+ var ops = new IPlayerSession[numOps];
+ for (var i = 0; i < numOps; i++)
+ {
+ ops[i] = _random.PickAndTake(ev.PlayerPool);
+ }
+
+ var map = "/Maps/pirate.yml";
+
+ var aabbs = _stationSystem.Stations.SelectMany(x =>
+ Comp(x).Grids.Select(x => _mapManager.GetGridComp(x).Grid.WorldAABB)).ToArray();
+ var aabb = aabbs[0];
+
+ for (var i = 1; i < aabbs.Length; i++)
+ {
+ aabb.Union(aabbs[i]);
+ }
+
+ var (_, gridId) = _mapLoader.LoadBlueprint(GameTicker.DefaultMap, map, new MapLoadOptions
+ {
+ Offset = aabb.Center + MathF.Max(aabb.Height / 2f, aabb.Width / 2f) * 2.5f
+ });
+
+ if (!gridId.HasValue)
+ {
+ Logger.ErrorS("pirates", $"Gridid was null when loading \"{map}\", aborting.");
+ foreach (var session in ops)
+ {
+ ev.PlayerPool.Add(session);
+ }
+ return;
+ }
+
+ _pirateShip = _mapManager.GetGridEuid(gridId.Value);
+
+ // TODO: Loot table or something
+ var pirateGear = _prototypeManager.Index("PirateGear"); // YARRR
+
+ var spawns = new List();
+
+ // Forgive me for hardcoding prototypes
+ foreach (var (_, meta, xform) in EntityQuery(true))
+ {
+ if (meta.EntityPrototype?.ID != "SpawnPointPirates" || xform.ParentUid != _pirateShip) continue;
+
+ spawns.Add(xform.Coordinates);
+ }
+
+ if (spawns.Count == 0)
+ {
+ spawns.Add(Transform(_pirateShip).Coordinates);
+ Logger.WarningS("pirates", $"Fell back to default spawn for nukies!");
+ }
+
+ for (var i = 0; i < ops.Length; i++)
+ {
+ var sex = _random.Prob(0.5f) ? Sex.Male : Sex.Female;
+
+ var name = sex.GetName("Human", _prototypeManager, _random);
+
+ var session = ops[i];
+ var newMind = new Mind.Mind(session.UserId)
+ {
+ CharacterName = name
+ };
+ newMind.ChangeOwningPlayer(session.UserId);
+
+ var mob = Spawn("MobHuman", _random.Pick(spawns));
+ MetaData(mob).EntityName = name;
+
+ newMind.TransferTo(mob);
+ _stationSpawningSystem.EquipStartingGear(mob, pirateGear, null);
+
+ _pirates.Add(newMind);
+
+ GameTicker.PlayerJoinGame(session);
+ }
+
+ _initialShipValue = _pricingSystem.AppraiseGrid(_pirateShip); // Include the players in the appraisal.
+ }
+
+ private void OnStartAttempt(RoundStartAttemptEvent ev)
+ {
+ if (!Enabled)
+ return;
+
+ var minPlayers = _cfg.GetCVar(CCVars.PiratesMinPlayers);
+ if (!ev.Forced && ev.Players.Length < minPlayers)
+ {
+ _chatManager.DispatchServerAnnouncement(Loc.GetString("nukeops-not-enough-ready-players", ("readyPlayersCount", ev.Players.Length), ("minimumPlayers", minPlayers)));
+ ev.Cancel();
+ return;
+ }
+
+ if (ev.Players.Length == 0)
+ {
+ _chatManager.DispatchServerAnnouncement(Loc.GetString("nukeops-no-one-ready"));
+ ev.Cancel();
+ return;
+ }
+ }
+}
diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs
index e76a1fe40c..e634c6ddc0 100644
--- a/Content.Shared/CCVar/CCVars.cs
+++ b/Content.Shared/CCVar/CCVars.cs
@@ -286,6 +286,19 @@ namespace Content.Shared.CCVar
public static readonly CVarDef NukeopsPlayersPerOp =
CVarDef.Create("nukeops.players_per_op", 5);
+ /*
+ * Pirates
+ */
+
+ public static readonly CVarDef PiratesMinPlayers =
+ CVarDef.Create("pirates.min_players", 25);
+
+ public static readonly CVarDef PiratesMaxOps =
+ CVarDef.Create("pirates.max_pirates", 6);
+
+ public static readonly CVarDef PiratesPlayersPerOp =
+ CVarDef.Create("pirates.players_per_pirate", 5);
+
/*
* Console
*/
diff --git a/Content.Shared/Materials/MaterialPrototype.cs b/Content.Shared/Materials/MaterialPrototype.cs
index 5dd95c8048..d49eed430a 100644
--- a/Content.Shared/Materials/MaterialPrototype.cs
+++ b/Content.Shared/Materials/MaterialPrototype.cs
@@ -42,5 +42,11 @@ namespace Content.Shared.Materials
[ViewVariables]
[DataField("icon")]
public SpriteSpecifier Icon { get; } = SpriteSpecifier.Invalid;
+
+ ///
+ /// The price per cm3.
+ ///
+ [DataField("price", required: true)]
+ public double Price = 0;
}
}
diff --git a/Resources/Locale/en-US/cargo/components/price-gun-component.ftl b/Resources/Locale/en-US/cargo/components/price-gun-component.ftl
new file mode 100644
index 0000000000..f031748be5
--- /dev/null
+++ b/Resources/Locale/en-US/cargo/components/price-gun-component.ftl
@@ -0,0 +1 @@
+price-gun-pricing-result = The device deems {THE($object)} to be worth {$price} credits.
diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-pirates.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-pirates.ftl
new file mode 100644
index 0000000000..8c224572a6
--- /dev/null
+++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-pirates.ftl
@@ -0,0 +1,7 @@
+pirates-title = Privateers
+pirates-description = A group of privateers has approached your lowly station. Hostile or not, their sole goal is to end the round with as many knicknacks on their ship as they can get.
+
+pirates-no-ship = Through unknown circumstances, the privateer's ship was completely and utterly destroyed. No score.
+pirates-final-score = The privateers successfully obtained {$score} credits worth of knicknacks, with their vessel being worth {$finalPrice} by the end.
+pirates-list-start = The privateers were:
+pirates-most-valuable = The most valuable stolen items were:
diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml
index b829f813fb..0977bd1a12 100644
--- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml
+++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml
@@ -51,7 +51,7 @@
Blunt: 0.8
Slash: 0.8
Piercing: 0.75
- Heat: 0.3
+ Heat: 0.3
Radiation: 0.1
- type: ExplosionResistance
resistance: 0.5
@@ -102,11 +102,11 @@
lowPressureMultiplier: 1000
- type: ClothingSpeedModifier
walkModifier: 0.65
- sprintModifier: 0.65
+ sprintModifier: 0.65
- type: Armor
modifiers:
coefficients:
- Blunt: 0.9
+ Blunt: 0.9
Slash: 0.85
Piercing: 0.85
Heat: 0.7
@@ -131,7 +131,7 @@
lowPressureMultiplier: 1000
- type: ClothingSpeedModifier
walkModifier: 0.75
- sprintModifier: 0.8
+ sprintModifier: 0.8
- type: Armor
modifiers:
coefficients:
@@ -216,7 +216,7 @@
- type: DiseaseProtection
protection: 0.2
- type: ClothingSpeedModifier
- walkModifier: 0.9
+ walkModifier: 0.9
sprintModifier: 0.95
- type: Armor
modifiers:
@@ -254,6 +254,8 @@
resistance: 0.7
- type: ToggleableClothing
clothingPrototype: ClothingHeadHelmetHardsuitRd
+ - type: StaticPrice
+ price: 750
- type: entity
parent: ClothingOuterHardsuitBase
@@ -303,7 +305,7 @@
Blunt: 0.6
Slash: 0.6
Piercing: 0.6
- Heat: 0.8
+ Heat: 0.8
Radiation: 0.25
- type: ExplosionResistance
resistance: 0.6
@@ -311,7 +313,7 @@
clothingPrototype: ClothingHeadHelmetHardsuitSecurity
- type: entity
- parent: ClothingOuterHardsuitSecurity
+ parent: ClothingOuterHardsuitSecurity
id: ClothingOuterHardsuitSecurityRed
name: head of security's hardsuit
description: A special suit that protects against hazardous, low pressure environments. Has an additional layer of armor.
@@ -324,7 +326,7 @@
highPressureMultiplier: 0.45
lowPressureMultiplier: 10000
- type: ClothingSpeedModifier
- walkModifier: 0.7
+ walkModifier: 0.7
sprintModifier: 0.75
- type: Armor
modifiers:
@@ -390,7 +392,7 @@
Blunt: 0.6
Slash: 0.6
Piercing: 0.4
- Heat: 0.25
+ Heat: 0.25
Radiation: 0.20
- type: ExplosionResistance
resistance: 0.5
@@ -422,10 +424,10 @@
Heat: 0.5
Radiation: 0.3
- type: ExplosionResistance
- resistance: 0.8
+ resistance: 0.8
- type: ToggleableClothing
clothingPrototype: ClothingHeadHelmetHardsuitLing
-
+
- type: entity
parent: ClothingOuterHardsuitBase
id: ClothingOuterHardsuitSpatio
@@ -440,7 +442,7 @@
highPressureMultiplier: 0.72
lowPressureMultiplier: 10000
- type: ClothingSpeedModifier
- walkModifier: 0.9
+ walkModifier: 0.9
sprintModifier: 0.8
- type: Armor
modifiers:
@@ -449,7 +451,7 @@
Slash: 0.9
Piercing: 0.95
Heat: 0.9
- Radiation: 0.5
+ Radiation: 0.5
- type: ToggleableClothing
clothingPrototype: ClothingHeadHelmetHardsuitSpatio
@@ -479,7 +481,7 @@
Slash: 0.95
Heat: 0.90
Radiation: 0.75
-
+
- type: entity
parent: ClothingOuterHardsuitBase
id: ClothingOuterHardsuitJuggernaut
@@ -508,7 +510,7 @@
resistance: 0.2
- type: ToggleableClothing
clothingPrototype: ClothingHeadHelmetHardsuitCybersun
-
+
- type: entity
parent: ClothingOuterHardsuitBase
id: ClothingOuterHardsuitSyndieCommander
@@ -555,7 +557,7 @@
walkModifier: 1.0
sprintModifier: 1.0
- type: TemperatureProtection
- coefficient: 0.001
+ coefficient: 0.001
- type: Armor
modifiers:
coefficients:
diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml
index c161e81029..ab567ccd99 100644
--- a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml
+++ b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml
@@ -46,6 +46,8 @@
sprintModifier: 1
enabled: false
- type: NoSlip
+ - type: StaticPrice
+ price: 750
- type: entity
parent: ClothingShoesBase
diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Conditional/pirates.yml b/Resources/Prototypes/Entities/Markers/Spawners/Conditional/pirates.yml
new file mode 100644
index 0000000000..6afb41d250
--- /dev/null
+++ b/Resources/Prototypes/Entities/Markers/Spawners/Conditional/pirates.yml
@@ -0,0 +1,11 @@
+- type: entity
+ id: SpawnPointPirates
+ parent: MarkerBase
+ name: Pirate spawn point
+ components:
+ - type: SpawnPoint
+ - type: Sprite
+ layers:
+ - state: green
+ - sprite: Objects/Fun/toys.rsi
+ state: synb
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
index 691f5be098..53612a62b0 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
@@ -142,6 +142,8 @@
60: 0.6
80: 0.4
90: 0.2
+ - type: MobPrice
+ price: 1000 # Living critters are valuable in space.
- type: entity
save: false
@@ -195,3 +197,4 @@
Heat : 1 #per second, scales with temperature & other constants
- type: Bloodstream
bloodMaxVolume: 150
+
diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml
index 74b4a9f78c..55b248480c 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/human.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml
@@ -322,6 +322,9 @@
attributes:
proper: true
- type: StandingState
+ - type: MobPrice
+ price: 1500 # Kidnapping a living person and selling them for cred is a good move.
+ deathPenalty: 0.01 # However they really ought to be living and intact, otherwise they're worth 100x less.
- type: entity
save: false
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml
index 6480fea036..b0e7fd65c5 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml
@@ -177,6 +177,8 @@
reagents:
- ReagentId: Bicaridine
Quantity: 20
+ - type: StaticPrice
+ price: 750
- type: entity
name: raw crab meat
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml
index 154f2bd790..573547ef03 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml
@@ -12,3 +12,5 @@
- type: Tag
tags:
- DroneUsable
+ - type: StaticPrice
+ price: 75
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
index d2b3608437..acd0644bd1 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml
@@ -11,6 +11,8 @@
- type: Tag
tags:
- DroneUsable
+ - type: StaticPrice
+ price: 75
- type: entity
parent: BaseComputerCircuitboard
@@ -56,6 +58,8 @@
components:
- type: ComputerBoard
prototype: ComputerSupplyOrdering
+ - type: StaticPrice
+ price: 750
- type: entity
parent: BaseComputerCircuitboard
@@ -127,6 +131,8 @@
components:
- type: ComputerBoard
prototype: ComputerId
+ - type: StaticPrice
+ price: 750
- type: entity
parent: BaseComputerCircuitboard
diff --git a/Resources/Prototypes/Entities/Objects/Devices/nuke.yml b/Resources/Prototypes/Entities/Objects/Devices/nuke.yml
index 7ea25e2d8d..d9429140df 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/nuke.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/nuke.yml
@@ -47,6 +47,8 @@
interfaces:
- key: enum.NukeUiKey.Key
type: NukeBoundUserInterface
+ - type: StaticPrice # TODO: Make absolutely certain cargo cannot sell this, that'd be horrible. Presumably, add an export ban component so only the yarrs get a deal here.
+ price: 50000 # YOU STOLE A NUCLEAR FISSION EXPLOSIVE?!
- type: entity
parent: NuclearBomb
@@ -87,3 +89,5 @@
Quantity: 3000
- type: ReagentTank
transferAmount: 100
+ - type: StaticPrice
+ price: 5000 # That's a pretty fancy keg you got there.
diff --git a/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml b/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml
index 5eb779c646..689befc35b 100644
--- a/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml
+++ b/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml
@@ -9,6 +9,8 @@
sprite: Objects/Materials/Sheets/glass.rsi
- type: Item
sprite: Objects/Materials/Sheets/glass.rsi
+ - type: StaticPrice
+ price: 0
- type: ItemStatus
- type: Tag
tags:
@@ -49,6 +51,8 @@
- type: Material
materials:
Glass: 100
+ - type: StackPrice
+ price: 5
- type: Stack
stackType: Glass
- type: Sprite
diff --git a/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml b/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml
index 3c3ab8d2a6..50ac4b03bf 100644
--- a/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml
+++ b/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml
@@ -9,6 +9,8 @@
sprite: Objects/Materials/Sheets/metal.rsi
- type: Item
sprite: Objects/Materials/Sheets/metal.rsi
+ - type: StaticPrice
+ price: 0
- type: ItemStatus
- type: Tag
tags:
diff --git a/Resources/Prototypes/Entities/Objects/Materials/ingots.yml b/Resources/Prototypes/Entities/Objects/Materials/ingots.yml
index f4f95cb3a0..963027b594 100644
--- a/Resources/Prototypes/Entities/Objects/Materials/ingots.yml
+++ b/Resources/Prototypes/Entities/Objects/Materials/ingots.yml
@@ -9,6 +9,8 @@
sprite: Objects/Materials/ingots.rsi
- type: Item
sprite: Objects/Materials/ingots.rsi
+ - type: StaticPrice
+ price: 0
- type: ItemStatus
- type: Tag
tags:
diff --git a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml
index 5fea5ad954..3ec7198841 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml
@@ -13,6 +13,8 @@
size: 12
sprite: Objects/Misc/nukedisk.rsi
state: icon
+ - type: StaticPrice
+ price: 2000
- type: entity
name: nuclear authentication disk
@@ -29,3 +31,5 @@
size: 12
sprite: Objects/Misc/nukedisk.rsi
state: icon
+ - type: StaticPrice
+ price: 1 # it's worth even less than normal items. Perfection.
diff --git a/Resources/Prototypes/Entities/Objects/Misc/space_cash.yml b/Resources/Prototypes/Entities/Objects/Misc/space_cash.yml
index d56dbe566b..006d8adfaf 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/space_cash.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/space_cash.yml
@@ -6,7 +6,9 @@
components:
- type: Material
materials:
- Credit: 100
+ Credit: 1
+ - type: StaticPrice
+ price: 0
- type: Stack
stackType: Credit
max: 1000000 # if you somehow get this rich consider buying a second station
@@ -45,6 +47,7 @@
name: credit
stack: Credit
icon: /Textures/Objects/Economy/cash.rsi/cash.png
+ price: 1
- type: stack
id: Credit
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml
index 7893742e21..f559d6e292 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml
@@ -18,6 +18,8 @@
- type: ExaminableSolution
solution: hypospray
- type: Hypospray
+ - type: StaticPrice
+ price: 750
- type: entity
name: gorlax hypospray
@@ -39,7 +41,7 @@
- type: ExaminableSolution
solution: hypospray
- type: Hypospray
-
+
- type: entity
name: chemical medipen
parent: BaseItem
@@ -75,6 +77,8 @@
- Trash
- type: Recyclable
- type: SpaceGarbage
+ - type: StaticPrice
+ price: 75 # These are limited supply items.
- type: entity
name: emergency medipen
@@ -166,4 +170,5 @@
- type: Tag
tags:
- Write
-
+ - type: StaticPrice
+ price: 75
diff --git a/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml b/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml
index f490d8a631..b67de8df6c 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml
@@ -16,6 +16,8 @@
max: 999999 # todo: add support for unlimited stacks
stackType: Telecrystal
- type: Telecrystal
+ - type: StackPrice
+ price: 200
- type: entity
parent: Telecrystal
diff --git a/Resources/Prototypes/Entities/Objects/Tools/appraisal.yml b/Resources/Prototypes/Entities/Objects/Tools/appraisal.yml
new file mode 100644
index 0000000000..8c289c6a32
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Tools/appraisal.yml
@@ -0,0 +1,15 @@
+- type: entity
+ parent: BaseItem
+ id: AppraisalTool
+ name: appraisal tool
+ description: A beancounter's best friend, with a quantum connection to the galactic market and the ability to appraise even the toughest items.
+ components:
+ - type: Sprite
+ sprite: Objects/Tools/appraisal-tool.rsi
+ state: icon
+ netsync: false
+ - type: Item
+ sprite: Objects/Tools/appraisal-tool.rsi
+ - type: PriceGun
+ - type: UseDelay
+ delay: 3
diff --git a/Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml b/Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml
index 4b95251c01..9374945178 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml
@@ -22,6 +22,8 @@
sprite: Objects/Tools/cable-coils.rsi
- type: CablePlacer
- type: Clickable
+ - type: StackPrice
+ price: 0.5
- type: entity
id: CableHVStack
diff --git a/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml b/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml
index 9fc0dab016..bcfd6134b2 100644
--- a/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml
+++ b/Resources/Prototypes/Entities/Objects/Vehicles/buckleable.yml
@@ -63,6 +63,8 @@
tags:
- VehicleKey
insertSound: /Audio/Effects/Vehicle/vehiclestartup.ogg
+ - type: StaticPrice
+ price: 750 # Grand Theft Auto.
- type: entity
id: VehiclePussyWagon
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 5cb92a8022..b61433d6a6 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
@@ -313,3 +313,5 @@
magState: mag
steps: 5
zeroVisible: true
+ - type: StaticPrice
+ price: 750
diff --git a/Resources/Prototypes/Entities/Objects/base_item.yml b/Resources/Prototypes/Entities/Objects/base_item.yml
index 46bb1fe917..8498733c36 100644
--- a/Resources/Prototypes/Entities/Objects/base_item.yml
+++ b/Resources/Prototypes/Entities/Objects/base_item.yml
@@ -5,6 +5,8 @@
components:
- type: Item
size: 5
+ - type: StaticPrice
+ price: 5
- type: Clickable
- type: InteractionOutline
- type: MovedByPressure
diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml
index 157aa25c6b..f5c498d051 100644
--- a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml
+++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml
@@ -58,7 +58,6 @@
components:
- Paper
-
- type: entity
id: CrateBaseSecure
parent: BaseStructureDynamic
diff --git a/Resources/Prototypes/Entities/Structures/Walls/girder.yml b/Resources/Prototypes/Entities/Structures/Walls/girder.yml
index b026cd6489..59cd8309c2 100644
--- a/Resources/Prototypes/Entities/Structures/Walls/girder.yml
+++ b/Resources/Prototypes/Entities/Structures/Walls/girder.yml
@@ -48,3 +48,5 @@
max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
+ - type: StaticPrice
+ price: 0.5
diff --git a/Resources/Prototypes/Entities/Structures/Walls/walls.yml b/Resources/Prototypes/Entities/Structures/Walls/walls.yml
index 7ea90e3d5a..58e433de84 100644
--- a/Resources/Prototypes/Entities/Structures/Walls/walls.yml
+++ b/Resources/Prototypes/Entities/Structures/Walls/walls.yml
@@ -366,6 +366,8 @@
- type: Appearance
visuals:
- type: ReinforcedWallVisualizer
+ - type: StaticPrice
+ price: 41.5 # total material cost. If you change the recipe for the wall you should recalculate this.
# Riveting
- type: entity
@@ -585,6 +587,8 @@
- type: IconSmooth
key: walls
base: solid
+ - type: StaticPrice
+ price: 1 # total material cost. If you change the recipe for the wall you should recalculate this.
- type: entity
parent: WallBase
diff --git a/Resources/Prototypes/Entities/Structures/Windows/plasma.yml b/Resources/Prototypes/Entities/Structures/Windows/plasma.yml
index ee47ebdcaa..7ab65ade4a 100644
--- a/Resources/Prototypes/Entities/Structures/Windows/plasma.yml
+++ b/Resources/Prototypes/Entities/Structures/Windows/plasma.yml
@@ -40,6 +40,8 @@
trackAllDamage: true
damageOverlay:
sprite: Structures/Windows/cracks.rsi
+ - type: StaticPrice
+ price: 20.5
- type: entity
id: PlasmaWindowDirectional
@@ -77,3 +79,5 @@
max: 2
- !type:DoActsBehavior
acts: [ "Destruction" ]
+ - type: StaticPrice
+ price: 20.5
diff --git a/Resources/Prototypes/Entities/Structures/Windows/reinforced.yml b/Resources/Prototypes/Entities/Structures/Windows/reinforced.yml
index 59f66c68c1..4ff897ce3c 100644
--- a/Resources/Prototypes/Entities/Structures/Windows/reinforced.yml
+++ b/Resources/Prototypes/Entities/Structures/Windows/reinforced.yml
@@ -49,6 +49,8 @@
trackAllDamage: true
damageOverlay:
sprite: Structures/Windows/cracks.rsi
+ - type: StaticPrice
+ price: 0.75
- type: entity
parent: ReinforcedWindow
@@ -68,6 +70,8 @@
- type: Occluder
sizeX: 32
sizeY: 32
+ - type: StaticPrice
+ price: 0.75
- type: entity
id: WindowReinforcedDirectional
@@ -107,3 +111,5 @@
max: 2
- !type:DoActsBehavior
acts: [ "Destruction" ]
+ - type: StaticPrice
+ price: 0.75
diff --git a/Resources/Prototypes/Entities/Structures/Windows/rplasma.yml b/Resources/Prototypes/Entities/Structures/Windows/rplasma.yml
index 8cfc849614..2efb42e339 100644
--- a/Resources/Prototypes/Entities/Structures/Windows/rplasma.yml
+++ b/Resources/Prototypes/Entities/Structures/Windows/rplasma.yml
@@ -49,6 +49,8 @@
trackAllDamage: true
damageOverlay:
sprite: Structures/Windows/cracks.rsi
+ - type: StaticPrice
+ price: 20.75
- type: entity
id: PlasmaReinforcedWindowDirectional
@@ -95,3 +97,5 @@
max: 2
- !type:DoActsBehavior
acts: [ "Destruction" ]
+ - type: StaticPrice
+ price: 20.75
diff --git a/Resources/Prototypes/Entities/Structures/Windows/window.yml b/Resources/Prototypes/Entities/Structures/Windows/window.yml
index ea58cf9a32..3c2650ebe9 100644
--- a/Resources/Prototypes/Entities/Structures/Windows/window.yml
+++ b/Resources/Prototypes/Entities/Structures/Windows/window.yml
@@ -85,6 +85,8 @@
trackAllDamage: true
damageOverlay:
sprite: Structures/Windows/cracks.rsi
+ - type: StaticPrice
+ price: 0.5
- type: entity
id: WindowDirectional
@@ -161,6 +163,8 @@
- type: Construction
graph: WindowDirectional
node: windowDirectional
+ - type: StaticPrice
+ price: 0.5
- type: entity
id: WindowTintedDirectional
@@ -184,6 +188,8 @@
state: tinted_window
- type: Occluder
boundingBox: "-0.5,-0.5,0.5,-0.3"
+ - type: StaticPrice
+ price: 0.5
- type: entity
id: WindowFrostedDirectional
@@ -202,3 +208,5 @@
- type: Icon
sprite: Structures/Windows/directional.rsi
state: frosted_window
+ - type: StaticPrice
+ price: 0.5
diff --git a/Resources/Prototypes/Reagents/Materials/glass.yml b/Resources/Prototypes/Reagents/Materials/glass.yml
index 422f9a1a16..2859705c67 100644
--- a/Resources/Prototypes/Reagents/Materials/glass.yml
+++ b/Resources/Prototypes/Reagents/Materials/glass.yml
@@ -4,6 +4,7 @@
name: glass
icon: Objects/Materials/Sheets/glass.rsi/glass.png
color: "#a8ccd7"
+ price: 0.0025
- type: material
id: ReinforcedGlass
@@ -11,6 +12,7 @@
name: reinforced glass
icon: Objects/Materials/Sheets/glass.rsi/rglass.png
color: "#549bb0"
+ price: 0.00375 # 2-1 mix of glass and metal.
- type: material
id: PlasmaGlass
@@ -18,6 +20,7 @@
name: plasma glass
icon: Objects/Materials/Sheets/glass.rsi/pglass.png
color: "#b35989"
+ price: 0.1025 # 1-1 mix of plasma and glass.
- type: material
id: ReinforcedPlasmaGlass
@@ -25,3 +28,4 @@
name: reinforced plasma glass
icon: Objects/Materials/Sheets/glass.rsi/rpglass.png
color: "#8c4069"
+ price: 0.10375 # 2-2-1 mix of plasma, glass, and metal.
diff --git a/Resources/Prototypes/Reagents/Materials/materials.yml b/Resources/Prototypes/Reagents/Materials/materials.yml
index b57352c19e..74f8890d79 100644
--- a/Resources/Prototypes/Reagents/Materials/materials.yml
+++ b/Resources/Prototypes/Reagents/Materials/materials.yml
@@ -5,6 +5,7 @@
name: cloth
icon: /Textures/Objects/Materials/materials.rsi/cloth.png
color: "#e7e7de"
+ price: 0.005
- type: material
id: Durathread
@@ -12,6 +13,7 @@
name: durathread
icon: /Textures/Objects/Materials/materials.rsi/durathread.png
color: "#8291a1"
+ price: 0.0175 # 1-1 mix of plastic and cloth.
- type: material
id: Plasma
@@ -19,6 +21,7 @@
name: plasma
icon: Objects/Materials/Sheets/other.rsi/plasma.png
color: "#7e009e"
+ price: 0.1
- type: material
id: Plastic
@@ -26,6 +29,7 @@
name: plastic
icon: Objects/Materials/Sheets/other.rsi/plastic.png
color: "#d9d9d9"
+ price: 0.0125
- type: material
id: Wood
@@ -33,10 +37,12 @@
name: wood
icon: Objects/Materials/materials.rsi/wood.png
color: "#966F33"
-
+ price: 0.01
+
- type: material
id: Uranium
stack: Uranium
name: uranium
icon: Objects/Materials/Sheets/other.rsi/uranium.png
color: "#32a852"
+ price: 0.05
diff --git a/Resources/Prototypes/Reagents/Materials/metals.yml b/Resources/Prototypes/Reagents/Materials/metals.yml
index f1a5905697..b04e9bdc84 100644
--- a/Resources/Prototypes/Reagents/Materials/metals.yml
+++ b/Resources/Prototypes/Reagents/Materials/metals.yml
@@ -3,6 +3,7 @@
stack: Steel
name: steel
icon: Objects/Materials/Sheets/metal.rsi/steel.png
+ price: 0.0025
- type: material
id: Gold
@@ -10,6 +11,7 @@
name: gold
icon: Objects/Materials/ingots.rsi/gold.png
color: "#FFD700"
+ price: 0.0625
- type: material
id: Silver
@@ -17,6 +19,7 @@
name: silver
icon: Objects/Materials/ingots.rsi/silver.png
color: "#C0C0C0"
+ price: 0.025
- type: material
id: Plasteel
@@ -24,3 +27,4 @@
name: plasteel
icon: Objects/Materials/Sheets/metal.rsi/plasteel.png
color: "#696969" #Okay, this is epic
+ price: 0.1025 # 1-1 mix of plasma and steel.
diff --git a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml
index 36e88d4679..3ee81e3479 100644
--- a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml
+++ b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml
@@ -27,6 +27,7 @@
shoes: ClothingShoesBootsWork
id: PassengerPDA
belt: ClothingBeltUtility
+ pocket1: AppraisalTool
innerclothingskirt: ClothingUniformJumpskirtColorLightBrown
satchel: ClothingBackpackSatchelEngineering
duffelbag: ClothingBackpackSatchelEngineering
@@ -106,7 +107,7 @@
back: ClothingBackpackDuffelSyndicateOperative
mask: ClothingMaskGasSyndicate
# eyes: Night Vision Goggles whenever they're made
- eyes: ClothingEyesGlassesMeson
+ eyes: ClothingEyesGlassesMeson
ears: ClothingHeadsetAltSyndicate
gloves: ClothingHandsGlovesCombat
outerClothing: ClothingOuterHardsuitSyndieCommander
@@ -117,7 +118,7 @@
innerclothingskirt: ClothingUniformJumpskirtOperative
satchel: ClothingBackpackDuffelSyndicateOperative
duffelbag: ClothingBackpackDuffelSyndicateOperative
-
+
- type: startingGear
id: SyndicateOperativeMedicFull
equipment:
diff --git a/Resources/Prototypes/game_presets.yml b/Resources/Prototypes/game_presets.yml
index 27919f84a4..cf4b56b495 100644
--- a/Resources/Prototypes/game_presets.yml
+++ b/Resources/Prototypes/game_presets.yml
@@ -79,3 +79,13 @@
showInVote: false
rules:
- Nukeops
+
+- type: gamePreset
+ id: Pirates
+ alias:
+ - pirates
+ name: pirates-title
+ description: pirates-description
+ showInVote: false
+ rules:
+ - Pirates
diff --git a/Resources/Prototypes/game_rules.yml b/Resources/Prototypes/game_rules.yml
index dff36b9cda..d071913805 100644
--- a/Resources/Prototypes/game_rules.yml
+++ b/Resources/Prototypes/game_rules.yml
@@ -10,6 +10,9 @@
- type: gameRule
id: Nukeops
+- type: gameRule
+ id: Pirates
+
- type: gameRule
id: Suspicion
diff --git a/Resources/Textures/Objects/Tools/appraisal-tool.rsi/icon.png b/Resources/Textures/Objects/Tools/appraisal-tool.rsi/icon.png
new file mode 100644
index 0000000000..d6c31c4889
Binary files /dev/null and b/Resources/Textures/Objects/Tools/appraisal-tool.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Tools/appraisal-tool.rsi/meta.json b/Resources/Textures/Objects/Tools/appraisal-tool.rsi/meta.json
new file mode 100644
index 0000000000..f17c22aab4
--- /dev/null
+++ b/Resources/Textures/Objects/Tools/appraisal-tool.rsi/meta.json
@@ -0,0 +1,14 @@
+{
+ "copyright" : "Taken from https://github.com/tgstation/tgstation/blob/master/icons/obj/device.dmi state export_scanner at commit 7544e865d0771d9bd917461e9da16d301fe40fc3.",
+ "license" : "CC-BY-SA-3.0",
+ "size" : {
+ "x" : 32,
+ "y" : 32
+ },
+ "states" : [
+ {
+ "name" : "icon"
+ }
+ ],
+ "version" : 1
+}