Special digestion & kudzu-eating (#16061)
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
|
|
||||||
namespace Content.Server.Body.Components
|
namespace Content.Server.Body.Components
|
||||||
{
|
{
|
||||||
[RegisterComponent, Access(typeof(StomachSystem))]
|
[RegisterComponent, Access(typeof(StomachSystem), typeof(FoodSystem))]
|
||||||
public sealed class StomachComponent : Component
|
public sealed class StomachComponent : Component
|
||||||
{
|
{
|
||||||
public float AccumulatedFrameTime;
|
public float AccumulatedFrameTime;
|
||||||
@@ -20,12 +22,6 @@ namespace Content.Server.Body.Components
|
|||||||
[DataField("bodySolutionName")]
|
[DataField("bodySolutionName")]
|
||||||
public string BodySolutionName = BloodstreamComponent.DefaultChemicalsSolutionName;
|
public string BodySolutionName = BloodstreamComponent.DefaultChemicalsSolutionName;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initial internal solution storage volume
|
|
||||||
/// </summary>
|
|
||||||
[DataField("initialMaxVolume", readOnly: true)]
|
|
||||||
public readonly FixedPoint2 InitialMaxVolume = FixedPoint2.New(50);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time in seconds between reagents being ingested and them being
|
/// Time in seconds between reagents being ingested and them being
|
||||||
/// transferred to <see cref="BloodstreamComponent"/>
|
/// transferred to <see cref="BloodstreamComponent"/>
|
||||||
@@ -33,6 +29,12 @@ namespace Content.Server.Body.Components
|
|||||||
[DataField("digestionDelay")]
|
[DataField("digestionDelay")]
|
||||||
public float DigestionDelay = 20;
|
public float DigestionDelay = 20;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A whitelist for what special-digestible-required foods this stomach is capable of eating.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("specialDigestible")]
|
||||||
|
public EntityWhitelist? SpecialDigestible = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to track how long each reagent has been in the stomach
|
/// Used to track how long each reagent has been in the stomach
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ namespace Content.Server.Body.Systems
|
|||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<StomachComponent, ComponentInit>(OnComponentInit);
|
|
||||||
SubscribeLocalEvent<StomachComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
|
SubscribeLocalEvent<StomachComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,11 +86,6 @@ namespace Content.Server.Body.Systems
|
|||||||
component.AccumulatedFrameTime = component.UpdateInterval;
|
component.AccumulatedFrameTime = component.UpdateInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentInit(EntityUid uid, StomachComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
_solutionContainerSystem.EnsureSolution(uid, DefaultSolutionName, component.InitialMaxVolume, out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanTransferSolution(EntityUid uid, Solution solution,
|
public bool CanTransferSolution(EntityUid uid, Solution solution,
|
||||||
SolutionContainerManagerComponent? solutions = null)
|
SolutionContainerManagerComponent? solutions = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Server.NPC.Queries.Considerations;
|
|||||||
using Content.Server.NPC.Queries.Curves;
|
using Content.Server.NPC.Queries.Curves;
|
||||||
using Content.Server.NPC.Queries.Queries;
|
using Content.Server.NPC.Queries.Queries;
|
||||||
using Content.Server.Nutrition.Components;
|
using Content.Server.Nutrition.Components;
|
||||||
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
using Content.Server.Storage.Components;
|
using Content.Server.Storage.Components;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
@@ -24,6 +25,7 @@ public sealed class NPCUtilitySystem : EntitySystem
|
|||||||
[Dependency] private readonly FactionSystem _faction = default!;
|
[Dependency] private readonly FactionSystem _faction = default!;
|
||||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
[Dependency] private readonly FoodSystem _food = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs the UtilityQueryPrototype and returns the best-matching entities.
|
/// Runs the UtilityQueryPrototype and returns the best-matching entities.
|
||||||
@@ -120,6 +122,11 @@ public sealed class NPCUtilitySystem : EntitySystem
|
|||||||
if (!TryComp<FoodComponent>(targetUid, out var food))
|
if (!TryComp<FoodComponent>(targetUid, out var food))
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
|
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
|
||||||
|
|
||||||
|
if (!_food.IsDigestibleBy(owner, targetUid, food))
|
||||||
|
return 0f;
|
||||||
|
|
||||||
return 1f;
|
return 1f;
|
||||||
}
|
}
|
||||||
case TargetAccessibleCon:
|
case TargetAccessibleCon:
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Body.Components;
|
||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
@@ -34,6 +35,25 @@ namespace Content.Server.Nutrition.Components
|
|||||||
[DataField("utensilRequired")]
|
[DataField("utensilRequired")]
|
||||||
public bool UtensilRequired = false;
|
public bool UtensilRequired = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If this is set to true, eating this food will require you to have a stomach with a
|
||||||
|
/// <see cref="StomachComponent.SpecialDigestible"/> that includes this entity in its whitelist,
|
||||||
|
/// rather than just being digestible by anything that can eat food.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// TODO think about making this a little more complex, right now you cant disallow mobs from eating stuff
|
||||||
|
/// that everyone else can eat
|
||||||
|
/// </remarks>
|
||||||
|
[DataField("requiresSpecialDigestion")]
|
||||||
|
public bool RequiresSpecialDigestion = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stomachs required to digest this entity.
|
||||||
|
/// Used to simulate 'ruminant' digestive systems (which can digest grass)
|
||||||
|
/// </summary>
|
||||||
|
[DataField("requiredStomachs")]
|
||||||
|
public int RequiredStomachs = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The localization identifier for the eat message. Needs a "food" entity argument passed to it.
|
/// The localization identifier for the eat message. Needs a "food" entity argument passed to it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Linq;
|
||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
@@ -5,6 +6,7 @@ using Content.Server.Nutrition.Components;
|
|||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
|
using Content.Shared.Body.Organ;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
@@ -85,16 +87,30 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
public bool TryFeed(EntityUid user, EntityUid target, EntityUid food, FoodComponent foodComp)
|
public bool TryFeed(EntityUid user, EntityUid target, EntityUid food, FoodComponent foodComp)
|
||||||
{
|
{
|
||||||
//Suppresses self-eating
|
//Suppresses self-eating
|
||||||
if (food == user || EntityManager.TryGetComponent<MobStateComponent>(food, out var mobState) && _mobStateSystem.IsAlive(food, mobState)) // Suppresses eating alive mobs
|
if (food == user || TryComp<MobStateComponent>(food, out var mobState) && _mobStateSystem.IsAlive(food, mobState)) // Suppresses eating alive mobs
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Target can't be fed or they're already eating
|
// Target can't be fed or they're already eating
|
||||||
if (!EntityManager.HasComponent<BodyComponent>(target))
|
if (!TryComp<BodyComponent>(target, out var body))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!_solutionContainerSystem.TryGetSolution(food, foodComp.SolutionName, out var foodSolution) || foodSolution.Name == null)
|
if (!_solutionContainerSystem.TryGetSolution(food, foodComp.SolutionName, out var foodSolution) || foodSolution.Name == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!_bodySystem.TryGetBodyOrganComponents<StomachComponent>(target, out var stomachs, body))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var forceFeed = user != target;
|
||||||
|
|
||||||
|
if (!IsDigestibleBy(food, foodComp, stomachs))
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(
|
||||||
|
forceFeed
|
||||||
|
? Loc.GetString("food-system-cant-digest-other", ("entity", food))
|
||||||
|
: Loc.GetString("food-system-cant-digest", ("entity", food)), user, user);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var flavors = _flavorProfileSystem.GetLocalizedFlavorsMessage(food, user, foodSolution);
|
var flavors = _flavorProfileSystem.GetLocalizedFlavorsMessage(food, user, foodSolution);
|
||||||
|
|
||||||
if (foodComp.UsesRemaining <= 0)
|
if (foodComp.UsesRemaining <= 0)
|
||||||
@@ -113,8 +129,6 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
if (!TryGetRequiredUtensils(user, foodComp, out _))
|
if (!TryGetRequiredUtensils(user, foodComp, out _))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var forceFeed = user != target;
|
|
||||||
|
|
||||||
if (forceFeed)
|
if (forceFeed)
|
||||||
{
|
{
|
||||||
var userName = Identity.Entity(user, EntityManager);
|
var userName = Identity.Entity(user, EntityManager);
|
||||||
@@ -183,11 +197,30 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
var transferAmount = component.TransferAmount != null ? FixedPoint2.Min((FixedPoint2) component.TransferAmount, solution.Volume) : solution.Volume;
|
var transferAmount = component.TransferAmount != null ? FixedPoint2.Min((FixedPoint2) component.TransferAmount, solution.Volume) : solution.Volume;
|
||||||
|
|
||||||
var split = _solutionContainerSystem.SplitSolution(uid, solution, transferAmount);
|
var split = _solutionContainerSystem.SplitSolution(uid, solution, transferAmount);
|
||||||
|
|
||||||
//TODO: Get the stomach UID somehow without nabbing owner
|
//TODO: Get the stomach UID somehow without nabbing owner
|
||||||
var firstStomach = stomachs.FirstOrNull(stomach => _stomachSystem.CanTransferSolution(stomach.Comp.Owner, split));
|
// Get the stomach with the highest available solution volume
|
||||||
|
var highestAvailable = FixedPoint2.Zero;
|
||||||
|
StomachComponent? stomachToUse = null;
|
||||||
|
foreach (var (stomach, _) in stomachs)
|
||||||
|
{
|
||||||
|
var owner = stomach.Owner;
|
||||||
|
if (!_stomachSystem.CanTransferSolution(owner, split))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!_solutionContainerSystem.TryGetSolution(owner, StomachSystem.DefaultSolutionName,
|
||||||
|
out var stomachSol))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (stomachSol.AvailableVolume <= highestAvailable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stomachToUse = stomach;
|
||||||
|
highestAvailable = stomachSol.AvailableVolume;
|
||||||
|
}
|
||||||
|
|
||||||
// No stomach so just popup a message that they can't eat.
|
// No stomach so just popup a message that they can't eat.
|
||||||
if (firstStomach == null)
|
if (stomachToUse == null)
|
||||||
{
|
{
|
||||||
_solutionContainerSystem.TryAddSolution(uid, solution, split);
|
_solutionContainerSystem.TryAddSolution(uid, solution, split);
|
||||||
_popupSystem.PopupEntity(forceFeed ? Loc.GetString("food-system-you-cannot-eat-any-more-other") : Loc.GetString("food-system-you-cannot-eat-any-more"), args.Target.Value, args.User);
|
_popupSystem.PopupEntity(forceFeed ? Loc.GetString("food-system-you-cannot-eat-any-more-other") : Loc.GetString("food-system-you-cannot-eat-any-more"), args.Target.Value, args.User);
|
||||||
@@ -195,7 +228,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
_reaction.DoEntityReaction(args.Target.Value, solution, ReactionMethod.Ingestion);
|
_reaction.DoEntityReaction(args.Target.Value, solution, ReactionMethod.Ingestion);
|
||||||
_stomachSystem.TryTransferSolution(firstStomach.Value.Comp.Owner, split, firstStomach.Value.Comp);
|
_stomachSystem.TryTransferSolution(stomachToUse.Owner, split, stomachToUse);
|
||||||
|
|
||||||
var flavors = args.FlavorMessage;
|
var flavors = args.FlavorMessage;
|
||||||
|
|
||||||
@@ -285,49 +318,43 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Force feeds someone remotely. Does not require utensils (well, not the normal type anyways).
|
/// Returns true if the food item can be digested by the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ProjectileForceFeed(EntityUid uid, EntityUid target, EntityUid? user, FoodComponent? food = null, BodyComponent? body = null)
|
public bool IsDigestibleBy(EntityUid uid, EntityUid food, FoodComponent? foodComp = null)
|
||||||
{
|
{
|
||||||
// TODO: Combine with regular feeding because holy code duplication batman.
|
if (!Resolve(food, ref foodComp, false))
|
||||||
if (!Resolve(uid, ref food, false) || !Resolve(target, ref body, false))
|
return false;
|
||||||
return;
|
|
||||||
|
|
||||||
if (IsMouthBlocked(target))
|
if (!_bodySystem.TryGetBodyOrganComponents<StomachComponent>(uid, out var stomachs))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if (!_solutionContainerSystem.TryGetSolution(uid, food.SolutionName, out var foodSolution))
|
return IsDigestibleBy(food, foodComp, stomachs);
|
||||||
return;
|
}
|
||||||
|
|
||||||
if (!_bodySystem.TryGetBodyOrganComponents<StomachComponent>(target, out var stomachs, body))
|
/// <summary>
|
||||||
return;
|
/// Returns true if <paramref name="stomachs"/> has a <see cref="StomachComponent"/> that is capable of
|
||||||
|
/// digesting this <paramref name="food"/> (or if they even have enough stomachs in the first place).
|
||||||
|
/// </summary>
|
||||||
|
private bool IsDigestibleBy(EntityUid food, FoodComponent component, List<(StomachComponent, OrganComponent)> stomachs)
|
||||||
|
{
|
||||||
|
var digestible = true;
|
||||||
|
|
||||||
if (food.UsesRemaining <= 0)
|
if (stomachs.Count < component.RequiredStomachs)
|
||||||
DeleteAndSpawnTrash(food, uid);
|
return false;
|
||||||
|
|
||||||
var firstStomach = stomachs.FirstOrNull(
|
if (!component.RequiresSpecialDigestion)
|
||||||
stomach => _stomachSystem.CanTransferSolution(((IComponent) stomach.Comp).Owner, foodSolution));
|
return true;
|
||||||
|
|
||||||
if (firstStomach == null)
|
foreach (var (comp, _) in stomachs)
|
||||||
return;
|
{
|
||||||
|
if (comp.SpecialDigestible == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
// logging
|
if (!comp.SpecialDigestible.IsValid(food, EntityManager))
|
||||||
if (user == null)
|
return false;
|
||||||
_adminLogger.Add(LogType.ForceFeed, $"{ToPrettyString(uid):food} {SolutionContainerSystem.ToPrettyString(foodSolution):solution} was thrown into the mouth of {ToPrettyString(target):target}");
|
}
|
||||||
else
|
|
||||||
_adminLogger.Add(LogType.ForceFeed, $"{ToPrettyString(user.Value):user} threw {ToPrettyString(uid):food} {SolutionContainerSystem.ToPrettyString(foodSolution):solution} into the mouth of {ToPrettyString(target):target}");
|
|
||||||
|
|
||||||
var filter = user == null ? Filter.Entities(target) : Filter.Entities(target, user.Value);
|
return digestible;
|
||||||
_popupSystem.PopupEntity(Loc.GetString(food.EatMessage, ("food", food.Owner)), target, filter, true);
|
|
||||||
|
|
||||||
foodSolution.DoEntityReaction(uid, ReactionMethod.Ingestion);
|
|
||||||
_stomachSystem.TryTransferSolution(((IComponent) firstStomach.Value.Comp).Owner, foodSolution, firstStomach.Value.Comp);
|
|
||||||
SoundSystem.Play(food.UseSound.GetSound(), Filter.Pvs(target), target, AudioParams.Default.WithVolume(-1f));
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(food.TrashPrototype))
|
|
||||||
EntityManager.QueueDeleteEntity(food.Owner);
|
|
||||||
else
|
|
||||||
DeleteAndSpawnTrash(food, uid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryGetRequiredUtensils(EntityUid user, FoodComponent component,
|
private bool TryGetRequiredUtensils(EntityUid user, FoodComponent component,
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ food-system-remove-mask = You need to take off the {$entity} first.
|
|||||||
|
|
||||||
food-system-you-cannot-eat-any-more = You can't eat any more!
|
food-system-you-cannot-eat-any-more = You can't eat any more!
|
||||||
food-system-you-cannot-eat-any-more-other = They can't eat any more!
|
food-system-you-cannot-eat-any-more-other = They can't eat any more!
|
||||||
food-system-try-use-food-is-empty = {$entity} is empty!
|
food-system-try-use-food-is-empty = {CAPITALIZE(THE($entity))} is empty!
|
||||||
food-system-wrong-utensil = you can't eat {$food} with a {$utensil}.
|
food-system-wrong-utensil = You can't eat {THE($food)} with {INDEFINITE($utensil)}.
|
||||||
|
food-system-cant-digest = You can't digest {THE($entity)}!
|
||||||
|
food-system-cant-digest-other = They can't digest {THE($entity)}!
|
||||||
|
|
||||||
food-system-verb-eat = Eat
|
food-system-verb-eat = Eat
|
||||||
|
|
||||||
|
|||||||
@@ -43,9 +43,8 @@
|
|||||||
- type: SolutionContainerManager
|
- type: SolutionContainerManager
|
||||||
solutions:
|
solutions:
|
||||||
stomach:
|
stomach:
|
||||||
maxVol: 100
|
maxVol: 40
|
||||||
- type: Stomach
|
- type: Stomach
|
||||||
maxVolume: 10
|
|
||||||
- type: Metabolizer
|
- type: Metabolizer
|
||||||
maxReagents: 3
|
maxReagents: 3
|
||||||
metabolizerTypes: [ Animal ]
|
metabolizerTypes: [ Animal ]
|
||||||
10
Resources/Prototypes/Body/Organs/Animal/ruminant.yml
Normal file
10
Resources/Prototypes/Body/Organs/Animal/ruminant.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
- type: entity
|
||||||
|
id: OrganAnimalRuminantStomach
|
||||||
|
parent: OrganAnimalStomach
|
||||||
|
name: ruminant stomach
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
stomach:
|
||||||
|
maxVol: 80
|
||||||
@@ -26,8 +26,11 @@
|
|||||||
noSpawn: true
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
- type: Stomach
|
- type: Stomach
|
||||||
maxVolume: 50
|
|
||||||
updateInterval: 1.5
|
updateInterval: 1.5
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
stomach:
|
||||||
|
maxVol: 50
|
||||||
- type: Metabolizer
|
- type: Metabolizer
|
||||||
updateFrequency: 1.5
|
updateFrequency: 1.5
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,9 @@
|
|||||||
parent: OrganAnimalStomach
|
parent: OrganAnimalStomach
|
||||||
suffix: "rat"
|
suffix: "rat"
|
||||||
components:
|
components:
|
||||||
- type: Stomach
|
- type: SolutionContainerManager
|
||||||
maxVolume: 50 # they're hungry
|
solutions:
|
||||||
|
stomach:
|
||||||
|
maxVol: 50
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: stomach
|
state: stomach
|
||||||
|
|||||||
@@ -4,4 +4,7 @@
|
|||||||
noSpawn: true
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
- type: Stomach
|
- type: Stomach
|
||||||
maxVol: 50
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
stomach:
|
||||||
|
maxVol: 50
|
||||||
|
|||||||
22
Resources/Prototypes/Body/Prototypes/Animal/ruminant.yml
Normal file
22
Resources/Prototypes/Body/Prototypes/Animal/ruminant.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
- type: body
|
||||||
|
id: AnimalRuminant
|
||||||
|
name: "ruminant"
|
||||||
|
root: torso
|
||||||
|
slots:
|
||||||
|
torso:
|
||||||
|
part: TorsoAnimal
|
||||||
|
connections:
|
||||||
|
- legs
|
||||||
|
organs:
|
||||||
|
lungs: OrganAnimalLungs
|
||||||
|
stomach: OrganAnimalRuminantStomach
|
||||||
|
stomach2: OrganAnimalRuminantStomach
|
||||||
|
liver: OrganAnimalLiver
|
||||||
|
heart: OrganAnimalHeart
|
||||||
|
kidneys: OrganAnimalKidneys
|
||||||
|
legs:
|
||||||
|
part: LegsAnimal
|
||||||
|
connections:
|
||||||
|
- feet
|
||||||
|
feet:
|
||||||
|
part: FeetAnimal
|
||||||
@@ -416,6 +416,10 @@
|
|||||||
- type: Faction
|
- type: Faction
|
||||||
factions:
|
factions:
|
||||||
- Passive
|
- Passive
|
||||||
|
- type: Body
|
||||||
|
prototype: AnimalRuminant
|
||||||
|
- type: HTN
|
||||||
|
rootTask: RuminantCompound
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: crab
|
name: crab
|
||||||
@@ -519,6 +523,10 @@
|
|||||||
- type: Faction
|
- type: Faction
|
||||||
factions:
|
factions:
|
||||||
- Passive
|
- Passive
|
||||||
|
- type: Body
|
||||||
|
prototype: AnimalRuminant
|
||||||
|
- type: HTN
|
||||||
|
rootTask: RuminantCompound
|
||||||
|
|
||||||
# Note that we gotta make this bitch vomit someday when you feed it anthrax or sumthin. Needs to be a small item thief too and aggressive if attacked.
|
# Note that we gotta make this bitch vomit someday when you feed it anthrax or sumthin. Needs to be a small item thief too and aggressive if attacked.
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|||||||
@@ -81,7 +81,19 @@
|
|||||||
kudzu:
|
kudzu:
|
||||||
!type:SpreaderNode
|
!type:SpreaderNode
|
||||||
nodeGroupID: Spreader
|
nodeGroupID: Spreader
|
||||||
|
- type: Food
|
||||||
|
requiredStomachs: 2 # ruminants have 4 stomachs but i dont care to give them literally 4 stomachs. 2 is good
|
||||||
|
# TODO make botany plants edible to ruminants as well ...
|
||||||
|
delay: 0.5
|
||||||
|
- type: FlavorProfile
|
||||||
|
flavors:
|
||||||
|
- fiber
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
food:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Nutriment
|
||||||
|
Quantity: 2
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WeakKudzu
|
id: WeakKudzu
|
||||||
@@ -154,3 +166,11 @@
|
|||||||
ignoreWhitelist:
|
ignoreWhitelist:
|
||||||
tags:
|
tags:
|
||||||
- Flesh
|
- Flesh
|
||||||
|
- type: Food # delightfully devilish !
|
||||||
|
delay: 0.5
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
food:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Protein
|
||||||
|
Quantity: 2
|
||||||
|
|||||||
@@ -15,6 +15,14 @@
|
|||||||
- tasks:
|
- tasks:
|
||||||
- id: IdleCompound
|
- id: IdleCompound
|
||||||
|
|
||||||
|
- type: htnCompound
|
||||||
|
id: RuminantCompound
|
||||||
|
branches:
|
||||||
|
- tasks:
|
||||||
|
- id: FoodCompound
|
||||||
|
- tasks:
|
||||||
|
- id: IdleCompound
|
||||||
|
|
||||||
- type: htnCompound
|
- type: htnCompound
|
||||||
id: DragonCarpCompound
|
id: DragonCarpCompound
|
||||||
branches:
|
branches:
|
||||||
|
|||||||
Reference in New Issue
Block a user