From a8fa538f50ff89eab4938a838903c85f70a4583f Mon Sep 17 00:00:00 2001 From: Piggy3 <98598467+Piggy3@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:56:37 -0700 Subject: [PATCH 1/5] Update animal.yml --- .../Prototypes/Body/Organs/Animal/animal.yml | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Resources/Prototypes/Body/Organs/Animal/animal.yml b/Resources/Prototypes/Body/Organs/Animal/animal.yml index 152c4c4112c..c994259e587 100644 --- a/Resources/Prototypes/Body/Organs/Animal/animal.yml +++ b/Resources/Prototypes/Body/Organs/Animal/animal.yml @@ -3,6 +3,7 @@ parent: BaseItem abstract: true components: + - type: Produce - type: Organ - type: Edible - type: Sprite @@ -60,6 +61,8 @@ reagents: - ReagentId: UncookedAnimalProteins Quantity: 5 + - ReagentId: Nutriment + Quantity: 5 - type: Item size: Small heldPrefix: lungs @@ -82,6 +85,8 @@ reagents: - ReagentId: UncookedAnimalProteins Quantity: 5 + - ReagentId: Nutriment + Quantity: 5 - type: Stomach - type: Metabolizer maxReagents: 3 @@ -120,6 +125,14 @@ - type: Sprite state: liver - type: Organ + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: UncookedAnimalProteins + Quantity: 5 + - ReagentId: Nutriment + Quantity: 5 - type: Metabolizer maxReagents: 1 metabolizerTypes: [ Animal ] @@ -138,6 +151,14 @@ - type: Sprite state: heart-on - type: Organ + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: UncookedAnimalProteins + Quantity: 5 + - ReagentId: Nutriment + Quantity: 5 - type: Metabolizer maxReagents: 2 metabolizerTypes: [ Animal ] @@ -160,6 +181,14 @@ - state: kidney-l - state: kidney-r - type: Organ + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: UncookedAnimalProteins + Quantity: 5 + - ReagentId: Nutriment + Quantity: 5 - type: Metabolizer maxReagents: 5 metabolizerTypes: [ Animal ] From acc14c297cd30f1616b28f0ee3f15bcb9d34b218 Mon Sep 17 00:00:00 2001 From: Piggy3 <98598467+Piggy3@users.noreply.github.com> Date: Sun, 31 May 2026 14:26:54 -0700 Subject: [PATCH 2/5] Revert "Update animal.yml" This reverts commit a8fa538f50ff89eab4938a838903c85f70a4583f. --- .../Prototypes/Body/Organs/Animal/animal.yml | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/Resources/Prototypes/Body/Organs/Animal/animal.yml b/Resources/Prototypes/Body/Organs/Animal/animal.yml index 38956888153..f7efe3d554f 100644 --- a/Resources/Prototypes/Body/Organs/Animal/animal.yml +++ b/Resources/Prototypes/Body/Organs/Animal/animal.yml @@ -3,7 +3,6 @@ parent: BaseItem abstract: true components: - - type: Produce - type: Organ - type: Edible - type: Sprite @@ -62,8 +61,6 @@ reagents: - ReagentId: UncookedAnimalProteins Quantity: 5 - - ReagentId: Nutriment - Quantity: 5 - type: Item size: Small heldPrefix: lungs @@ -86,8 +83,6 @@ reagents: - ReagentId: UncookedAnimalProteins Quantity: 5 - - ReagentId: Nutriment - Quantity: 5 - type: Stomach - type: Metabolizer maxReagents: 3 @@ -126,14 +121,6 @@ - type: Sprite state: liver - type: Organ - - type: SolutionContainerManager - solutions: - food: - reagents: - - ReagentId: UncookedAnimalProteins - Quantity: 5 - - ReagentId: Nutriment - Quantity: 5 - type: Metabolizer maxReagents: 1 metabolizerTypes: [ Animal ] @@ -152,14 +139,6 @@ - type: Sprite state: heart-on - type: Organ - - type: SolutionContainerManager - solutions: - food: - reagents: - - ReagentId: UncookedAnimalProteins - Quantity: 5 - - ReagentId: Nutriment - Quantity: 5 - type: Metabolizer maxReagents: 2 metabolizerTypes: [ Animal ] @@ -182,14 +161,6 @@ - state: kidney-l - state: kidney-r - type: Organ - - type: SolutionContainerManager - solutions: - food: - reagents: - - ReagentId: UncookedAnimalProteins - Quantity: 5 - - ReagentId: Nutriment - Quantity: 5 - type: Metabolizer maxReagents: 5 metabolizerTypes: [ Animal ] From cee06a52e0386fcaf7c4235e4a504a7dca82e9f1 Mon Sep 17 00:00:00 2001 From: Piggy3 <98598467+Piggy3@users.noreply.github.com> Date: Sun, 31 May 2026 14:27:03 -0700 Subject: [PATCH 3/5] Revert "Merge branch 'organ-biomass' into persistence_testing" This reverts commit d85b25f0b246d747b6c7afb2308315c4f60816ae, reversing changes made to b63b395705ba5f254328841eba00dc22375f7d4e. --- Content.Client/Doors/DoorSystem.cs | 2 +- .../Components/DoorSignalControlComponent.cs | 15 +- .../Systems/DoorSignalControlSystem.cs | 87 ++++----- .../Doors/Components/DoorComponent.cs | 7 +- .../Doors/Systems/SharedDoorSystem.cs | 50 +---- .../en-US/machine-linking/receiver_ports.ftl | 3 - .../Catalog/Cargo/cargo_bounties_food.yml | 154 ---------------- .../Cargo/cargo_bounties_materials.yml | 101 ---------- .../Prototypes/DeviceLinking/sink_ports.yml | 5 - .../Objects/Consumable/Food/burger.yml | 172 ------------------ .../Doors/Airlocks/base_structureairlocks.yml | 1 - .../Recipes/Cooking/meal_recipes.yml | 57 ------ .../markings/markings/bounty_validate_test.go | 163 ----------------- 13 files changed, 54 insertions(+), 763 deletions(-) delete mode 100644 Resources/Prototypes/Catalog/Cargo/cargo_bounties_food.yml delete mode 100644 Resources/Prototypes/Catalog/Cargo/cargo_bounties_materials.yml delete mode 100644 Tools/markings/markings/bounty_validate_test.go diff --git a/Content.Client/Doors/DoorSystem.cs b/Content.Client/Doors/DoorSystem.cs index 451d6ccbdc7..0f6537eeadd 100644 --- a/Content.Client/Doors/DoorSystem.cs +++ b/Content.Client/Doors/DoorSystem.cs @@ -119,7 +119,7 @@ private void UpdateAppearanceForDoorState(Entity entity, SpriteCo } return; - case DoorState.Opening or DoorState.boltingOpen: + case DoorState.Opening: if (entity.Comp.OpeningAnimationTime == TimeSpan.Zero) return; diff --git a/Content.Server/DeviceLinking/Components/DoorSignalControlComponent.cs b/Content.Server/DeviceLinking/Components/DoorSignalControlComponent.cs index f87af0a882b..8d2e984753f 100644 --- a/Content.Server/DeviceLinking/Components/DoorSignalControlComponent.cs +++ b/Content.Server/DeviceLinking/Components/DoorSignalControlComponent.cs @@ -7,21 +7,18 @@ namespace Content.Server.DeviceLinking.Components public sealed partial class DoorSignalControlComponent : Component { [DataField("openPort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string OpenSink = "Open"; + public string OpenPort = "Open"; [DataField("closePort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string CloseSink = "Close"; + public string ClosePort = "Close"; [DataField("togglePort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ToggleSink = "Toggle"; + public string TogglePort = "Toggle"; [DataField("boltPort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string BoltSink = "DoorBolt"; + public string InBolt = "DoorBolt"; - [DataField("directDrivePort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string DirectDriveSink = "DirectDrive"; - - [DataField("statusPort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string StatusSource = "DoorStatus"; + [DataField("onOpenPort", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string OutOpen = "DoorStatus"; } } diff --git a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs index 47cb612b6c1..a7089780581 100644 --- a/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs +++ b/Content.Server/DeviceLinking/Systems/DoorSignalControlSystem.cs @@ -27,8 +27,8 @@ public override void Initialize() private void OnInit(EntityUid uid, DoorSignalControlComponent component, ComponentInit args) { - _signalSystem.EnsureSinkPorts(uid, component.OpenSink, component.CloseSink, component.ToggleSink); - _signalSystem.EnsureSourcePorts(uid, component.StatusSource); + _signalSystem.EnsureSinkPorts(uid, component.OpenPort, component.ClosePort, component.TogglePort); + _signalSystem.EnsureSourcePorts(uid, component.OutOpen); } private void OnSignalReceived(EntityUid uid, DoorSignalControlComponent component, ref SignalReceivedEvent args) @@ -39,45 +39,47 @@ private void OnSignalReceived(EntityUid uid, DoorSignalControlComponent componen var state = SignalState.Momentary; args.Data?.TryGetValue(DeviceNetworkConstants.LogicState, out state); - // A special "fuzzy" helper state, which equates to either High or Momentary(pulse signal). - // Used for signals that respond on prompt rather than sustained. - bool fuzzyState = state == SignalState.High || state == SignalState.Momentary; - switch (args.Port) + + if (args.Port == component.OpenPort) + { + if (state == SignalState.High || state == SignalState.Momentary) + { + if (door.State == DoorState.Closed) + _doorSystem.TryOpen(uid, door); + } + } + else if (args.Port == component.ClosePort) + { + if (state == SignalState.High || state == SignalState.Momentary) + { + if (door.State == DoorState.Open) + _doorSystem.TryClose(uid, door); + } + } + else if (args.Port == component.TogglePort) { - case var port when port == component.OpenSink && door.State == DoorState.Closed && fuzzyState: - _doorSystem.TryOpen(uid, door); - break; - case var port when port == component.CloseSink && door.State == DoorState.Open && fuzzyState: - _doorSystem.TryClose(uid, door); - break; - case var port when port == component.ToggleSink && fuzzyState: + if (state == SignalState.High || state == SignalState.Momentary) + { _doorSystem.TryToggleDoor(uid, door); - break; - case var port when port == component.BoltSink && TryComp(uid, out var bolts): - switch (state) - { - case SignalState.Momentary: - _doorSystem.SetBoltsDown((uid, bolts), !bolts.BoltsDown); - break; - case SignalState.High: - _doorSystem.SetBoltsDown((uid, bolts), true); - break; - case SignalState.Low: - _doorSystem.SetBoltsDown((uid, bolts), false); - break; - } - break; - case var port when port == component.DirectDriveSink: - switch (state) - { - case SignalState.High: - _doorSystem.DirectDriveOpen(uid, door, null, false, true); - break; - case SignalState.Low: - _doorSystem.DirectDriveClose(uid, door, null, false); - break; - } - break; + } + } + else if (args.Port == component.InBolt) + { + if (!TryComp(uid, out var bolts)) + return; + + // if its a pulse toggle, otherwise set bolts to high/low + bool bolt; + if (state == SignalState.Momentary) + { + bolt = !bolts.BoltsDown; + } + else + { + bolt = state == SignalState.High; + } + + _doorSystem.SetBoltsDown((uid, bolts), bolt); } } @@ -86,16 +88,15 @@ private void OnStateChanged(EntityUid uid, DoorSignalControlComponent door, Door if (args.State == DoorState.Closed) { // only ever say the door is closed when it is completely airtight - _signalSystem.SendSignal(uid, door.StatusSource, false); + _signalSystem.SendSignal(uid, door.OutOpen, false); } else if (args.State == DoorState.Open || args.State == DoorState.Opening || args.State == DoorState.Closing - || args.State == DoorState.Emagging - || args.State == DoorState.boltingOpen) + || args.State == DoorState.Emagging) { // say the door is open whenever it would be letting air pass - _signalSystem.SendSignal(uid, door.StatusSource, true); + _signalSystem.SendSignal(uid, door.OutOpen, true); } } } diff --git a/Content.Shared/Doors/Components/DoorComponent.cs b/Content.Shared/Doors/Components/DoorComponent.cs index e106cce2356..e66dff2611d 100644 --- a/Content.Shared/Doors/Components/DoorComponent.cs +++ b/Content.Shared/Doors/Components/DoorComponent.cs @@ -25,10 +25,6 @@ public sealed partial class DoorComponent : Component [DataField, AutoNetworkedField] [Access(typeof(SharedDoorSystem))] public DoorState State = DoorState.Closed; - // There isn't an easy safe way to shut and bolt the door in one go. - // Collisions and shit make it unrealistic, unlike bolting open, which is infallible. - // Our best alternative is to just have the door "want" to be bolted when it's closed. - public bool BoltingOnShut = false; #region Timing // if you want do dynamically adjust these times, you need to add networking for them. So for now, they are all @@ -311,8 +307,7 @@ public enum DoorState : byte Opening, Welded, Denying, - Emagging, - boltingOpen + Emagging } [Serializable, NetSerializable] diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.cs index 37e012f5779..310ea70bdc8 100644 --- a/Content.Shared/Doors/Systems/SharedDoorSystem.cs +++ b/Content.Shared/Doors/Systems/SharedDoorSystem.cs @@ -179,7 +179,7 @@ public bool SetState(EntityUid uid, DoorState state, DoorComponent? door = null) door.NextStateChange = GameTiming.CurTime + door.EmagDuration; break; - case DoorState.Open or DoorState.boltingOpen: + case DoorState.Open: door.Partial = false; if (door.NextStateChange == null) _activeDoors.Remove((uid, door)); @@ -321,27 +321,6 @@ public bool TryOpen(EntityUid uid, DoorComponent? door = null, EntityUid? user = return true; } - public bool DirectDriveOpen(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false, bool quiet = false) - { - if (!Resolve(uid, ref door)) - return false; - - if (TryComp(uid, out var doorBoltComponent)) - { - SetBoltsDown((uid, doorBoltComponent), false, null, true); - } - - if (!CanOpen(uid, door, user, quiet)) - return false; - - if (!SetState(uid, DoorState.boltingOpen, door)) - return false; - - StartOpening(uid, door, user, predicted); - - return true; - } - public bool CanOpen(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool quiet = true) { if (!Resolve(uid, ref door)) @@ -388,7 +367,7 @@ public void StartOpening(EntityUid uid, DoorComponent? door = null, EntityUid? u else if (_net.IsServer) Audio.PlayPvs(door.OpenSound, uid, AudioParams.Default.WithVolume(-5)); - if ((lastState == DoorState.Emagging || lastState == DoorState.boltingOpen) && TryComp(uid, out var doorBoltComponent)) + if (lastState == DoorState.Emagging && TryComp(uid, out var doorBoltComponent)) SetBoltsDown((uid, doorBoltComponent), true, user, true); } @@ -441,26 +420,6 @@ public bool TryClose(EntityUid uid, DoorComponent? door = null, EntityUid? user return true; } - public bool DirectDriveClose(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false) - { - if (!Resolve(uid, ref door)) - return false; - - if (TryComp(uid, out var doorBoltComponent)) - { - SetBoltsDown((uid, doorBoltComponent), false, null, true); - } - - door.BoltingOnShut = true; - Dirty(uid, door); - - if (!CanClose(uid, door, user)) - return false; - - StartClosing(uid, door, user, predicted); - return true; - } - /// /// Immediately start closing a door /// @@ -524,11 +483,6 @@ public bool OnPartialClose(EntityUid uid, DoorComponent? door = null, PhysicsCom door.Partial = true; SetCollidable(uid, true, door, physics); door.NextStateChange = GameTiming.CurTime + door.CloseTimeTwo; - if (door.BoltingOnShut && TryComp(uid, out var doorBoltComponent)) - { - door.BoltingOnShut = false; - SetBoltsDown((uid, doorBoltComponent), true, null, true); - } Dirty(uid, door); _activeDoors.Add((uid, door)); diff --git a/Resources/Locale/en-US/machine-linking/receiver_ports.ftl b/Resources/Locale/en-US/machine-linking/receiver_ports.ftl index f89cd84f327..aa34b415c5c 100644 --- a/Resources/Locale/en-US/machine-linking/receiver_ports.ftl +++ b/Resources/Locale/en-US/machine-linking/receiver_ports.ftl @@ -25,9 +25,6 @@ signal-port-description-close = Closes a device. signal-port-name-doorbolt = Door bolt signal-port-description-doorbolt = Bolts door when HIGH. -signal-port-name-direct-drive = Direct drive -signal-port-description-direct-drive = Switches the door to be directly driven by signals, and remains bolted otherwise. HIGH opens the door, LOW closes it. - signal-port-name-trigger-receiver = Trigger signal-port-description-trigger-receiver = Triggers some mechanism on the device. diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_bounties_food.yml b/Resources/Prototypes/Catalog/Cargo/cargo_bounties_food.yml deleted file mode 100644 index 6eefd1e15a3..00000000000 --- a/Resources/Prototypes/Catalog/Cargo/cargo_bounties_food.yml +++ /dev/null @@ -1,154 +0,0 @@ -# Cargo bounty rebalance for issue #161 -# REMOVED trivial single-item bounties like: -# - $3000 / 10x Carrots -# - $2000 / 3x Carrot fries -# REPLACED with combined multi-item bounties that require ~45+ min to complete -# Reward guideline: ~20% above one of the constituent bounties (not a hard rule) -# Refresh timer context: 2.5 hours, so bounties should feel meaningful but obtainable - -- type: cargoBounty - id: FoodCarrotMixed - label: cargo-bounty-food-carrot-mixed - reward: 2500 - entries: - # WHY: merged 10x Carrots ($3000) + 3x Carrot Fries ($2000) into one bounty - # Quantities increased to raise complexity; reward set between the two originals - # so players feel rewarded without it being a windfall for trivial effort - - id: FoodCarrot - name: cargo-bounty-entry-carrot - amount: 25 - orGroup: null - - id: FoodCarrotFries - name: cargo-bounty-entry-carrot-fries - amount: 8 - orGroup: null - # WHY: carrot cake added as optional complexity boost per issue guidance - # "adding related items to increase complexity is also valid where it makes sense" - - id: FoodCarrotCake - name: cargo-bounty-entry-carrot-cake - amount: 4 - orGroup: null - -- type: cargoBounty - id: FoodBreadAssorted - label: cargo-bounty-food-bread-assorted - reward: 3000 - entries: - # WHY: replaces trivial single bread bounties; baker must produce a full assortment - # This requires sustained kitchen effort rather than a single quick craft - - id: FoodBreadPlain - name: cargo-bounty-entry-bread-plain - amount: 10 - orGroup: null - - id: FoodBreadMeatball - name: cargo-bounty-entry-bread-meatball - amount: 5 - orGroup: null - - id: FoodBreadBanana - name: cargo-bounty-entry-bread-banana - amount: 5 - orGroup: null - -- type: cargoBounty - id: FoodSaladPlatter - label: cargo-bounty-food-salad-platter - reward: 2800 - entries: - # WHY: salad items are fast to make individually but sourcing ingredients - # for all three together creates meaningful kitchen coordination time - - id: FoodSaladGarden - name: cargo-bounty-entry-salad-garden - amount: 8 - orGroup: null - - id: FoodSaladCaesar - name: cargo-bounty-entry-salad-caesar - amount: 6 - orGroup: null - - id: FoodSaladWaldorf - name: cargo-bounty-entry-salad-waldorf - amount: 4 - orGroup: null - -- type: cargoBounty - id: FoodMeatCooked - label: cargo-bounty-food-meat-cooked - reward: 3500 - entries: - # WHY: requires both hunting/processing AND cooking, two distinct gameplay loops - # combining them ensures the bounty can't be trivialized by one player alone quickly - - id: FoodMeatSteak - name: cargo-bounty-entry-meat-steak - amount: 10 - orGroup: null - - id: FoodMeatBurger - name: cargo-bounty-entry-meat-burger - amount: 8 - orGroup: null - - id: FoodMeatCutlet - name: cargo-bounty-entry-meat-cutlet - amount: 6 - orGroup: null - -- type: cargoBounty - id: FoodDairyProducts - label: cargo-bounty-food-dairy-products - reward: 2200 - entries: - # WHY: dairy requires botany (seeds) + kitchen processing chain - # multiple products ensure it cannot be completed with a single recipe loop - - id: FoodCheese - name: cargo-bounty-entry-cheese - amount: 8 - orGroup: null - - id: FoodButter - name: cargo-bounty-entry-butter - amount: 6 - orGroup: null - - id: FoodMilkCarton - name: cargo-bounty-entry-milk-carton - amount: 10 - orGroup: null - -- type: cargoBounty - id: FoodFruitBasket - label: cargo-bounty-food-fruit-basket - reward: 2600 - entries: - # WHY: variety of fruits means botany must grow multiple crop types - # prevents trivial single-crop speed-run completion - - id: FoodApple - name: cargo-bounty-entry-apple - amount: 15 - orGroup: null - - id: FoodOrange - name: cargo-bounty-entry-orange - amount: 12 - orGroup: null - - id: FoodWatermelon - name: cargo-bounty-entry-watermelon - amount: 6 - orGroup: null - - id: FoodGrapes - name: cargo-bounty-entry-grapes - amount: 10 - orGroup: null - -- type: cargoBounty - id: FoodSoupSelection - label: cargo-bounty-food-soup-selection - reward: 3200 - entries: - # WHY: soups require pots, ingredients from multiple sources, and cook time - # a selection of 3 types ensures sustained kitchen engagement - - id: FoodSoupTomato - name: cargo-bounty-entry-soup-tomato - amount: 8 - orGroup: null - - id: FoodSoupMushroom - name: cargo-bounty-entry-soup-mushroom - amount: 6 - orGroup: null - - id: FoodSoupPotato - name: cargo-bounty-entry-soup-potato - amount: 6 - orGroup: null diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_bounties_materials.yml b/Resources/Prototypes/Catalog/Cargo/cargo_bounties_materials.yml deleted file mode 100644 index 9c4c78b0418..00000000000 --- a/Resources/Prototypes/Catalog/Cargo/cargo_bounties_materials.yml +++ /dev/null @@ -1,101 +0,0 @@ -# Material cargo bounties rebalance for issue #161 -# REMOVED trivial low-quantity single-material bounties -# REPLACED with combined multi-material bounties requiring coordinated station effort -# Context: 2.5-hour refresh timer; bounties should feel like a shift goal, not a sidebar - -- type: cargoBounty - id: MaterialsMetalSheet - label: cargo-bounty-materials-metal-sheet - reward: 4000 - entries: - # WHY: merged trivial small-stack metal bounties into one requiring - # sustained mining + smelting loop; quantities set so one player can - # complete within the refresh window with focused effort but not trivially - - id: SheetSteel - name: cargo-bounty-entry-sheet-steel - amount: 50 - orGroup: null - - id: SheetPlastic - name: cargo-bounty-entry-sheet-plastic - amount: 30 - orGroup: null - - id: SheetGlass - name: cargo-bounty-entry-sheet-glass - amount: 40 - orGroup: null - -- type: cargoBounty - id: MaterialsExoticAlloy - label: cargo-bounty-materials-exotic-alloy - reward: 6500 - entries: - # WHY: exotic/refined materials require mining rare ores AND processing - # combining them gates completion behind both a mining run and R&D/smelting - - id: SheetPlasma - name: cargo-bounty-entry-sheet-plasma - amount: 20 - orGroup: null - - id: SheetUranium - name: cargo-bounty-entry-sheet-uranium - amount: 15 - orGroup: null - - id: SheetGold - name: cargo-bounty-entry-sheet-gold - amount: 10 - orGroup: null - -- type: cargoBounty - id: MaterialsClothFiber - label: cargo-bounty-materials-cloth-fiber - reward: 3000 - entries: - # WHY: cloth production involves botany (cotton/durathread) + processing - # multiple cloth types ensures varied production rather than single-source spam - - id: ClothingMaterialCloth - name: cargo-bounty-entry-cloth - amount: 30 - orGroup: null - - id: ClothingMaterialDurathread - name: cargo-bounty-entry-durathread - amount: 20 - orGroup: null - -- type: cargoBounty - id: MaterialsChemReagents - label: cargo-bounty-materials-chem-reagents - reward: 5000 - entries: - # WHY: chemical reagents require chemistry department involvement - # multiple reagents prevent one quick chem-loop from trivializing the bounty - - id: ChemistryReagentOmega3 - name: cargo-bounty-entry-omega3 - amount: 10 - orGroup: null - - id: ChemistryReagentSodiumChloride - name: cargo-bounty-entry-sodium-chloride - amount: 15 - orGroup: null - - id: ChemistryReagentSugar - name: cargo-bounty-entry-sugar - amount: 20 - orGroup: null - -- type: cargoBounty - id: MaterialsCircuitBoards - label: cargo-bounty-materials-circuit-boards - reward: 5500 - entries: - # WHY: circuit boards require science/engineering investment - # asking for multiple board types gates completion behind cross-department effort - - id: CircuitboardComputer - name: cargo-bounty-entry-circuit-computer - amount: 5 - orGroup: null - - id: CircuitboardMachineAME - name: cargo-bounty-entry-circuit-ame - amount: 3 - orGroup: null - - id: CircuitboardMachineAnomalyGenerator - name: cargo-bounty-entry-circuit-anomaly - amount: 2 - orGroup: null diff --git a/Resources/Prototypes/DeviceLinking/sink_ports.yml b/Resources/Prototypes/DeviceLinking/sink_ports.yml index 99e80f7c9b8..45e15ba0d6d 100644 --- a/Resources/Prototypes/DeviceLinking/sink_ports.yml +++ b/Resources/Prototypes/DeviceLinking/sink_ports.yml @@ -43,11 +43,6 @@ name: signal-port-name-doorbolt description: signal-port-description-doorbolt -- type: sinkPort - id: DirectDrive - name: signal-port-name-direct-drive - description: signal-port-description-direct-drive - - type: sinkPort id: Trigger name: signal-port-name-trigger-receiver diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml index 1a6c04038b4..30f307b6eb0 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml @@ -370,178 +370,6 @@ - Meat # Tastes like bun, brains. -# Series of organ burgers -- type: entity - parent: FoodBurgerBase - id: FoodBurgerLung - name: lung burger - description: A strange looking burger. - components: - - type: Item - storedOffset: 0,1 - inhandVisuals: - left: - - state: plain-inhand-left - right: - - state: plain-inhand-right - - type: FlavorProfile - flavors: - - bun - - meaty - - type: Sprite - state: cheese - - type: SolutionContainerManager - solutions: - food: - maxVol: 20 - reagents: - - ReagentId: Nutriment - Quantity: 6 - - ReagentId: Protein - Quantity: 6 - - ReagentId: Vitamin - Quantity: 5 - - type: Tag - tags: - - Meat - -- type: entity - parent: FoodBurgerBase - id: FoodBurgerLiver - name: liver burger - description: A strange looking burger. - components: - - type: Item - storedOffset: 0,1 - inhandVisuals: - left: - - state: plain-inhand-left - right: - - state: plain-inhand-right - - type: FlavorProfile - flavors: - - bun - - meaty - - type: Sprite - state: cheese - - type: SolutionContainerManager - solutions: - food: - maxVol: 20 - reagents: - - ReagentId: Nutriment - Quantity: 6 - - ReagentId: Protein - Quantity: 6 - - ReagentId: Vitamin - Quantity: 5 - - type: Tag - tags: - - Meat - -- type: entity - parent: FoodBurgerBase - id: FoodBurgerStomach - name: stomach burger - description: A strange looking burger. - components: - - type: Item - storedOffset: 0,1 - inhandVisuals: - left: - - state: plain-inhand-left - right: - - state: plain-inhand-right - - type: FlavorProfile - flavors: - - bun - - meaty - - type: Sprite - state: cheese - - type: SolutionContainerManager - solutions: - food: - maxVol: 20 - reagents: - - ReagentId: Nutriment - Quantity: 6 - - ReagentId: Protein - Quantity: 6 - - ReagentId: Vitamin - Quantity: 5 - - type: Tag - tags: - - Meat - -- type: entity - parent: FoodBurgerBase - id: FoodBurgerKidneys - name: kidneys burger - description: A strange looking burger. - components: - - type: Item - storedOffset: 0,1 - inhandVisuals: - left: - - state: plain-inhand-left - right: - - state: plain-inhand-right - - type: FlavorProfile - flavors: - - bun - - meaty - - type: Sprite - state: cheese - - type: SolutionContainerManager - solutions: - food: - maxVol: 20 - reagents: - - ReagentId: Nutriment - Quantity: 6 - - ReagentId: Protein - Quantity: 6 - - ReagentId: Vitamin - Quantity: 5 - - type: Tag - tags: - - Meat - -- type: entity - parent: FoodBurgerBase - id: FoodBurgerHeart - name: heart burger - description: A strange looking burger. - components: - - type: Item - storedOffset: 0,1 - inhandVisuals: - left: - - state: plain-inhand-left - right: - - state: plain-inhand-right - - type: FlavorProfile - flavors: - - bun - - meaty - - type: Sprite - state: cheese - - type: SolutionContainerManager - solutions: - food: - maxVol: 20 - reagents: - - ReagentId: Nutriment - Quantity: 6 - - ReagentId: Protein - Quantity: 6 - - ReagentId: Vitamin - Quantity: 5 - - type: Tag - tags: - - Meat - - - type: entity parent: FoodBurgerBase id: FoodBurgerCat diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml index 9caae0c829b..717530bfb79 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml @@ -122,7 +122,6 @@ - Toggle - AutoClose - DoorBolt - - DirectDrive - type: DeviceLinkSource ports: - DoorStatus diff --git a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml index dc4c531f9cd..8499e884700 100644 --- a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml +++ b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml @@ -111,63 +111,6 @@ FoodBreadBun: 1 OrganHumanBrain: 1 -#Series of organ burger -- type: microwaveMealRecipe - id: RecipeLungBurger - name: lung burger recipe - result: FoodBurgerLung - time: 10 - group: Savory - solids: - FoodBreadBun: 1 - OrganAnimalLungs: 1 - FoodCheeseSlice: 1 - -- type: microwaveMealRecipe - id: RecipeLiverBurger - name: liver burger recipe - result: FoodBurgerLiver - time: 10 - group: Savory - solids: - FoodBreadBun: 1 - OrganAnimalLiver: 1 - FoodCheeseSlice: 1 - -- type: microwaveMealRecipe - id: RecipeStomachBurger - name: stomach burger recipe - result: FoodBurgerStomach - time: 10 - group: Savory - solids: - FoodBreadBun: 1 - OrganAnimalStomach: 1 - FoodCheeseSlice: 1 - -- type: microwaveMealRecipe - id: RecipeKidneyBurger - name: kidney burger recipe - result: FoodBurgerKidneys - time: 10 - group: Savory - solids: - FoodBreadBun: 1 - OrganAnimalKidneys: 1 - FoodCheeseSlice: 1 - -- type: microwaveMealRecipe - id: RecipeHeartBurger - name: heart burger recipe - result: FoodBurgerHeart - time: 10 - group: Savory - solids: - FoodBreadBun: 1 - OrganAnimalHeart: 1 - FoodCheeseSlice: 1 - - - type: microwaveMealRecipe id: RecipeCatBurger name: cat burger recipe diff --git a/Tools/markings/markings/bounty_validate_test.go b/Tools/markings/markings/bounty_validate_test.go deleted file mode 100644 index b2c05d71f2d..00000000000 --- a/Tools/markings/markings/bounty_validate_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package markings_test - -// NOTE: These tests validate bounty rebalance logic concepts since the actual -// bounty data is in YAML and loaded at runtime by the game engine. -// They document the design constraints from issue #161 so regressions are caught. - -import ( - "testing" -) - -// BountyEntry mirrors the structure of a cargo bounty entry for validation. -type BountyEntry struct { - ID string - Amount int -} - -// CargoBounty mirrors the structure of a cargo bounty prototype for validation. -type CargoBounty struct { - ID string - Reward int - Entries []BountyEntry -} - -// isTrivial returns true if a bounty can be completed trivially: -// defined as having only 1 entry type AND total item count below the trivial threshold. -// Issue #161: trivial bounties complete too fast relative to the 2.5-hour refresh timer. -func isTrivial(b CargoBounty) bool { - if len(b.Entries) < 2 { - // Single-item bounties are the primary target for removal per issue #161 - return true - } - totalItems := 0 - for _, e := range b.Entries { - totalItems += e.Amount - } - // WHY threshold=15: below this even multi-item bounties complete in <10 min - return totalItems < 15 -} - -// rewardIsReasonable checks that a bounty reward falls within design guidelines: -// not so low players ignore it, not so high it breaks weekly payout caps. -// Issue #161 guideline: ~20% above one constituent bounty's value, roughly $2000-$7000. -func rewardIsReasonable(b CargoBounty) bool { - return b.Reward >= 2000 && b.Reward <= 8000 -} - -// TestRebalancedBountiesAreNotTrivial verifies the new combined bounties -// meet the complexity bar set in issue #161: multiple item types, meaningful quantities. -func TestRebalancedBountiesAreNotTrivial(t *testing.T) { - // These represent the new bounties defined in cargo_bounties_food.yml - // and cargo_bounties_materials.yml after the rebalance. - newBounties := []CargoBounty{ - { - ID: "FoodCarrotMixed", - Reward: 2500, - Entries: []BountyEntry{ - {ID: "FoodCarrot", Amount: 25}, - {ID: "FoodCarrotFries", Amount: 8}, - {ID: "FoodCarrotCake", Amount: 4}, - }, - }, - { - ID: "MaterialsMetalSheet", - Reward: 4000, - Entries: []BountyEntry{ - {ID: "SheetSteel", Amount: 50}, - {ID: "SheetPlastic", Amount: 30}, - {ID: "SheetGlass", Amount: 40}, - }, - }, - { - ID: "MaterialsExoticAlloy", - Reward: 6500, - Entries: []BountyEntry{ - {ID: "SheetPlasma", Amount: 20}, - {ID: "SheetUranium", Amount: 15}, - {ID: "SheetGold", Amount: 10}, - }, - }, - { - ID: "FoodBreadAssorted", - Reward: 3000, - Entries: []BountyEntry{ - {ID: "FoodBreadPlain", Amount: 10}, - {ID: "FoodBreadMeatball", Amount: 5}, - {ID: "FoodBreadBanana", Amount: 5}, - }, - }, - } - - for _, b := range newBounties { - t.Run(b.ID, func(t *testing.T) { - // WHY: every new bounty must have multiple entry types - // single-type bounties are the definition of trivial per issue #161 - if isTrivial(b) { - t.Errorf("bounty %q is trivial (single item type or too few items); must have 2+ item types with meaningful quantities", b.ID) - } - }) - } -} - -// TestRewardRangeIsReasonable ensures no bounty pays out absurdly low or high -// relative to the weekly payout cap and the ~20% guideline from issue #161. -func TestRewardRangeIsReasonable(t *testing.T) { - bounties := []CargoBounty{ - {ID: "FoodCarrotMixed", Reward: 2500}, - {ID: "FoodBreadAssorted", Reward: 3000}, - {ID: "FoodSaladPlatter", Reward: 2800}, - {ID: "FoodMeatCooked", Reward: 3500}, - {ID: "MaterialsMetalSheet", Reward: 4000}, - {ID: "MaterialsExoticAlloy", Reward: 6500}, - {ID: "MaterialsClothFiber", Reward: 3000}, - {ID: "MaterialsChemReagents", Reward: 5000}, - {ID: "MaterialsCircuitBoards", Reward: 5500}, - } - - for _, b := range bounties { - t.Run(b.ID, func(t *testing.T) { - // WHY: reward must be in $2000-$8000 range - // below $2000: players won't bother; above $8000: breaks economy pacing - if !rewardIsReasonable(b) { - t.Errorf("bounty %q reward %d is outside reasonable range [2000, 8000]", b.ID, b.Reward) - } - }) - } -} - -// TestOldTrivialBountiesWereCorrectlyIdentified documents the REMOVED bounties -// so future contributors understand why they were replaced, not just deleted. -// Issue #161: these completed in <10 min vs the 2.5-hour refresh timer. -func TestOldTrivialBountiesWereCorrectlyIdentified(t *testing.T) { - // These are the OLD bounties that were trivial and have been removed. - // This test serves as living documentation of the rebalance decision. - oldTrivialBounties := []CargoBounty{ - { - // WHY removed: single item, only 10 units, completable in <5 minutes - ID: "OldCarrotTen", - Reward: 3000, - Entries: []BountyEntry{ - {ID: "FoodCarrot", Amount: 10}, - }, - }, - { - // WHY removed: single item, only 3 units, trivially fast to cook - ID: "OldCarrotFriesThree", - Reward: 2000, - Entries: []BountyEntry{ - {ID: "FoodCarrotFries", Amount: 3}, - }, - }, - } - - for _, b := range oldTrivialBounties { - t.Run(b.ID+"_was_trivial", func(t *testing.T) { - // Confirm our isTrivial function correctly identifies these as trivial. - // If this test fails, isTrivial logic regressed and may let trivial bounties - // slip back in during future content additions. - if !isTrivial(b) { - t.Errorf("bounty %q should be identified as trivial but was not; check isTrivial() logic", b.ID) - } - }) - } -} From 8ba63c1f0cd2d66933ab53642508c226181df705 Mon Sep 17 00:00:00 2001 From: Piggy3 <98598467+Piggy3@users.noreply.github.com> Date: Sun, 31 May 2026 16:44:30 -0700 Subject: [PATCH 4/5] add deltapressure to tiny fans --- .../Atmospherics/Thresholds/deltapressure.yml | 9 +++++ .../Piping/Atmospherics/special.yml | 40 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/Resources/Prototypes/Atmospherics/Thresholds/deltapressure.yml b/Resources/Prototypes/Atmospherics/Thresholds/deltapressure.yml index d64a80f6f28..b911cf67f57 100644 --- a/Resources/Prototypes/Atmospherics/Thresholds/deltapressure.yml +++ b/Resources/Prototypes/Atmospherics/Thresholds/deltapressure.yml @@ -105,3 +105,12 @@ minPressureDelta: 187.5 scalingType: Threshold + +- type: entity + abstract: true + id: BaseDeltaPressureFans + components: + - type: DeltaPressure + minPressure: 200 + minPressureDelta: 150 + scalingType: Linear diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml index 2026ed38a4d..ff55f9fd5bb 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml @@ -1,6 +1,7 @@ # Devices which are not portable but don't link up to anything - type: entity id: AtmosDeviceFanTiny + parent: BaseDeltaPressureFans name: tiny fan description: A tiny fan, releasing a thin gust of air. placement: @@ -43,9 +44,29 @@ - type: Tag tags: - SpreaderIgnore + - type: Damageable + damageContainer: StructuralInorganic + damageModifierSet: StructuralMetallic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 1 + behaviors: + - !type:SpawnEntitiesBehavior + spawn: + TinyFanFlatpack: + min: 1 + max: 1 + - !type:PlaySoundBehavior + sound: + collection: MetalSlam + - !type:DoActsBehavior + acts: [ "Destruction" ] - type: entity id: AtmosDeviceFanDirectional + parent: BaseDeltaPressureFans name: directional fan description: A thin fan, stopping the movement of gases across it. placement: @@ -91,3 +112,22 @@ - type: Tag tags: - SpreaderIgnore + - type: Damageable + damageContainer: StructuralInorganic + damageModifierSet: StructuralMetallic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 1 + behaviors: + - !type:SpawnEntitiesBehavior + spawn: + DirectionalFanFlatpack: + min: 1 + max: 1 + - !type:PlaySoundBehavior + sound: + collection: MetalSlam + - !type:DoActsBehavior + acts: [ "Destruction" ] From 376803a9abe72986b1cb65240dbeede4149001c5 Mon Sep 17 00:00:00 2001 From: Piggy3 <98598467+Piggy3@users.noreply.github.com> Date: Mon, 15 Jun 2026 04:52:12 -0700 Subject: [PATCH 5/5] Update deltapressure.yml --- .../Atmospherics/Thresholds/deltapressure.yml | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/Resources/Prototypes/Atmospherics/Thresholds/deltapressure.yml b/Resources/Prototypes/Atmospherics/Thresholds/deltapressure.yml index b911cf67f57..d29f4a85d54 100644 --- a/Resources/Prototypes/Atmospherics/Thresholds/deltapressure.yml +++ b/Resources/Prototypes/Atmospherics/Thresholds/deltapressure.yml @@ -6,111 +6,111 @@ abstract: true id: BaseDeltaPressureReinforcedPlasma components: - - type: DeltaPressure - minPressure: 150000 - minPressureDelta: 100000 - scalingType: Linear - scalingPower: 0.0001 + - type: DeltaPressure + minPressure: 150000 + minPressureDelta: 100000 + scalingType: Linear + scalingPower: 0.0001 ## For quarter reinforced plasma windows - type: entity abstract: true id: BaseDeltaPressureReinforcedPlasmaQuarter components: - - type: DeltaPressure - minPressure: 37500 - minPressureDelta: 25000 - scalingType: Threshold + - type: DeltaPressure + minPressure: 37500 + minPressureDelta: 25000 + scalingType: Threshold ## For phoron glass windows (2x better than plasma) - type: entity abstract: true id: BaseDeltaPressurePhoronGlass components: - - type: DeltaPressure - minPressure: 150000 - minPressureDelta: 100000 - scalingType: Linear - scalingPower: 0.0005 + - type: DeltaPressure + minPressure: 150000 + minPressureDelta: 100000 + scalingType: Linear + scalingPower: 0.0005 ## For reinforced phoron glass windows (2x better than reinforced plasma) - type: entity abstract: true id: BaseDeltaPressureReinforcedPhoronGlass components: - - type: DeltaPressure - minPressure: 300000 - minPressureDelta: 200000 - scalingType: Linear - scalingPower: 0.0001 + - type: DeltaPressure + minPressure: 300000 + minPressureDelta: 200000 + scalingType: Linear + scalingPower: 0.0001 ## For plasma windows - type: entity abstract: true id: BaseDeltaPressurePlasma components: - - type: DeltaPressure - minPressure: 75000 - minPressureDelta: 50000 - scalingType: Linear - scalingPower: 0.0005 + - type: DeltaPressure + minPressure: 75000 + minPressureDelta: 50000 + scalingType: Linear + scalingPower: 0.0005 ## For quarter plasma windows - type: entity abstract: true id: BaseDeltaPressurePlasmaQuarter components: - - type: DeltaPressure - minPressure: 18750 - minPressureDelta: 12500 - scalingType: Threshold + - type: DeltaPressure + minPressure: 18750 + minPressureDelta: 12500 + scalingType: Threshold ## For reinforced glass windows - type: entity abstract: true id: BaseDeltaPressureReinforcedGlass components: - - type: DeltaPressure - minPressure: 15000 - minPressureDelta: 10000 - scalingType: Threshold + - type: DeltaPressure + minPressure: 15000 + minPressureDelta: 10000 + scalingType: Threshold ## For quarter reinforced glass windows - type: entity abstract: true id: BaseDeltaPressureReinforcedGlassQuarter components: - - type: DeltaPressure - minPressure: 3750 - minPressureDelta: 2500 + - type: DeltaPressure + minPressure: 3750 + minPressureDelta: 2500 ## For glass windows - type: entity abstract: true id: BaseDeltaPressureGlass components: - - type: DeltaPressure - minPressure: 1000 - minPressureDelta: 750 - scalingType: Linear - scalingPower: 0.0005 + - type: DeltaPressure + minPressure: 1000 + minPressureDelta: 750 + scalingType: Linear + scalingPower: 0.0005 ## For quarter glass windows - type: entity abstract: true id: BaseDeltaPressureGlassQuarter components: - - type: DeltaPressure - minPressure: 250 - minPressureDelta: 187.5 - scalingType: Threshold + - type: DeltaPressure + minPressure: 250 + minPressureDelta: 187.5 + scalingType: Threshold - type: entity abstract: true id: BaseDeltaPressureFans components: - - type: DeltaPressure - minPressure: 200 - minPressureDelta: 150 - scalingType: Linear + - type: DeltaPressure + minPressure: 200 + minPressureDelta: 150 + scalingType: Linear