Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Content.Shared/Nutrition/Components/EdibleComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ public sealed partial class EdibleComponent : Component
[DataField]
public bool RequireDead = true;

/// <summary>
/// Maximum hunger value this food can bring the eater to.
/// If null, there is no cap (fully satisfying food, e.g. cooked meals).
/// If set, food acts as a snack and cannot push hunger above this value.
/// </summary>
[DataField]
public float? MaxNutrition = null;

/// <summary>
/// Verb, icon, and sound data for our edible.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions Content.Shared/Nutrition/Components/HungerComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ public sealed partial class HungerComponent : Component
[DataField, ViewVariables(VVAccess.ReadOnly)]
public float? StartingHunger = null;

/// <summary>
/// Goobstation
/// Active hunger cap set when eating snack food (food with EdibleComponent.MaxNutrition).
/// Hunger cannot be raised above this value while the cap is active.
/// Cleared to null when eating fully satisfying (cooked) food.
/// </summary>
[DataField]
[AutoNetworkedField]
public float? NutritionCap = null;

/// <summary>
/// A dictionary relating HungerThreshold to the amount of <see cref="HungerSystem.GetHunger">current hunger</see> needed for each one
/// </summary>
Expand Down
27 changes: 26 additions & 1 deletion Content.Shared/Nutrition/EntitySystems/HungerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,10 @@ public void ModifyHunger(EntityUid uid, float amount, HungerComponent? component
{
if (!Resolve(uid, ref component))
return;
SetHunger(uid, GetHunger(component) + amount, component);
var newHunger = GetHunger(component) + amount;
if (component.NutritionCap.HasValue)
newHunger = Math.Min(newHunger, component.NutritionCap.Value);
SetHunger(uid, newHunger, component);
}

/// <summary>
Expand Down Expand Up @@ -299,6 +302,28 @@ public HungerThreshold GetHungerThreshold(HungerComponent component, float? food
return result;
}

/// <summary>
/// Goobstation — sets or raises the active nutrition cap for snack food.
/// </summary>
public void SetNutritionCap(EntityUid uid, float cap, HungerComponent? component = null)
{
if (!Resolve(uid, ref component))
return;
component.NutritionCap = Math.Max(component.NutritionCap ?? 0f, cap);
DirtyField(uid, component, nameof(HungerComponent.NutritionCap));
}

/// <summary>
/// Goobstation — clears the active nutrition cap (called when eating fully satisfying food).
/// </summary>
public void ClearNutritionCap(EntityUid uid, HungerComponent? component = null)
{
if (!Resolve(uid, ref component))
return;
component.NutritionCap = null;
DirtyField(uid, component, nameof(HungerComponent.NutritionCap));
}

/// <summary>
/// A check that returns if the entity is below a hunger threshold.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions Content.Shared/Nutrition/EntitySystems/IngestionSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public sealed partial class IngestionSystem : EntitySystem
[Dependency] private readonly SharedBodySystem _body = default!;
[Dependency] private readonly ReactiveSystem _reaction = default!;
[Dependency] private readonly StomachSystem _stomach = default!;
[Dependency] private readonly HungerSystem _hungerSystem = default!;

/// <inheritdoc/>
public override void Initialize()
Expand Down Expand Up @@ -368,6 +369,15 @@ private void OnEatingDoAfter(Entity<BodyComponent> entity, ref EatingDoAfterEven

_reaction.DoEntityReaction(entity, split, ReactionMethod.Ingestion);

// Goobstation — update NutritionCap based on whether this food is a snack
if (TryComp(food, out EdibleComponent? edibleComp))
{
if (edibleComp.MaxNutrition.HasValue)
_hungerSystem.SetNutritionCap(entity, edibleComp.MaxNutrition.Value);
else
_hungerSystem.ClearNutritionCap(entity);
}

// Everything is good to go item has been successfuly eaten
var afterEv = new IngestedEvent(args.User, entity, split, forceFed);
RaiseLocalEvent(food, ref afterEv);
Expand Down
20 changes: 0 additions & 20 deletions Resources/Prototypes/Catalog/Cargo/cargo_food.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,6 @@
#
# SPDX-License-Identifier: MIT

- type: cargoProduct
id: FoodPizza
icon:
sprite: Objects/Consumable/Food/Baked/pizza.rsi
state: margherita-slice
product: CrateFoodPizza
cost: 1600
category: cargoproduct-category-name-food
group: market

- type: cargoProduct
id: FoodPizzaLarge
icon:
sprite: Objects/Consumable/Food/Baked/pizza.rsi
state: margherita
product: CrateFoodPizzaLarge
cost: 1800
category: cargoproduct-category-name-food
group: market

- type: cargoProduct
id: FoodMRE
icon:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@
- type: Tag
tags:
- FoodSnack
- type: Edible
maxNutrition: 100.0
- type: Sprite
sprite: Objects/Consumable/Food/snacks.rsi
- type: SolutionContainerManager
Expand Down
50 changes: 0 additions & 50 deletions Resources/Prototypes/GameRules/cargo_gifts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
- id: GiftsFireProtection
- id: GiftsJanitor
- id: GiftsMedical
- id: GiftsPizzaPartyLarge
- id: GiftsPizzaPartySmall
- id: GiftsSecurityGuns
- id: GiftsSecurityRiot
- id: GiftsSpacingSupplies
Expand All @@ -49,54 +47,6 @@
- type: CargoGiftsRule
sender: cargo-gift-default-sender

- type: entity
id: GiftsPizzaPartySmall
parent: CargoGiftsBase
components:
- type: StationEvent
weight: 5
duration: 120
earliestStart: 20
chaos: # Goobstation
Hunger: -80
Thirst: -40
eventType: FreeStuff # Goobstation
# Goobstation
- type: GameRule
chaosScore: -15
- type: CargoGiftsRule
description: cargo-gift-pizza-small
dest: cargo-gift-dest-bar
gifts:
FoodPizza: 2 # 8 pizzas
FoodBarSupply: 1
FoodSoftdrinks: 2
CrateVendingMachineRestockRobustSoftdrinks: 1

- type: entity
id: GiftsPizzaPartyLarge
parent: CargoGiftsBase
components:
- type: StationEvent
weight: 2
duration: 240
earliestStart: 20
minimumPlayers: 40
chaos: # Goobstation
Hunger: -300
Thirst: -120
eventType: FreeStuff # Goobstation
# Goobstation
- type: GameRule
chaosScore: -30
- type: CargoGiftsRule
description: cargo-gift-pizza-large
dest: cargo-gift-dest-bar
gifts:
FoodPizzaLarge: 1 # 16 pizzas
FoodBarSupply: 1
FoodSoftdrinksLarge: 1

- type: entity
id: GiftsEngineering
parent: CargoGiftsBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@
conditions:
- !type:StorageWelded
welded: false
- !type:Locked
locked: false
completed:
- !type:SpawnPrototype
prototype: SheetSteel1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-FileCopyrightText: 2025 Goob-Station
#
# SPDX-License-Identifier: AGPL-3.0-or-later

# FoodSnackBase is defined in upstream snacks.yml with maxNutrition via Edible component.
# No additional definitions needed here.
Loading