+++ /dev/null
-using Content.Shared.Nutrition.EntitySystems;
-
-namespace Content.Client.Nutrition.EntitySystems;
-
-public sealed class DrinkSystem : SharedDrinkSystem
-{
-}
/// This component prevents NPC mobs like mice or cows from wanting to drink something that shouldn't be drank from.
/// Including but not limited to: puddles
/// </summary>
-[RegisterComponent, Access(typeof(DrinkSystem))]
-public sealed partial class BadDrinkComponent : Component
-{
-}
+[RegisterComponent]
+public sealed partial class BadDrinkComponent : Component;
+++ /dev/null
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Chemistry.Components.SolutionManager;
-using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.Nutrition.Components;
-using Content.Shared.Nutrition.EntitySystems;
-
-
-namespace Content.Server.Nutrition.EntitySystems;
-
-public sealed class DrinkSystem : SharedDrinkSystem
-{
- [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
- [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- // TODO add InteractNoHandEvent for entities like mice.
- SubscribeLocalEvent<DrinkComponent, SolutionContainerChangedEvent>(OnSolutionChange);
- SubscribeLocalEvent<DrinkComponent, ComponentInit>(OnDrinkInit);
- // run before inventory so for bucket it always tries to drink before equipping (when empty)
- // run after openable so its always open -> drink
- }
-
- private void OnDrinkInit(Entity<DrinkComponent> entity, ref ComponentInit args)
- {
- if (TryComp<DrainableSolutionComponent>(entity, out var existingDrainable))
- {
- // Beakers have Drink component but they should use the existing Drainable
- entity.Comp.Solution = existingDrainable.Solution;
- }
- else
- {
- _solutionContainer.EnsureSolution(entity.Owner, entity.Comp.Solution, out _);
- }
-
- UpdateAppearance(entity, entity.Comp);
-
- if (TryComp(entity, out RefillableSolutionComponent? refillComp))
- refillComp.Solution = entity.Comp.Solution;
-
- if (TryComp(entity, out DrainableSolutionComponent? drainComp))
- drainComp.Solution = entity.Comp.Solution;
- }
-
- private void OnSolutionChange(Entity<DrinkComponent> entity, ref SolutionContainerChangedEvent args)
- {
- UpdateAppearance(entity, entity.Comp);
- }
-
- public void UpdateAppearance(EntityUid uid, DrinkComponent component)
- {
- if (!TryComp<AppearanceComponent>(uid, out var appearance) ||
- !HasComp<SolutionContainerManagerComponent>(uid))
- {
- return;
- }
-
- var drainAvailable = DrinkVolume(uid, component);
- _appearance.SetData(uid, FoodVisuals.Visual, drainAvailable.Float(), appearance);
- }
-}
+++ /dev/null
-using Content.Shared.Nutrition.EntitySystems;
-using Content.Shared.FixedPoint;
-using Robust.Shared.Audio;
-using Robust.Shared.GameStates;
-
-namespace Content.Shared.Nutrition.Components;
-
-[Obsolete("Migration to Content.Shared.Nutrition.Components.EdibleComponent is required")]
-[NetworkedComponent, AutoGenerateComponentState]
-[RegisterComponent, Access(typeof(SharedDrinkSystem))]
-public sealed partial class DrinkComponent : Component
-{
- [DataField]
- public string Solution = "drink";
-
- [DataField, AutoNetworkedField]
- public SoundSpecifier UseSound = new SoundPathSpecifier("/Audio/Items/drink.ogg");
-
- [DataField, AutoNetworkedField]
- public FixedPoint2 TransferAmount = FixedPoint2.New(5);
-
- /// <summary>
- /// How long it takes to drink this yourself.
- /// </summary>
- [DataField, AutoNetworkedField]
- public float Delay = 1;
-
- /// <summary>
- /// If true, trying to drink when empty will not handle the event.
- /// This means other systems such as equipping on use can run.
- /// Example usecase is the bucket.
- /// </summary>
- [DataField]
- public bool IgnoreEmpty;
-
- /// <summary>
- /// This is how many seconds it takes to force feed someone this drink.
- /// </summary>
- [DataField, AutoNetworkedField]
- public float ForceFeedDelay = 3;
-}
//Prevents food usage with a wrong utensil
if ((ev.Types & utensil.Comp.Types) == 0)
{
- _popup.PopupClient(Loc.GetString("ingestion-try-use-wrong-utensil", ("verb", GetEdibleVerb(target)),("food", target), ("utensil", utensil.Owner)), user, user);
+ _popup.PopupClient(Loc.GetString("ingestion-try-use-wrong-utensil", ("verb", GetEdibleVerb(target)), ("food", target), ("utensil", utensil.Owner)), user, user);
return true;
}
return;
// TODO: Once we have predicted randomness delete this for something sane...
- var seed = SharedRandomExtensions.HashCodeCombine(new() {(int)_timing.CurTick.Value, GetNetEntity(entity).Id, GetNetEntity(userUid).Id });
+ var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(entity).Id, GetNetEntity(userUid).Id });
var rand = new System.Random(seed);
if (!rand.Prob(entity.Comp.BreakChance))
return;
_audio.PlayPredicted(entity.Comp.BreakSound, userUid, userUid, AudioParams.Default.WithVolume(-2f));
- // Not prediced because no random predicted
PredictedDel(entity.Owner);
}
private void OnEdibleInit(Entity<EdibleComponent> entity, ref ComponentInit args)
{
- // TODO: When Food and Drink component are kill make sure to nuke both TryComps and just have it update appearance...
- // Beakers, Soap and other items have drainable, and we should be able to eat that solution...
- // If I could make drainable properly support sound effects and such I'd just have it use TryIngest itself
- // Does this exist just to make tests fail? That way you have the proper yaml???
+ // Beakers, Soap and other items have drainable, and we should be able to eat that solution.
+ // This ensures that tests fail when you configured the yaml from and EdibleComponent uses the wrong solution,
if (TryComp<DrainableSolutionComponent>(entity, out var existingDrainable))
entity.Comp.Solution = existingDrainable.Solution;
+ else
+ _solutionContainer.EnsureSolution(entity.Owner, entity.Comp.Solution, out _);
UpdateAppearance(entity);
if (!forceFed)
return;
- _popup.PopupClient(Loc.GetString("ingestion-other-cannot-ingest-any-more", ("target", entity), ("verb", GetEdibleVerb(food))), args.Target.Value, args.User);
+ _popup.PopupClient(Loc.GetString("ingestion-other-cannot-ingest-any-more", ("target", entity), ("verb", GetEdibleVerb(food))), args.Target.Value, args.User);
return;
}
if (!forceFed)
return;
- _popup.PopupClient(Loc.GetString("ingestion-other-cannot-ingest-any-more", ("target", entity), ("verb", GetEdibleVerb(food))), args.Target.Value, args.User);
+ _popup.PopupClient(Loc.GetString("ingestion-other-cannot-ingest-any-more", ("target", entity), ("verb", GetEdibleVerb(food))), args.Target.Value, args.User);
return;
}
_popup.PopupClient(Loc.GetString("edible-force-feed-success-user", ("target", targetName), ("verb", edible.Verb)), args.User, args.User);
// log successful forced feeding
+ // TODO: Use correct verb
_adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity):user} forced {ToPrettyString(args.User):target} to eat {ToPrettyString(entity):food}");
}
else
args.User);
// log successful voluntary eating
+ // TODO: Use correct verb
+ // the past tense is tricky here
+ // localized admin logs when?
_adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} ate {ToPrettyString(entity):food}");
}
+++ /dev/null
-using Content.Shared.Administration.Logs;
-using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.Database;
-using Content.Shared.FixedPoint;
-using Content.Shared.Forensics;
-using Content.Shared.IdentityManagement;
-using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
-using Content.Shared.Inventory;
-using Content.Shared.Nutrition.Components;
-using Content.Shared.Popups;
-using Content.Shared.Verbs;
-using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Player;
-
-namespace Content.Shared.Nutrition.EntitySystems;
-
-[Obsolete("Migration to Content.Shared.Nutrition.EntitySystems.IngestionSystem is required")]
-public abstract partial class SharedDrinkSystem : EntitySystem
-{
- [Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
- [Dependency] private readonly FlavorProfileSystem _flavorProfile = default!;
- [Dependency] private readonly IngestionSystem _ingestion = default!;
- [Dependency] private readonly SharedPopupSystem _popup = default!;
- [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent<DrinkComponent, UseInHandEvent>(OnUseDrinkInHand, after: new[] { typeof(OpenableSystem), typeof(InventorySystem) });
- SubscribeLocalEvent<DrinkComponent, AfterInteractEvent>(OnUseDrink);
-
- SubscribeLocalEvent<DrinkComponent, AttemptShakeEvent>(OnAttemptShake);
-
- SubscribeLocalEvent<DrinkComponent, GetVerbsEvent<AlternativeVerb>>(AddDrinkVerb);
-
- SubscribeLocalEvent<DrinkComponent, BeforeIngestedEvent>(OnBeforeDrinkEaten);
- SubscribeLocalEvent<DrinkComponent, IngestedEvent>(OnDrinkEaten);
-
- SubscribeLocalEvent<DrinkComponent, EdibleEvent>(OnDrink);
-
- SubscribeLocalEvent<DrinkComponent, IsDigestibleEvent>(OnIsDigestible);
-
- SubscribeLocalEvent<DrinkComponent, GetEdibleTypeEvent>(OnGetEdibleType);
- }
-
- protected void OnAttemptShake(Entity<DrinkComponent> entity, ref AttemptShakeEvent args)
- {
- if (IsEmpty(entity, entity.Comp))
- args.Cancelled = true;
- }
-
- protected FixedPoint2 DrinkVolume(EntityUid uid, DrinkComponent? component = null)
- {
- if (!Resolve(uid, ref component))
- return FixedPoint2.Zero;
-
- if (!_solutionContainer.TryGetSolution(uid, component.Solution, out _, out var sol))
- return FixedPoint2.Zero;
-
- return sol.Volume;
- }
-
- protected bool IsEmpty(EntityUid uid, DrinkComponent? component = null)
- {
- if (!Resolve(uid, ref component))
- return true;
-
- return DrinkVolume(uid, component) <= 0;
- }
-
- /// <summary>
- /// Eat or drink an item
- /// </summary>
- private void OnUseDrinkInHand(Entity<DrinkComponent> entity, ref UseInHandEvent ev)
- {
- if (ev.Handled)
- return;
-
- ev.Handled = _ingestion.TryIngest(ev.User, ev.User, entity);
- }
-
- /// <summary>
- /// Feed someone else
- /// </summary>
- private void OnUseDrink(Entity<DrinkComponent> entity, ref AfterInteractEvent args)
- {
- if (args.Handled || args.Target == null || !args.CanReach)
- return;
-
- args.Handled = _ingestion.TryIngest(args.User, args.Target.Value, entity);
- }
-
- private void AddDrinkVerb(Entity<DrinkComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
- {
- var user = args.User;
-
- if (entity.Owner == user || !args.CanInteract || !args.CanAccess)
- return;
-
- if (!_ingestion.TryGetIngestionVerb(user, entity, IngestionSystem.Drink, out var verb))
- return;
-
- args.Verbs.Add(verb);
- }
-
- private void OnBeforeDrinkEaten(Entity<DrinkComponent> food, ref BeforeIngestedEvent args)
- {
- if (args.Cancelled)
- return;
-
- // Set it to transfer amount if it exists, otherwise eat the whole volume if possible.
- args.Transfer = food.Comp.TransferAmount;
- }
-
- private void OnDrinkEaten(Entity<DrinkComponent> entity, ref IngestedEvent args)
- {
- if (args.Handled)
- return;
-
- args.Handled = true;
-
- _audio.PlayPredicted(entity.Comp.UseSound, args.Target, args.User, AudioParams.Default.WithVolume(-2f).WithVariation(0.25f));
-
- var flavors = _flavorProfile.GetLocalizedFlavorsMessage(entity.Owner, args.Target, args.Split);
-
- if (args.ForceFed)
- {
- var targetName = Identity.Entity(args.Target, EntityManager);
- var userName = Identity.Entity(args.User, EntityManager);
-
- _popup.PopupEntity(Loc.GetString("edible-force-feed-success", ("user", userName), ("verb", _ingestion.GetProtoVerb(IngestionSystem.Drink)), ("flavors", flavors)), entity, entity);
-
- _popup.PopupClient(Loc.GetString("edible-force-feed-success-user", ("target", targetName), ("verb", _ingestion.GetProtoVerb(IngestionSystem.Drink))), args.User, args.User);
-
- // log successful forced drinking
- _adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity.Owner):user} forced {ToPrettyString(args.User):target} to drink {ToPrettyString(entity.Owner):drink}");
- }
- else
- {
- _popup.PopupPredicted(Loc.GetString("edible-slurp", ("flavors", flavors)),
- Loc.GetString("edible-slurp-other"),
- args.User,
- args.User);
-
- // log successful voluntary drinking
- _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} drank {ToPrettyString(entity.Owner):drink}");
- }
-
- if (_ingestion.GetUsesRemaining(entity, entity.Comp.Solution, args.Split.Volume) <= 0)
- return;
-
- // Leave some of the consumer's DNA on the consumed item...
- var ev = new TransferDnaEvent
- {
- Donor = args.Target,
- Recipient = entity,
- CanDnaBeCleaned = false,
- };
- RaiseLocalEvent(args.Target, ref ev);
-
- args.Repeat = !args.ForceFed;
- }
-
- private void OnDrink(Entity<DrinkComponent> drink, ref EdibleEvent args)
- {
- if (args.Cancelled || args.Solution != null)
- return;
-
- if (!_solutionContainer.TryGetSolution(drink.Owner, drink.Comp.Solution, out args.Solution) || IsEmpty(drink))
- {
- args.Cancelled = true;
-
- _popup.PopupClient(Loc.GetString("ingestion-try-use-is-empty", ("entity", drink)), drink, args.User);
- return;
- }
-
- args.Time += TimeSpan.FromSeconds(drink.Comp.Delay);
- }
-
- private void OnIsDigestible(Entity<DrinkComponent> ent, ref IsDigestibleEvent args)
- {
- // Anyone can drink from puddles on the floor!
- args.UniversalDigestion();
- }
-
- private void OnGetEdibleType(Entity<DrinkComponent> ent, ref GetEdibleTypeEvent args)
- {
- if (args.Type != null)
- return;
-
- args.SetPrototype(IngestionSystem.Drink);
- }
-}
- type: Transform
pos: -45.5,-61.5
parent: 2
- - type: Drink
- useSound: !type:SoundPathSpecifier
- path: /Audio/Items/drink.ogg
+ - type: Edible
+ edible: Drink
solution: pool
+ destroyOnEmpty: false
+ utensil: Spoon
- uid: 16868
components:
- type: Transform
pos: -44.5,-61.5
parent: 2
- - type: Drink
- useSound: !type:SoundPathSpecifier
- path: /Audio/Items/drink.ogg
+ - type: Edible
+ edible: Drink
solution: pool
+ destroyOnEmpty: false
+ utensil: Spoon
- uid: 16872
components:
- type: Transform
pos: -46.5,-61.5
parent: 2
- - type: Drink
- useSound: !type:SoundPathSpecifier
- path: /Audio/Items/drink.ogg
+ - type: Edible
+ edible: Drink
solution: pool
+ destroyOnEmpty: false
+ utensil: Spoon
- uid: 16907
components:
- type: Transform
pos: -44.5,-60.5
parent: 2
- - type: Drink
- useSound: !type:SoundPathSpecifier
- path: /Audio/Items/drink.ogg
+ - type: Edible
+ edible: Drink
solution: pool
+ destroyOnEmpty: false
+ utensil: Spoon
- uid: 17621
components:
- type: Transform
solution: drink
delay: 0.5
forceFeedDelay: 1.5
+ utensil: Spoon
- type: FlavorProfile
flavors:
- water
delay: 3
transferAmount: 1
solution: puddle
+ utensil: None
- type: ExaminableSolution
solution: puddle
locVolume: "examinable-solution-on-examine-volume-puddle"
id: DrinkTomatoJuice
suffix: tomato juice
components:
- - type: Drink
- type: SolutionContainerManager
solutions:
drink:
edible: Drink
solution: food
destroyOnEmpty: false
+ utensil: Spoon
- type: DamageOnLand
damage:
types:
components:
- type: Item
size: Tiny
- - type: Drink
+ - type: Edible
+ edible: Food # usually contains powders like flour or condiments like ketchup
solution: food
+ destroyOnEmpty: false
+ utensil: Spoon
- type: Openable
sound:
collection: packetOpenSounds
- type: ExaminableSolution
exactVolume: true
+- type: entity
+ parent: BaseFoodCondimentPacket
+ id: BaseFoodCondimentPacketDrink
+ abstract: true
+ components:
+ - type: Edible
+ edible: Drink # slurping sounds!
+
- type: entity
parent: BaseFoodCondimentPacket
id: FoodCondimentPacketAstrotame
fillBaseName: packet-trans-
- type: entity
- parent: BaseFoodCondimentPacket
+ parent: BaseFoodCondimentPacketDrink
id: FoodCondimentPacketBbq
name: BBQ sauce
description: Hand wipes not included.
fillBaseName: packet-trans-
- type: entity
- parent: BaseFoodCondimentPacket
+ parent: BaseFoodCondimentPacketDrink
id: FoodCondimentPacketCornoil
name: corn oil
description: Corn oil. A delicious oil used in cooking. Made from corn.
fillBaseName: packet-trans-
- type: entity
- parent: BaseFoodCondimentPacket
+ parent: BaseFoodCondimentPacketDrink
id: FoodCondimentPacketColdsauce
name: coldsauce
description: Coldsauce. Leaves the tongue numb in its passage.
fillBaseName: packet-trans-
- type: entity
- parent: BaseFoodCondimentPacket
+ parent: BaseFoodCondimentPacketDrink
id: FoodCondimentPacketHorseradish
name: horseradish sauce
description: A packet of smelly horseradish sauce.
fillBaseName: packet-solid-
- type: entity
- parent: BaseFoodCondimentPacket
+ parent: BaseFoodCondimentPacketDrink
id: FoodCondimentPacketHotsauce
name: hotsauce
description: You can almost TASTE the stomach ulcers now!
fillBaseName: packet-trans-
- type: entity
- parent: BaseFoodCondimentPacket
+ parent: BaseFoodCondimentPacketDrink
id: FoodCondimentPacketKetchup
name: ketchup
description: You feel more American already.
fillBaseName: packet-solid-
- type: entity
- parent: BaseFoodCondimentPacket
+ parent: BaseFoodCondimentPacketDrink
id: FoodCondimentPacketMustard
name: mustard
description: A condiment made from the ground-up seeds of the Mustard plant.
fillBaseName: packet-solid-
- type: entity
- parent: BaseFoodCondimentPacket
+ parent: BaseFoodCondimentPacketDrink
id: FoodCondimentPacketSoy
name: soy sauce
description: A salty soy-based flavoring.
name: condiment bottle
description: A thin glass bottle used to store condiments.
components:
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: food
+ destroyOnEmpty: false
+ utensil: None
- type: Openable
sound:
collection: pop
# Shakers
- type: entity
- parent: BaseFoodCondiment
+ parent: BaseFoodCondiment # TODO: This should not inherit TrashOnSolutionEmpty, SpaceGarbage and the price of 0
id: BaseFoodShaker
abstract: true
name: empty shaker
components:
- type: Item
size: Tiny
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: food
+ destroyOnEmpty: false
+ utensil: None # don't conflict with stirring
- type: SolutionContainerManager
solutions:
food:
solution: food
- type: DrainableSolution
solution: food
- - type: Drink
+ - type: Edible
+ edible: Food # usually contains powders like flour or condiments like ketchup
solution: food
- useSound:
- collection: eating
+ utensil: Spoon
- type: Damageable
damageContainer: Inorganic
- type: Spillable
reagents:
- ReagentId: OilOlive
Quantity: 20
+ - type: Edible
+ edible: Drink # slurping sounds!
- type: entity
parent: ReagentPacketBase
- type: SolutionContainerManager
- type: Sprite
state: produce
- # let cows eat raw produce like wheat and oats
- - type: Edible
- requiresSpecialDigestion: true
- type: Produce
- type: PotencyVisuals
- type: Appearance
- type: Extractable
grindableSolutionName: food
+
+- type: entity
+ parent: ProduceBase
+ id: ProduceBaseRuminant
+ abstract: true
+ components:
+ # let cows eat raw produce like wheat and oats
+ - type: Edible
+ requiresSpecialDigestion: true
- type: Tag
tags:
- Ruminant
name: wheat bushel
description: Sigh... wheat... a-grain?
id: WheatBushel
- parent: ProduceBase
+ parent: ProduceBaseRuminant
components:
- type: Sprite
sprite: Objects/Specific/Hydroponics/wheat.rsi
name: meatwheat bushel
description: Some blood-drenched wheat stalks. You can crush them into what passes for meat if you squint hard enough.
id: MeatwheatBushel
- parent: ProduceBase
+ parent: ProduceBaseRuminant
components:
- type: Sprite
sprite: Objects/Specific/Hydroponics/meatwheat.rsi
name: oat bushel
description: Eat oats, do squats.
id: OatBushel
- parent: ProduceBase
+ parent: ProduceBaseRuminant
components:
- type: Sprite
sprite: Objects/Specific/Hydroponics/oat.rsi
name: sugarcane
description: Sickly sweet.
id: Sugarcane
- parent: ProduceBase
+ parent: ProduceBaseRuminant
components:
- type: Sprite
sprite: Objects/Specific/Hydroponics/sugarcane.rsi
name: nettle
description: Stingy little prick.
id: Nettle
- parent: ProduceBase
+ parent: ProduceBaseRuminant
components:
- type: Sprite
sprite: Objects/Specific/Hydroponics/nettle.rsi
name: rice bushel
description: Can be ground into rice, perfect for pudding or sake.
id: RiceBushel
- parent: ProduceBase
+ parent: ProduceBaseRuminant
components:
- type: Sprite
sprite: Objects/Specific/Hydroponics/rice.rsi
name: soybeans
description: For those who can't stand seeing good old meat.
id: FoodSoybeans
- parent: ProduceBase
+ parent: ProduceBaseRuminant
components:
- type: Sprite
sprite: Objects/Specific/Hydroponics/soybeans.rsi
name: koibean
description: These beans seem a little bit fishy.
id: FoodKoibean
- parent: ProduceBase
+ parent: ProduceBaseRuminant
components:
- type: Sprite
sprite: Objects/Specific/Hydroponics/koibean.rsi
- type: entity
name: cannabis leaves
- parent: ProduceBase
+ parent: ProduceBaseRuminant
id: LeavesCannabis
description: "Recently legalized in most galaxies."
components:
- type: entity
name: tea leaves
- parent: ProduceBase
+ parent: ProduceBaseRuminant
id: LeavesTea
description: "Can be dried out to make tea."
components:
- type: entity
name: dried tea leaves
- parent: ProduceBase
+ parent: ProduceBaseRuminant
id: LeavesTeaDried
description: "Dried tea leaves, ready to be ground."
components:
- type: entity
name: tobacco leaves
- parent: ProduceBase
+ parent: ProduceBaseRuminant
id: LeavesTobacco
description: "Dry them out to make some smokes."
components:
sprite: Objects/Specific/Hydroponics/tobacco.rsi
- type: Produce
seedId: tobacco
+ - type: SolutionContainerManager
+ solutions:
+ food:
+ reagents:
+ - ReagentId: Nicotine
+ Quantity: 2
- type: entity
name: dried tobacco leaves
suffix: Empty
description: A spray bottle with an unscrewable top.
components:
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: spray
- ignoreEmpty: true
+ destroyOnEmpty: false
+ utensil: None
+ transferAmount: 10
useSound:
path: /Audio/Effects/spray3.ogg
- transferAmount: 10
+ params:
+ variation: 0.2
- type: Tag
tags:
- Spray
interfaces:
enum.TransferAmountUiKey.Key:
type: TransferAmountBoundUserInterface
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: beaker
+ destroyOnEmpty: false
+ utensil: Spoon
- type: Spillable
solution: beaker
- type: Appearance
- type: SolutionContainerVisuals
maxFillLevels: 6
fillBaseName: bottle-1-
- - type: Drink
+ - type: Edible
+ edible: Drink
+ solution: drink
+ destroyOnEmpty: false
+ utensil: None
- type: SolutionContainerManager
solutions:
drink: # This solution name and target volume is hard-coded in ChemMasterComponent
fillBaseName: vial-1-
inHandsMaxFillLevels: 4
inHandsFillBaseName: -fill-
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: beaker
+ destroyOnEmpty: false
+ utensil: None
- type: SolutionContainerManager
solutions:
beaker:
interfaces:
enum.TransferAmountUiKey.Key:
type: TransferAmountBoundUserInterface
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: beaker
+ destroyOnEmpty: false
+ utensil: None
- type: Appearance
- type: SolutionContainerVisuals
maxFillLevels: 6
interfaces:
enum.TransferAmountUiKey.Key:
type: TransferAmountBoundUserInterface
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: beaker
+ destroyOnEmpty: false
+ utensil: Spoon
- type: Appearance
- type: SolutionContainerVisuals
maxFillLevels: 6
edible: Drink
solution: bucket
destroyOnEmpty: false
+ utensil: Spoon
- type: Sprite
sprite: Objects/Tools/bucket.rsi
layers:
- Honk
- Carpetium
- JuiceThatMakesYouWeh
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: anomaly
+ destroyOnEmpty: false
+ utensil: Spoon
- type: DrainableSolution
solution: anomaly
- type: DrawableSolution
- type: ReactiveContainer
solution: bucket
container: item_slot
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: bucket
+ destroyOnEmpty: false
+ utensil: Spoon
- type: Appearance
- type: SolutionContainerVisuals
maxFillLevels: 3
interfaces:
enum.StorageUiKey.Key:
type: StorageBoundUserInterface
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: bucket
+ destroyOnEmpty: false
+ utensil: Spoon
- type: ContainerContainer
containers:
storagebase: !type:Container
solution: beaker
- type: SolutionTransfer
canChangeTransferAmount: true
- - type: Drink
+ - type: Edible
+ edible: Drink
solution: beaker
+ destroyOnEmpty: false
+ utensil: None
- type: entity
id: XenoArtifactSpeedUp