diff --git a/Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs b/Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs index 7ad25333327..dc141963498 100644 --- a/Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs +++ b/Content.Server/Shipyard/Systems/ShipyardSystem.Consoles.cs @@ -307,9 +307,24 @@ public void OnSellMessage(EntityUid uid, ShipyardConsoleComponent component, Shi var shuttleName = ToPrettyString(shuttleUid); // Grab the name before it gets 1984'd - if (!TrySellShuttle(stationUid, shuttleUid, out var bill)) + var saleResult = TrySellShuttle(stationUid, shuttleUid, out var bill); + if (saleResult.Error != ShipyardSaleError.Success) { - ConsolePopup(args.Actor, Loc.GetString("shipyard-console-sale-reqs")); + switch (saleResult.Error) + { + case ShipyardSaleError.Undocked: + ConsolePopup(args.Actor, Loc.GetString("shipyard-console-sale-not-docked")); + break; + case ShipyardSaleError.OrganicsAboard: + ConsolePopup(args.Actor, Loc.GetString("shipyard-console-sale-organic-aboard", ("name", saleResult.OrganicName ?? "Somebody"))); + break; + case ShipyardSaleError.InvalidShip: + ConsolePopup(args.Actor, Loc.GetString("shipyard-console-sale-invalid-ship")); + break; + default: + ConsolePopup(args.Actor, Loc.GetString("shipyard-console-sale-unknown-reason", ("reason", saleResult.Error.ToString()))); + break; + } PlayDenySound(uid, component); return; } @@ -471,7 +486,14 @@ private void OnItemSlotChanged(EntityUid uid, ShipyardConsoleComponent component } } - public bool FoundOrganics(EntityUid uid, EntityQuery mobQuery, EntityQuery xformQuery) + /// + /// Looks for a living, sapient being aboard a particular entity. + /// + /// The entity to search (e.g. a shuttle, a station) + /// A query to get the MobState from an entity + /// A query to get the transform component of an entity + /// The name of the sapient being if one was found, null otherwise. + public string? FoundOrganics(EntityUid uid, EntityQuery mobQuery, EntityQuery xformQuery) { var xform = xformQuery.GetComponent(uid); var childEnumerator = xform.ChildEnumerator; @@ -481,12 +503,17 @@ public bool FoundOrganics(EntityUid uid, EntityQuery mobQuery if (mobQuery.TryGetComponent(child, out var mobState) && !_mobState.IsDead(child, mobState) && _mind.TryGetMind(child, out var mind, out var mindComp) - && !_mind.IsCharacterDeadIc(mindComp) - || FoundOrganics(child, mobQuery, xformQuery)) - return true; + && !_mind.IsCharacterDeadIc(mindComp)) + return mindComp.CharacterName; + else + { + var charName = FoundOrganics(child, mobQuery, xformQuery); + if (charName != null) + return charName; + } } - return false; + return null; } /// diff --git a/Content.Server/Shipyard/Systems/ShipyardSystem.cs b/Content.Server/Shipyard/Systems/ShipyardSystem.cs index ffbc7b53f40..875defcb4b7 100644 --- a/Content.Server/Shipyard/Systems/ShipyardSystem.cs +++ b/Content.Server/Shipyard/Systems/ShipyardSystem.cs @@ -39,6 +39,21 @@ public sealed partial class ShipyardSystem : SharedShipyardSystem private ISawmill _sawmill = default!; private bool _enabled; + // The type of error from the attempted sale of a ship. + public enum ShipyardSaleError + { + Success, // Ship can be sold. + Undocked, // Ship is not docked with the station. + OrganicsAboard, // Sapient intelligence is aboard, cannot sell, would delete the organics + InvalidShip, // Ship is invalid + } + + public struct ShipyardSaleResult + { + public ShipyardSaleError Error; // Whether or not the ship can be sold. + public string? OrganicName; // In case an organic is aboard, this will be set to the first that's aboard. + } + public override void Initialize() { base.Initialize(); @@ -174,17 +189,24 @@ private bool TryAddShuttle(string shuttlePath, [NotNullWhen(true)] out EntityUid /// /// The ID of the station that the shuttle is docked to /// The grid ID of the shuttle to be appraised and sold - public bool TrySellShuttle(EntityUid stationUid, EntityUid shuttleUid, out int bill) + public ShipyardSaleResult TrySellShuttle(EntityUid stationUid, EntityUid shuttleUid, out int bill) { + ShipyardSaleResult result = new ShipyardSaleResult(); bill = 0; if (!TryComp(stationUid, out var stationGrid) || !HasComp(shuttleUid) || !TryComp(shuttleUid, out var xform) || ShipyardMap == null) - return false; + { + result.Error = ShipyardSaleError.InvalidShip; + return result; + } var targetGrid = _station.GetLargestGrid(stationGrid); if (targetGrid == null) - return false; + { + result.Error = ShipyardSaleError.InvalidShip; + return result; + } var gridDocks = _docking.GetDocks((EntityUid) targetGrid); var shuttleDocks = _docking.GetDocks(shuttleUid); @@ -207,16 +229,20 @@ public bool TrySellShuttle(EntityUid stationUid, EntityUid shuttleUid, out int b if (!isDocked) { _sawmill.Warning($"shuttle is not docked to that station"); - return false; + result.Error = ShipyardSaleError.Undocked; + return result; } var mobQuery = GetEntityQuery(); var xformQuery = GetEntityQuery(); - if (FoundOrganics(shuttleUid, mobQuery, xformQuery)) + var charName = FoundOrganics(shuttleUid, mobQuery, xformQuery); + if (charName is not null) { _sawmill.Warning($"organics on board"); - return false; + result.Error = ShipyardSaleError.OrganicsAboard; + result.OrganicName = charName; + return result; } //just yeet and delete for now. Might want to split it into another function later to send back to the shipyard map first to pause for something @@ -229,7 +255,8 @@ public bool TrySellShuttle(EntityUid stationUid, EntityUid shuttleUid, out int b bill = (int) _pricing.AppraiseGrid(shuttleUid); _mapManager.DeleteGrid(shuttleUid); _sawmill.Info($"Sold shuttle {shuttleUid} for {bill}"); - return true; + result.Error = ShipyardSaleError.Success; + return result; } private void CleanupShipyard() diff --git a/Content.Server/_NF/CryoSleep/CryoSleepSystem.cs b/Content.Server/_NF/CryoSleep/CryoSleepSystem.cs index 1133ebbff84..0e17d32b402 100644 --- a/Content.Server/_NF/CryoSleep/CryoSleepSystem.cs +++ b/Content.Server/_NF/CryoSleep/CryoSleepSystem.cs @@ -199,9 +199,10 @@ public bool InsertBody(EntityUid? toInsert, CryoSleepComponent component, bool f var mobQuery = GetEntityQuery(); var xformQuery = GetEntityQuery(); // Refuse to accept "passengers" (e.g. pet felinids in bags) - if (_shipyard.FoundOrganics(toInsert.Value, mobQuery, xformQuery)) + string? name = _shipyard.FoundOrganics(toInsert.Value, mobQuery, xformQuery); + if (name is not null) { - _popup.PopupEntity(Loc.GetString("cryopod-refuse-organic", ("cryopod", cryopod)), cryopod, PopupType.SmallCaution); + _popup.PopupEntity(Loc.GetString("cryopod-refuse-organic", ("cryopod", cryopod), ("name", name)), cryopod, PopupType.SmallCaution); return false; } diff --git a/Resources/Locale/en-US/_NF/cryosleep/cryosleep-component.ftl b/Resources/Locale/en-US/_NF/cryosleep/cryosleep-component.ftl index 47115c0304d..eaefd477674 100644 --- a/Resources/Locale/en-US/_NF/cryosleep/cryosleep-component.ftl +++ b/Resources/Locale/en-US/_NF/cryosleep/cryosleep-component.ftl @@ -17,6 +17,6 @@ cryo-wakeup-result-disabled = Returning from cryosleep is disabled on this serve # Cryopod cryopod-refuse-dead = The {$cryopod} refuses to accept dead patients. -cryopod-refuse-organic = The {$cryopod} refuses to accept more than 1 sentient entity at once. +cryopod-refuse-organic = The {$cryopod} detected multiple sentients! Remove {$name}. cryopod-wake-up = {$entity} returns from cryosleep! diff --git a/Resources/Locale/en-US/_NF/shipyard/shipyard-console-component.ftl b/Resources/Locale/en-US/_NF/shipyard/shipyard-console-component.ftl index 0d3c8f346ce..159cefdb2f7 100644 --- a/Resources/Locale/en-US/_NF/shipyard/shipyard-console-component.ftl +++ b/Resources/Locale/en-US/_NF/shipyard/shipyard-console-component.ftl @@ -12,5 +12,10 @@ shipyard-console-invalid-station = Not a valid station shipyard-console-no-bank = No bank account found shipyard-console-no-deed = No ship deed found shipyard-console-sale-reqs = Ship must be docked and all crew disembarked +shipyard-console-sale-not-docked = Ship must be docked. +shipyard-console-sale-organic-aboard = All crew must disembark. {$name} is still aboard. +# This error message is bad, but if it happens, something awful's happened. +shipyard-console-sale-invalid-ship = Ship is invalid and cannot be sold. +shipyard-console-sale-unknown-reason = Ship cannot be sold: {reason} shipyard-console-deed-label = Registered Ship: shipyard-console-appraisal-label = Shuttle Estimated Value:{" "}