Implements item pricing, and piracy. (#8548)
* Start implementing item pricing. * Flesh out prices a bit, add the appraisal tool. * Add prices to more things. * YARRRRRRR * gives pirates an appraisal tool in their pocket. * Makes the various traitor objectives valuable. Also nerfs the price of a living person, so it's easier to bargain for them. * Address reviews. * Address reviews.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Cargo.Systems;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Shared.Cargo;
|
using Content.Shared.Cargo;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Cargo.Systems;
|
||||||
using Content.Shared.Cargo.Components;
|
using Content.Shared.Cargo.Components;
|
||||||
|
|
||||||
namespace Content.Server.Cargo.Components
|
namespace Content.Server.Cargo.Components
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Cargo.Systems;
|
||||||
using Content.Shared.Cargo;
|
using Content.Shared.Cargo;
|
||||||
using Content.Shared.Cargo.Components;
|
using Content.Shared.Cargo.Components;
|
||||||
using Content.Shared.MachineLinking;
|
using Content.Shared.MachineLinking;
|
||||||
|
|||||||
26
Content.Server/Cargo/Components/MobPriceComponent.cs
Normal file
26
Content.Server/Cargo/Components/MobPriceComponent.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace Content.Server.Cargo.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for calculating the price of mobs.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class MobPriceComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("missingBodyPartPenalty")]
|
||||||
|
public double MissingBodyPartPenalty = 1.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The base price this mob should fetch.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("price", required: true)]
|
||||||
|
public double Price;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The percentage of the actual price that should be granted should the appraised mob be dead.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("deathPenalty")]
|
||||||
|
public double DeathPenalty = 0.2f;
|
||||||
|
}
|
||||||
10
Content.Server/Cargo/Components/PriceGunComponent.cs
Normal file
10
Content.Server/Cargo/Components/PriceGunComponent.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Content.Server.Cargo.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for the price gun, which calculates the price of any object it appraises.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class PriceGunComponent : Component
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
14
Content.Server/Cargo/Components/StackPriceComponent.cs
Normal file
14
Content.Server/Cargo/Components/StackPriceComponent.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Content.Server.Cargo.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for pricing stacks of items.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class StackPriceComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The price of the object this component is on, per unit.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("price", required: true)]
|
||||||
|
public double Price;
|
||||||
|
}
|
||||||
14
Content.Server/Cargo/Components/StaticPriceComponent.cs
Normal file
14
Content.Server/Cargo/Components/StaticPriceComponent.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Content.Server.Cargo.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for setting a static, unchanging price for an object.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class StaticPriceComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The price of the object this component is on.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("price", required: true)]
|
||||||
|
public double Price;
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ using Content.Shared.Access.Systems;
|
|||||||
using Content.Shared.Cargo;
|
using Content.Shared.Cargo;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
|
|
||||||
namespace Content.Server.Cargo
|
namespace Content.Server.Cargo.Systems
|
||||||
{
|
{
|
||||||
public sealed partial class CargoSystem
|
public sealed partial class CargoSystem
|
||||||
{
|
{
|
||||||
@@ -6,7 +6,7 @@ using Content.Shared.Cargo;
|
|||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
namespace Content.Server.Cargo;
|
namespace Content.Server.Cargo.Systems;
|
||||||
|
|
||||||
public sealed partial class CargoSystem
|
public sealed partial class CargoSystem
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,7 @@ using Content.Shared.Cargo;
|
|||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Cargo;
|
namespace Content.Server.Cargo.Systems;
|
||||||
|
|
||||||
public sealed partial class CargoSystem : SharedCargoSystem
|
public sealed partial class CargoSystem : SharedCargoSystem
|
||||||
{
|
{
|
||||||
37
Content.Server/Cargo/Systems/PriceGunSystem.cs
Normal file
37
Content.Server/Cargo/Systems/PriceGunSystem.cs
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles...
|
||||||
|
/// </summary>
|
||||||
|
public sealed class PriceGunSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||||
|
[Dependency] private readonly PricingSystem _pricingSystem = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<PriceGunComponent, AfterInteractEvent>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
190
Content.Server/Cargo/Systems/PricingSystem.cs
Normal file
190
Content.Server/Cargo/Systems/PricingSystem.cs
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles calculating the price of items, and implements two basic methods of pricing materials.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class PricingSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IConsoleHost _consoleHost = default!;
|
||||||
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<StaticPriceComponent, PriceCalculationEvent>(CalculateStaticPrice);
|
||||||
|
SubscribeLocalEvent<StackPriceComponent, PriceCalculationEvent>(CalculateStackPrice);
|
||||||
|
SubscribeLocalEvent<MobPriceComponent, PriceCalculationEvent>(CalculateMobPrice);
|
||||||
|
|
||||||
|
_consoleHost.RegisterCommand("appraisegrid",
|
||||||
|
"Calculates the total value of the given grids.",
|
||||||
|
"appraisegrid <grid Ids>", 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<BodyComponent>(uid, out var body) || !TryComp<MobStateComponent>(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<StackComponent>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appraises an entity, returning it's price.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">The entity to appraise.</param>
|
||||||
|
/// <returns>The price of the entity.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// This fires off an event to calculate the price.
|
||||||
|
/// Calculating the price of an entity that somehow contains itself will likely hang.
|
||||||
|
/// </remarks>
|
||||||
|
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<MaterialComponent>(uid, out var material) && !HasComp<StackPriceComponent>(uid))
|
||||||
|
{
|
||||||
|
if (TryComp<StackComponent>(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<ContainerManagerComponent>(uid, out var containers))
|
||||||
|
{
|
||||||
|
foreach (var container in containers.Containers)
|
||||||
|
{
|
||||||
|
foreach (var ent in container.Value.ContainedEntities)
|
||||||
|
{
|
||||||
|
ev.Price += GetPrice(ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ev.Price;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appraises a grid, this is mainly meant to be used by yarrs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grid">The grid to appraise.</param>
|
||||||
|
/// <param name="predicate">An optional predicate that controls whether or not the entity is counted toward the total.</param>
|
||||||
|
/// <param name="afterPredicate">An optional predicate to run after the price has been calculated. Useful for high scores or similar.</param>
|
||||||
|
/// <returns>The total value of the grid.</returns>
|
||||||
|
public double AppraiseGrid(EntityUid grid, Func<EntityUid, bool>? predicate = null, Action<EntityUid, double>? 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A directed by-ref event fired on an entity when something needs to know it's price. This value is not cached.
|
||||||
|
/// </summary>
|
||||||
|
[ByRefEvent]
|
||||||
|
public struct PriceCalculationEvent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The total price of the entity.
|
||||||
|
/// </summary>
|
||||||
|
public double Price = 0;
|
||||||
|
|
||||||
|
public PriceCalculationEvent() { }
|
||||||
|
}
|
||||||
216
Content.Server/GameTicking/Rules/PiratesRuleSystem.cs
Normal file
216
Content.Server/GameTicking/Rules/PiratesRuleSystem.cs
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles the Pirates minor antag, which is designed to coincide with other modes on occasion.
|
||||||
|
/// </summary>
|
||||||
|
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<Mind.Mind> _pirates = new();
|
||||||
|
private EntityUid _pirateShip = EntityUid.Invalid;
|
||||||
|
private double _initialShipValue;
|
||||||
|
|
||||||
|
public override string Prototype => "Pirates";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<RulePlayerSpawningEvent>(OnPlayerSpawningEvent);
|
||||||
|
SubscribeLocalEvent<RoundEndTextAppendEvent>(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 <max pirate count>: 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<StationDataComponent>(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<StartingGearPrototype>("PirateGear"); // YARRR
|
||||||
|
|
||||||
|
var spawns = new List<EntityCoordinates>();
|
||||||
|
|
||||||
|
// Forgive me for hardcoding prototypes
|
||||||
|
foreach (var (_, meta, xform) in EntityQuery<SpawnPointComponent, MetaDataComponent, TransformComponent>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -286,6 +286,19 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<int> NukeopsPlayersPerOp =
|
public static readonly CVarDef<int> NukeopsPlayersPerOp =
|
||||||
CVarDef.Create("nukeops.players_per_op", 5);
|
CVarDef.Create("nukeops.players_per_op", 5);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pirates
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static readonly CVarDef<int> PiratesMinPlayers =
|
||||||
|
CVarDef.Create("pirates.min_players", 25);
|
||||||
|
|
||||||
|
public static readonly CVarDef<int> PiratesMaxOps =
|
||||||
|
CVarDef.Create("pirates.max_pirates", 6);
|
||||||
|
|
||||||
|
public static readonly CVarDef<int> PiratesPlayersPerOp =
|
||||||
|
CVarDef.Create("pirates.players_per_pirate", 5);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Console
|
* Console
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -42,5 +42,11 @@ namespace Content.Shared.Materials
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
[DataField("icon")]
|
[DataField("icon")]
|
||||||
public SpriteSpecifier Icon { get; } = SpriteSpecifier.Invalid;
|
public SpriteSpecifier Icon { get; } = SpriteSpecifier.Invalid;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The price per cm3.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("price", required: true)]
|
||||||
|
public double Price = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
price-gun-pricing-result = The device deems {THE($object)} to be worth {$price} credits.
|
||||||
@@ -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:
|
||||||
@@ -254,6 +254,8 @@
|
|||||||
resistance: 0.7
|
resistance: 0.7
|
||||||
- type: ToggleableClothing
|
- type: ToggleableClothing
|
||||||
clothingPrototype: ClothingHeadHelmetHardsuitRd
|
clothingPrototype: ClothingHeadHelmetHardsuitRd
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 750
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingOuterHardsuitBase
|
parent: ClothingOuterHardsuitBase
|
||||||
|
|||||||
@@ -46,6 +46,8 @@
|
|||||||
sprintModifier: 1
|
sprintModifier: 1
|
||||||
enabled: false
|
enabled: false
|
||||||
- type: NoSlip
|
- type: NoSlip
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 750
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingShoesBase
|
parent: ClothingShoesBase
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -142,6 +142,8 @@
|
|||||||
60: 0.6
|
60: 0.6
|
||||||
80: 0.4
|
80: 0.4
|
||||||
90: 0.2
|
90: 0.2
|
||||||
|
- type: MobPrice
|
||||||
|
price: 1000 # Living critters are valuable in space.
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
save: false
|
save: false
|
||||||
@@ -195,3 +197,4 @@
|
|||||||
Heat : 1 #per second, scales with temperature & other constants
|
Heat : 1 #per second, scales with temperature & other constants
|
||||||
- type: Bloodstream
|
- type: Bloodstream
|
||||||
bloodMaxVolume: 150
|
bloodMaxVolume: 150
|
||||||
|
|
||||||
|
|||||||
@@ -322,6 +322,9 @@
|
|||||||
attributes:
|
attributes:
|
||||||
proper: true
|
proper: true
|
||||||
- type: StandingState
|
- 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
|
- type: entity
|
||||||
save: false
|
save: false
|
||||||
|
|||||||
@@ -177,6 +177,8 @@
|
|||||||
reagents:
|
reagents:
|
||||||
- ReagentId: Bicaridine
|
- ReagentId: Bicaridine
|
||||||
Quantity: 20
|
Quantity: 20
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 750
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: raw crab meat
|
name: raw crab meat
|
||||||
|
|||||||
@@ -12,3 +12,5 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- DroneUsable
|
- DroneUsable
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 75
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- DroneUsable
|
- DroneUsable
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 75
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseComputerCircuitboard
|
parent: BaseComputerCircuitboard
|
||||||
@@ -56,6 +58,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: ComputerBoard
|
- type: ComputerBoard
|
||||||
prototype: ComputerSupplyOrdering
|
prototype: ComputerSupplyOrdering
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 750
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseComputerCircuitboard
|
parent: BaseComputerCircuitboard
|
||||||
@@ -127,6 +131,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: ComputerBoard
|
- type: ComputerBoard
|
||||||
prototype: ComputerId
|
prototype: ComputerId
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 750
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseComputerCircuitboard
|
parent: BaseComputerCircuitboard
|
||||||
|
|||||||
@@ -47,6 +47,8 @@
|
|||||||
interfaces:
|
interfaces:
|
||||||
- key: enum.NukeUiKey.Key
|
- key: enum.NukeUiKey.Key
|
||||||
type: NukeBoundUserInterface
|
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
|
- type: entity
|
||||||
parent: NuclearBomb
|
parent: NuclearBomb
|
||||||
@@ -87,3 +89,5 @@
|
|||||||
Quantity: 3000
|
Quantity: 3000
|
||||||
- type: ReagentTank
|
- type: ReagentTank
|
||||||
transferAmount: 100
|
transferAmount: 100
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 5000 # That's a pretty fancy keg you got there.
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
sprite: Objects/Materials/Sheets/glass.rsi
|
sprite: Objects/Materials/Sheets/glass.rsi
|
||||||
- type: Item
|
- type: Item
|
||||||
sprite: Objects/Materials/Sheets/glass.rsi
|
sprite: Objects/Materials/Sheets/glass.rsi
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0
|
||||||
- type: ItemStatus
|
- type: ItemStatus
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
@@ -49,6 +51,8 @@
|
|||||||
- type: Material
|
- type: Material
|
||||||
materials:
|
materials:
|
||||||
Glass: 100
|
Glass: 100
|
||||||
|
- type: StackPrice
|
||||||
|
price: 5
|
||||||
- type: Stack
|
- type: Stack
|
||||||
stackType: Glass
|
stackType: Glass
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
sprite: Objects/Materials/Sheets/metal.rsi
|
sprite: Objects/Materials/Sheets/metal.rsi
|
||||||
- type: Item
|
- type: Item
|
||||||
sprite: Objects/Materials/Sheets/metal.rsi
|
sprite: Objects/Materials/Sheets/metal.rsi
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0
|
||||||
- type: ItemStatus
|
- type: ItemStatus
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
sprite: Objects/Materials/ingots.rsi
|
sprite: Objects/Materials/ingots.rsi
|
||||||
- type: Item
|
- type: Item
|
||||||
sprite: Objects/Materials/ingots.rsi
|
sprite: Objects/Materials/ingots.rsi
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0
|
||||||
- type: ItemStatus
|
- type: ItemStatus
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
size: 12
|
size: 12
|
||||||
sprite: Objects/Misc/nukedisk.rsi
|
sprite: Objects/Misc/nukedisk.rsi
|
||||||
state: icon
|
state: icon
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 2000
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: nuclear authentication disk
|
name: nuclear authentication disk
|
||||||
@@ -29,3 +31,5 @@
|
|||||||
size: 12
|
size: 12
|
||||||
sprite: Objects/Misc/nukedisk.rsi
|
sprite: Objects/Misc/nukedisk.rsi
|
||||||
state: icon
|
state: icon
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 1 # it's worth even less than normal items. Perfection.
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
components:
|
components:
|
||||||
- type: Material
|
- type: Material
|
||||||
materials:
|
materials:
|
||||||
Credit: 100
|
Credit: 1
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0
|
||||||
- type: Stack
|
- type: Stack
|
||||||
stackType: Credit
|
stackType: Credit
|
||||||
max: 1000000 # if you somehow get this rich consider buying a second station
|
max: 1000000 # if you somehow get this rich consider buying a second station
|
||||||
@@ -45,6 +47,7 @@
|
|||||||
name: credit
|
name: credit
|
||||||
stack: Credit
|
stack: Credit
|
||||||
icon: /Textures/Objects/Economy/cash.rsi/cash.png
|
icon: /Textures/Objects/Economy/cash.rsi/cash.png
|
||||||
|
price: 1
|
||||||
|
|
||||||
- type: stack
|
- type: stack
|
||||||
id: Credit
|
id: Credit
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
- type: ExaminableSolution
|
- type: ExaminableSolution
|
||||||
solution: hypospray
|
solution: hypospray
|
||||||
- type: Hypospray
|
- type: Hypospray
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 750
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: gorlax hypospray
|
name: gorlax hypospray
|
||||||
@@ -75,6 +77,8 @@
|
|||||||
- Trash
|
- Trash
|
||||||
- type: Recyclable
|
- type: Recyclable
|
||||||
- type: SpaceGarbage
|
- type: SpaceGarbage
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 75 # These are limited supply items.
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: emergency medipen
|
name: emergency medipen
|
||||||
@@ -166,4 +170,5 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Write
|
- Write
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 75
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
max: 999999 # todo: add support for unlimited stacks
|
max: 999999 # todo: add support for unlimited stacks
|
||||||
stackType: Telecrystal
|
stackType: Telecrystal
|
||||||
- type: Telecrystal
|
- type: Telecrystal
|
||||||
|
- type: StackPrice
|
||||||
|
price: 200
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Telecrystal
|
parent: Telecrystal
|
||||||
|
|||||||
15
Resources/Prototypes/Entities/Objects/Tools/appraisal.yml
Normal file
15
Resources/Prototypes/Entities/Objects/Tools/appraisal.yml
Normal file
@@ -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
|
||||||
@@ -22,6 +22,8 @@
|
|||||||
sprite: Objects/Tools/cable-coils.rsi
|
sprite: Objects/Tools/cable-coils.rsi
|
||||||
- type: CablePlacer
|
- type: CablePlacer
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
|
- type: StackPrice
|
||||||
|
price: 0.5
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CableHVStack
|
id: CableHVStack
|
||||||
|
|||||||
@@ -63,6 +63,8 @@
|
|||||||
tags:
|
tags:
|
||||||
- VehicleKey
|
- VehicleKey
|
||||||
insertSound: /Audio/Effects/Vehicle/vehiclestartup.ogg
|
insertSound: /Audio/Effects/Vehicle/vehiclestartup.ogg
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 750 # Grand Theft Auto.
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: VehiclePussyWagon
|
id: VehiclePussyWagon
|
||||||
|
|||||||
@@ -313,3 +313,5 @@
|
|||||||
magState: mag
|
magState: mag
|
||||||
steps: 5
|
steps: 5
|
||||||
zeroVisible: true
|
zeroVisible: true
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 750
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: Item
|
- type: Item
|
||||||
size: 5
|
size: 5
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 5
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: MovedByPressure
|
- type: MovedByPressure
|
||||||
|
|||||||
@@ -58,7 +58,6 @@
|
|||||||
components:
|
components:
|
||||||
- Paper
|
- Paper
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CrateBaseSecure
|
id: CrateBaseSecure
|
||||||
parent: BaseStructureDynamic
|
parent: BaseStructureDynamic
|
||||||
|
|||||||
@@ -48,3 +48,5 @@
|
|||||||
max: 1
|
max: 1
|
||||||
- !type:DoActsBehavior
|
- !type:DoActsBehavior
|
||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0.5
|
||||||
|
|||||||
@@ -366,6 +366,8 @@
|
|||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
- type: ReinforcedWallVisualizer
|
- type: ReinforcedWallVisualizer
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 41.5 # total material cost. If you change the recipe for the wall you should recalculate this.
|
||||||
|
|
||||||
# Riveting
|
# Riveting
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -585,6 +587,8 @@
|
|||||||
- type: IconSmooth
|
- type: IconSmooth
|
||||||
key: walls
|
key: walls
|
||||||
base: solid
|
base: solid
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 1 # total material cost. If you change the recipe for the wall you should recalculate this.
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: WallBase
|
parent: WallBase
|
||||||
|
|||||||
@@ -40,6 +40,8 @@
|
|||||||
trackAllDamage: true
|
trackAllDamage: true
|
||||||
damageOverlay:
|
damageOverlay:
|
||||||
sprite: Structures/Windows/cracks.rsi
|
sprite: Structures/Windows/cracks.rsi
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 20.5
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: PlasmaWindowDirectional
|
id: PlasmaWindowDirectional
|
||||||
@@ -77,3 +79,5 @@
|
|||||||
max: 2
|
max: 2
|
||||||
- !type:DoActsBehavior
|
- !type:DoActsBehavior
|
||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 20.5
|
||||||
|
|||||||
@@ -49,6 +49,8 @@
|
|||||||
trackAllDamage: true
|
trackAllDamage: true
|
||||||
damageOverlay:
|
damageOverlay:
|
||||||
sprite: Structures/Windows/cracks.rsi
|
sprite: Structures/Windows/cracks.rsi
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0.75
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ReinforcedWindow
|
parent: ReinforcedWindow
|
||||||
@@ -68,6 +70,8 @@
|
|||||||
- type: Occluder
|
- type: Occluder
|
||||||
sizeX: 32
|
sizeX: 32
|
||||||
sizeY: 32
|
sizeY: 32
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0.75
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WindowReinforcedDirectional
|
id: WindowReinforcedDirectional
|
||||||
@@ -107,3 +111,5 @@
|
|||||||
max: 2
|
max: 2
|
||||||
- !type:DoActsBehavior
|
- !type:DoActsBehavior
|
||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0.75
|
||||||
|
|||||||
@@ -49,6 +49,8 @@
|
|||||||
trackAllDamage: true
|
trackAllDamage: true
|
||||||
damageOverlay:
|
damageOverlay:
|
||||||
sprite: Structures/Windows/cracks.rsi
|
sprite: Structures/Windows/cracks.rsi
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 20.75
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: PlasmaReinforcedWindowDirectional
|
id: PlasmaReinforcedWindowDirectional
|
||||||
@@ -95,3 +97,5 @@
|
|||||||
max: 2
|
max: 2
|
||||||
- !type:DoActsBehavior
|
- !type:DoActsBehavior
|
||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 20.75
|
||||||
|
|||||||
@@ -85,6 +85,8 @@
|
|||||||
trackAllDamage: true
|
trackAllDamage: true
|
||||||
damageOverlay:
|
damageOverlay:
|
||||||
sprite: Structures/Windows/cracks.rsi
|
sprite: Structures/Windows/cracks.rsi
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0.5
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WindowDirectional
|
id: WindowDirectional
|
||||||
@@ -161,6 +163,8 @@
|
|||||||
- type: Construction
|
- type: Construction
|
||||||
graph: WindowDirectional
|
graph: WindowDirectional
|
||||||
node: windowDirectional
|
node: windowDirectional
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0.5
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WindowTintedDirectional
|
id: WindowTintedDirectional
|
||||||
@@ -184,6 +188,8 @@
|
|||||||
state: tinted_window
|
state: tinted_window
|
||||||
- type: Occluder
|
- type: Occluder
|
||||||
boundingBox: "-0.5,-0.5,0.5,-0.3"
|
boundingBox: "-0.5,-0.5,0.5,-0.3"
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0.5
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WindowFrostedDirectional
|
id: WindowFrostedDirectional
|
||||||
@@ -202,3 +208,5 @@
|
|||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Structures/Windows/directional.rsi
|
sprite: Structures/Windows/directional.rsi
|
||||||
state: frosted_window
|
state: frosted_window
|
||||||
|
- type: StaticPrice
|
||||||
|
price: 0.5
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
name: glass
|
name: glass
|
||||||
icon: Objects/Materials/Sheets/glass.rsi/glass.png
|
icon: Objects/Materials/Sheets/glass.rsi/glass.png
|
||||||
color: "#a8ccd7"
|
color: "#a8ccd7"
|
||||||
|
price: 0.0025
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: ReinforcedGlass
|
id: ReinforcedGlass
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
name: reinforced glass
|
name: reinforced glass
|
||||||
icon: Objects/Materials/Sheets/glass.rsi/rglass.png
|
icon: Objects/Materials/Sheets/glass.rsi/rglass.png
|
||||||
color: "#549bb0"
|
color: "#549bb0"
|
||||||
|
price: 0.00375 # 2-1 mix of glass and metal.
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: PlasmaGlass
|
id: PlasmaGlass
|
||||||
@@ -18,6 +20,7 @@
|
|||||||
name: plasma glass
|
name: plasma glass
|
||||||
icon: Objects/Materials/Sheets/glass.rsi/pglass.png
|
icon: Objects/Materials/Sheets/glass.rsi/pglass.png
|
||||||
color: "#b35989"
|
color: "#b35989"
|
||||||
|
price: 0.1025 # 1-1 mix of plasma and glass.
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: ReinforcedPlasmaGlass
|
id: ReinforcedPlasmaGlass
|
||||||
@@ -25,3 +28,4 @@
|
|||||||
name: reinforced plasma glass
|
name: reinforced plasma glass
|
||||||
icon: Objects/Materials/Sheets/glass.rsi/rpglass.png
|
icon: Objects/Materials/Sheets/glass.rsi/rpglass.png
|
||||||
color: "#8c4069"
|
color: "#8c4069"
|
||||||
|
price: 0.10375 # 2-2-1 mix of plasma, glass, and metal.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
name: cloth
|
name: cloth
|
||||||
icon: /Textures/Objects/Materials/materials.rsi/cloth.png
|
icon: /Textures/Objects/Materials/materials.rsi/cloth.png
|
||||||
color: "#e7e7de"
|
color: "#e7e7de"
|
||||||
|
price: 0.005
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: Durathread
|
id: Durathread
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
name: durathread
|
name: durathread
|
||||||
icon: /Textures/Objects/Materials/materials.rsi/durathread.png
|
icon: /Textures/Objects/Materials/materials.rsi/durathread.png
|
||||||
color: "#8291a1"
|
color: "#8291a1"
|
||||||
|
price: 0.0175 # 1-1 mix of plastic and cloth.
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: Plasma
|
id: Plasma
|
||||||
@@ -19,6 +21,7 @@
|
|||||||
name: plasma
|
name: plasma
|
||||||
icon: Objects/Materials/Sheets/other.rsi/plasma.png
|
icon: Objects/Materials/Sheets/other.rsi/plasma.png
|
||||||
color: "#7e009e"
|
color: "#7e009e"
|
||||||
|
price: 0.1
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: Plastic
|
id: Plastic
|
||||||
@@ -26,6 +29,7 @@
|
|||||||
name: plastic
|
name: plastic
|
||||||
icon: Objects/Materials/Sheets/other.rsi/plastic.png
|
icon: Objects/Materials/Sheets/other.rsi/plastic.png
|
||||||
color: "#d9d9d9"
|
color: "#d9d9d9"
|
||||||
|
price: 0.0125
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: Wood
|
id: Wood
|
||||||
@@ -33,6 +37,7 @@
|
|||||||
name: wood
|
name: wood
|
||||||
icon: Objects/Materials/materials.rsi/wood.png
|
icon: Objects/Materials/materials.rsi/wood.png
|
||||||
color: "#966F33"
|
color: "#966F33"
|
||||||
|
price: 0.01
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: Uranium
|
id: Uranium
|
||||||
@@ -40,3 +45,4 @@
|
|||||||
name: uranium
|
name: uranium
|
||||||
icon: Objects/Materials/Sheets/other.rsi/uranium.png
|
icon: Objects/Materials/Sheets/other.rsi/uranium.png
|
||||||
color: "#32a852"
|
color: "#32a852"
|
||||||
|
price: 0.05
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
stack: Steel
|
stack: Steel
|
||||||
name: steel
|
name: steel
|
||||||
icon: Objects/Materials/Sheets/metal.rsi/steel.png
|
icon: Objects/Materials/Sheets/metal.rsi/steel.png
|
||||||
|
price: 0.0025
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: Gold
|
id: Gold
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
name: gold
|
name: gold
|
||||||
icon: Objects/Materials/ingots.rsi/gold.png
|
icon: Objects/Materials/ingots.rsi/gold.png
|
||||||
color: "#FFD700"
|
color: "#FFD700"
|
||||||
|
price: 0.0625
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: Silver
|
id: Silver
|
||||||
@@ -17,6 +19,7 @@
|
|||||||
name: silver
|
name: silver
|
||||||
icon: Objects/Materials/ingots.rsi/silver.png
|
icon: Objects/Materials/ingots.rsi/silver.png
|
||||||
color: "#C0C0C0"
|
color: "#C0C0C0"
|
||||||
|
price: 0.025
|
||||||
|
|
||||||
- type: material
|
- type: material
|
||||||
id: Plasteel
|
id: Plasteel
|
||||||
@@ -24,3 +27,4 @@
|
|||||||
name: plasteel
|
name: plasteel
|
||||||
icon: Objects/Materials/Sheets/metal.rsi/plasteel.png
|
icon: Objects/Materials/Sheets/metal.rsi/plasteel.png
|
||||||
color: "#696969" #Okay, this is epic
|
color: "#696969" #Okay, this is epic
|
||||||
|
price: 0.1025 # 1-1 mix of plasma and steel.
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
shoes: ClothingShoesBootsWork
|
shoes: ClothingShoesBootsWork
|
||||||
id: PassengerPDA
|
id: PassengerPDA
|
||||||
belt: ClothingBeltUtility
|
belt: ClothingBeltUtility
|
||||||
|
pocket1: AppraisalTool
|
||||||
innerclothingskirt: ClothingUniformJumpskirtColorLightBrown
|
innerclothingskirt: ClothingUniformJumpskirtColorLightBrown
|
||||||
satchel: ClothingBackpackSatchelEngineering
|
satchel: ClothingBackpackSatchelEngineering
|
||||||
duffelbag: ClothingBackpackSatchelEngineering
|
duffelbag: ClothingBackpackSatchelEngineering
|
||||||
|
|||||||
@@ -79,3 +79,13 @@
|
|||||||
showInVote: false
|
showInVote: false
|
||||||
rules:
|
rules:
|
||||||
- Nukeops
|
- Nukeops
|
||||||
|
|
||||||
|
- type: gamePreset
|
||||||
|
id: Pirates
|
||||||
|
alias:
|
||||||
|
- pirates
|
||||||
|
name: pirates-title
|
||||||
|
description: pirates-description
|
||||||
|
showInVote: false
|
||||||
|
rules:
|
||||||
|
- Pirates
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
- type: gameRule
|
- type: gameRule
|
||||||
id: Nukeops
|
id: Nukeops
|
||||||
|
|
||||||
|
- type: gameRule
|
||||||
|
id: Pirates
|
||||||
|
|
||||||
- type: gameRule
|
- type: gameRule
|
||||||
id: Suspicion
|
id: Suspicion
|
||||||
|
|
||||||
|
|||||||
BIN
Resources/Textures/Objects/Tools/appraisal-tool.rsi/icon.png
Normal file
BIN
Resources/Textures/Objects/Tools/appraisal-tool.rsi/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 231 B |
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user