From 4b9d488c1e3c472601b012d8b4a667b3ceee8798 Mon Sep 17 00:00:00 2001 From: 20kdc Date: Sat, 26 Sep 2020 14:28:55 +0100 Subject: [PATCH] The Grovelling-to-the-Chef Games (monkey cubes and meat spikes) (#2117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Rehydratable component -> monkey cubes now have some of their behaviour * Placeholder kitchen spike entity * KitchenSpike component: the kitchen spike now has basic functionality still placeholder sprite though * Kitchen Spike: Import meatspike assets from CEV-Eris * Kitchen Spike: Actually use sprites somewhat * Kitchen Spike: Forgot I removed the MeatParts property from Butcherable * Monkey cubes: Use IReagentReaction even though it doesn't quite work yet. Butcherable: remove imports * Monkey cubes/Rehydratable: Re-add ISolutionChange * Update Resources/Prototypes/Entities/Constructible/Ground/kitchen.yml Co-authored-by: Víctor Aguilera Puerto <6766154+Zumorica@users.noreply.github.com> --- .../Chemistry/RehydratableComponent.cs | 92 ++++++++++++++ .../Kitchen/ButcherableComponent.cs | 30 +++++ .../Kitchen/KitchenSpikeComponent.cs | 114 ++++++++++++++++++ .../Components/Items/SharedHandsComponent.cs | 2 +- .../Entities/Constructible/Ground/kitchen.yml | 23 ++++ .../Prototypes/Entities/Mobs/NPCs/animals.yml | 2 + .../Entities/Objects/Consumable/food.yml | 5 +- .../Recipes/Construction/kitchen.yml | 18 +++ .../Constructible/Misc/kitchen.rsi/meta.json | 12 ++ .../Constructible/Misc/kitchen.rsi/spike.png | Bin 0 -> 344 bytes .../Misc/kitchen.rsi/spikebloody.png | Bin 0 -> 956 bytes .../Misc/kitchen.rsi/spikebloodygreen.png | Bin 0 -> 1007 bytes 12 files changed, 296 insertions(+), 2 deletions(-) create mode 100644 Content.Server/GameObjects/Components/Chemistry/RehydratableComponent.cs create mode 100644 Content.Server/GameObjects/Components/Kitchen/ButcherableComponent.cs create mode 100644 Content.Server/GameObjects/Components/Kitchen/KitchenSpikeComponent.cs create mode 100644 Resources/Prototypes/Entities/Constructible/Ground/kitchen.yml create mode 100644 Resources/Prototypes/Recipes/Construction/kitchen.yml create mode 100644 Resources/Textures/Constructible/Misc/kitchen.rsi/meta.json create mode 100644 Resources/Textures/Constructible/Misc/kitchen.rsi/spike.png create mode 100644 Resources/Textures/Constructible/Misc/kitchen.rsi/spikebloody.png create mode 100644 Resources/Textures/Constructible/Misc/kitchen.rsi/spikebloodygreen.png diff --git a/Content.Server/GameObjects/Components/Chemistry/RehydratableComponent.cs b/Content.Server/GameObjects/Components/Chemistry/RehydratableComponent.cs new file mode 100644 index 0000000000..f727d00616 --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/RehydratableComponent.cs @@ -0,0 +1,92 @@ +#nullable enable +using System; +using System.Collections.Generic; +using Content.Server.GameObjects.Components.Body.Digestive; +using Content.Server.GameObjects.Components.Chemistry; +using Content.Server.GameObjects.Components.GUI; +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Utility; +using Content.Shared.Chemistry; +using Content.Shared.Interfaces; +using Content.Shared.Interfaces.GameObjects.Components; +using Content.Shared.Utility; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Server.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; +using Robust.Shared.Log; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Server.GameObjects.Components.Chemistry +{ + /// + /// Basically, monkey cubes. + /// But specifically, this component deletes the entity and spawns in a new entity when the entity is exposed to a given reagent. + /// + [RegisterComponent] + [ComponentReference(typeof(IReagentReaction))] + [ComponentReference(typeof(ISolutionChange))] + public class RehydratableComponent : Component, IReagentReaction, ISolutionChange + { + public override string Name => "Rehydratable"; + + [ViewVariables] + private string _catalystPrototype = ""; + [ViewVariables] + private string? _targetPrototype; + + private bool _expanding; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _catalystPrototype, "catalyst", "chem.H2O"); + serializer.DataField(ref _targetPrototype, "target", null); + } + + ReagentUnit IReagentReaction.ReagentReactTouch(ReagentPrototype reagent, ReagentUnit volume) => Reaction(reagent, volume); + ReagentUnit IReagentReaction.ReagentReactInjection(ReagentPrototype reagent, ReagentUnit volume) => Reaction(reagent, volume); + + private ReagentUnit Reaction(ReagentPrototype reagent, ReagentUnit volume) + { + if ((volume > ReagentUnit.Zero) && (reagent.ID == _catalystPrototype)) + { + Expand(); + } + return ReagentUnit.Zero; + } + + void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) + { + var solution = eventArgs.Owner.GetComponent(); + if (solution.Solution.GetReagentQuantity(_catalystPrototype) > ReagentUnit.Zero) + { + Expand(); + } + } + + // Try not to make this public if you can help it. + private void Expand() + { + if (_expanding) + { + return; + } + _expanding = true; + Owner.PopupMessageEveryone(Loc.GetString("{0:TheName} expands!", Owner)); + if (!string.IsNullOrEmpty(_targetPrototype)) + { + Owner.EntityManager.SpawnEntity(_targetPrototype, Owner.Transform.Coordinates); + } + Owner.Delete(); + } + } +} diff --git a/Content.Server/GameObjects/Components/Kitchen/ButcherableComponent.cs b/Content.Server/GameObjects/Components/Kitchen/ButcherableComponent.cs new file mode 100644 index 0000000000..0e7d7b3dbc --- /dev/null +++ b/Content.Server/GameObjects/Components/Kitchen/ButcherableComponent.cs @@ -0,0 +1,30 @@ +#nullable enable +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Kitchen +{ + /// + /// Indicates that the entity can be thrown on a kitchen spike for butchering. + /// + [RegisterComponent] + public class ButcherableComponent : Component + { + public override string Name => "Butcherable"; + + [ViewVariables] + public string? MeatPrototype => _meatPrototype; + + [ViewVariables] + private string? _meatPrototype; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _meatPrototype, "meat", null); + } + } +} + diff --git a/Content.Server/GameObjects/Components/Kitchen/KitchenSpikeComponent.cs b/Content.Server/GameObjects/Components/Kitchen/KitchenSpikeComponent.cs new file mode 100644 index 0000000000..35bfe18dc8 --- /dev/null +++ b/Content.Server/GameObjects/Components/Kitchen/KitchenSpikeComponent.cs @@ -0,0 +1,114 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Content.Server.GameObjects.Components.Body; +using Content.Server.GameObjects.Components.Chemistry; +using Content.Server.GameObjects.Components.GUI; +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.Components.Power.ApcNetComponents; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.Chat; +using Content.Server.Interfaces.GameObjects; +using Content.Server.Utility; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Body; +using Content.Shared.GameObjects.Components.Power; +using Content.Shared.Interfaces; +using Content.Shared.Interfaces.GameObjects.Components; +using Content.Shared.Kitchen; +using Content.Shared.Prototypes.Kitchen; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.Components.Container; +using Robust.Server.GameObjects.Components.UserInterface; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Serialization; +using Robust.Shared.Timers; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Kitchen +{ + [RegisterComponent] + [ComponentReference(typeof(IActivate))] + public class KitchenSpikeComponent : Component, IActivate, ISuicideAct + { + public override string Name => "KitchenSpike"; + + private int _meatParts; + private string? _meatPrototype; + private string _meatSource1p = "?"; + private string _meatSource0 = "?"; + + void IActivate.Activate(ActivateEventArgs eventArgs) + { + var victim = eventArgs.User.GetComponent().PulledObject?.Owner; + + var sprite = Owner.GetComponent(); + + if (victim == null) + { + if (_meatParts == 0) + { + return; + } + _meatParts--; + + if (!string.IsNullOrEmpty(_meatPrototype)) + { + Owner.EntityManager.SpawnEntity(_meatPrototype, Owner.Transform.Coordinates); + } + + if (_meatParts != 0) + { + eventArgs.User.PopupMessage(_meatSource1p); + } + else + { + sprite.LayerSetState(0, "spike"); + eventArgs.User.PopupMessage(_meatSource0); + } + return; + } + else if (_meatParts > 0) + { + Owner.PopupMessage(eventArgs.User, Loc.GetString("The spike already has something on it, finish collecting its meat first!")); + return; + } + + if (!victim.TryGetComponent(out var food)) + { + Owner.PopupMessage(eventArgs.User, Loc.GetString("{0:theName} can't be butchered on the spike.", victim)); + return; + } + + _meatPrototype = food.MeatPrototype; + _meatParts = 5; + _meatSource1p = Loc.GetString("You remove some meat from {0:theName}.", victim); + _meatSource0 = Loc.GetString("You remove the last piece of meat from {0:theName}!", victim); + + sprite.LayerSetState(0, "spikebloody"); + + Owner.PopupMessageEveryone(Loc.GetString("{0:theName} has forced {1:theName} onto the spike, killing them instantly!", eventArgs.User, victim)); + victim.Delete(); + } + + public SuicideKind Suicide(IEntity victim, IChatManager chat) + { + var othersMessage = Loc.GetString("{0:theName} has thrown themselves on a meat spike!", victim); + victim.PopupMessageOtherClients(othersMessage); + + var selfMessage = Loc.GetString("You throw yourself on a meat spike!"); + victim.PopupMessage(selfMessage); + + return SuicideKind.Piercing; + } + } +} diff --git a/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs index 02919bcf8e..9e16860294 100644 --- a/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs +++ b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs @@ -15,7 +15,7 @@ namespace Content.Shared.GameObjects.Components.Items public sealed override uint? NetID => ContentNetIDs.HANDS; [ViewVariables] - protected ICollidableComponent? PulledObject; + public ICollidableComponent? PulledObject { get; protected set; } [ViewVariables] protected bool IsPulling => PulledObject != null; diff --git a/Resources/Prototypes/Entities/Constructible/Ground/kitchen.yml b/Resources/Prototypes/Entities/Constructible/Ground/kitchen.yml new file mode 100644 index 0000000000..ab76b8d1c2 --- /dev/null +++ b/Resources/Prototypes/Entities/Constructible/Ground/kitchen.yml @@ -0,0 +1,23 @@ +- type: entity + id: KitchenSpike + name: meat spike + description: A spike for collecting meat from animals. + components: + - type: Clickable + - type: InteractionOutline + - type: Collidable + shapes: + - !type:PhysShapeAabb + mask: + - Impassable + layer: + - Impassable + - type: Sprite + # temp to make clickmask work + sprite: Constructible/Misc/kitchen.rsi + state: spike + - type: Anchorable + - type: Pullable + - type: Destructible + deadThreshold: 50 + - type: KitchenSpike diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index a4dd7a47b5..317de00e00 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -60,6 +60,8 @@ normal: monkey dead: dead - type: Pullable + - type: Butcherable + meat: FoodMeat - type: entity save: false diff --git a/Resources/Prototypes/Entities/Objects/Consumable/food.yml b/Resources/Prototypes/Entities/Objects/Consumable/food.yml index a22396e796..9c35a42c1b 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/food.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/food.yml @@ -1705,9 +1705,12 @@ reagents: - ReagentId: chem.Nutriment Quantity: 10 + maxVol: 11 # needs room for water + caps: AddTo, RemoveFrom, FitsInDispenser - type: Sprite sprite: Objects/Consumable/Food/monkeycube.rsi - + - type: Rehydratable + target: MonkeyMob_Content - type: entity parent: FoodBase diff --git a/Resources/Prototypes/Recipes/Construction/kitchen.yml b/Resources/Prototypes/Recipes/Construction/kitchen.yml new file mode 100644 index 0000000000..75a4504c10 --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/kitchen.yml @@ -0,0 +1,18 @@ +- type: construction + name: meat spike + id: KitchenSpike + category: Items/Kitchen + keywords: [kitchen] + description: + icon: Constructible/Misc/kitchen.rsi/spike.png + result: KitchenSpike + objectType: Structure + steps: + # Replace with Metal Rods whenever + # also this should be done with a Welding tool if that is specifiable + - material: Metal + amount: 3 + reverse: + # logic here: BOLT_TURNING -> Wrench -> Anchoring + tool: Anchoring + diff --git a/Resources/Textures/Constructible/Misc/kitchen.rsi/meta.json b/Resources/Textures/Constructible/Misc/kitchen.rsi/meta.json new file mode 100644 index 0000000000..7bf3d1be3c --- /dev/null +++ b/Resources/Textures/Constructible/Misc/kitchen.rsi/meta.json @@ -0,0 +1,12 @@ +{ + "version":1, + "size":{"x":32,"y":32}, + "license":"CC-BY-SA-3.0", + "copyright":"Taken from https://github.com/discordia-space/CEV-Eris/blob/2b969adc2dfd3e9621bf3597c5cbffeb3ac8c9f0/icons/obj/kitchen.dmi", + "states":[ + {"name":"spike","directions":1,"delays":[[1.0]]}, + {"name":"spikebloody","directions":1,"delays":[[1.0]]}, + {"name":"spikebloodygreen","directions":1,"delays":[[1.0]]} + ] +} + diff --git a/Resources/Textures/Constructible/Misc/kitchen.rsi/spike.png b/Resources/Textures/Constructible/Misc/kitchen.rsi/spike.png new file mode 100644 index 0000000000000000000000000000000000000000..f39fafcf20e4a8569ca8630f082af1efa8556a36 GIT binary patch literal 344 zcmV-e0jK_nP)fQkczKMYj?*0Qy2fXX%(yzfm@w6>aO1)ZbmRt!WFCJDwNayCm{uGuLxg)e;7wn)60)22r+)C}{P_Qhq4fqf)6l?__1-HR4 zWMD~0u5F>g2m9c{pn;a%m$-UISOiCOZ5Z{X?qx9I!&1Hc`fyDeYyKEb@cZ(+_jk@c z=X=lZ_dCCHBwg1zOgO3ule#XJS6BCK+}+v98LwB`Hvxb^ARwhuDWNDz-D6VMMJ@YM zwIzr|B1Hqn;v!wAPZ!5mQAr*M1P&g7?GeAvC!(4rRnXfdFa3c^uyM%PGl6VO6_?+C zMmDC3dw&0pKfCAmi)>647v8hvO(6g<;`@yB!yKNotwl%Km?}JHTS-66@%`XO&5M9* zAS4Y>{mtrsvV)$Coq2bjkss;{f7K-@q~KR~ z{G*fKFz?Ru`;r4^<_!Sm-Fg0hd*}Cs?`oy;iUf?sMF9GuQK^)K=h+OefBH3NoKDV} zCKGl$n;%}><-9K%l}ha#XcHEU6|gXu;GAg^b2^!{+qw92oKx3zY3W<9D5u}hQ((h} zxt`;$CJkAF~kc!6{H_f8FUJ`W?m{zUqH*T6J zy}bY^y}eA>?K|X6i9q4pJKsH0i~v9?9_LzXD`4e=dP&&oalWyZ#{JfRjGHE3K7S6t zQQ*5=4)rS!8*6F0yCAvlX&ix4=d&yAT=>(;A6r`he7?EKQ`4j;pC|qo%&xQ-N$fQe zdtQRsm3Ag?%}GI7=89s?z4PNK#!Qo6T3P^@yfr7yuC&v%Q!uTnBAm%^Wt)NYv4@W2 zB|5_HeXalgZ$m}lwe82tpJ<>cY^jbyMD-xy!=XF`hhj z5gu(jcw+*frA)%3ZD=X8SnZ62%3r&#fsmxdR8i1xNCaF1A*s}PqxBuNS}UuzmwB*< z8vi9MeRpSP&Fi=<0l&{Dd_zMluddeYY^os=i3s1&P}PQJS8G;qUaP6B2T5HQ+MPR; eBOx7jd;S8B@we0eoV$ns0000 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Constructible/Misc/kitchen.rsi/spikebloodygreen.png b/Resources/Textures/Constructible/Misc/kitchen.rsi/spikebloodygreen.png new file mode 100644 index 0000000000000000000000000000000000000000..213c7247baf1f2fc3b382013d6e10421f1784c07 GIT binary patch literal 1007 zcmVp$)TN}qU@2M_Ld8qj9@3d+*G+Uar4Pbx=IxvL=FRth3{eyX z|5L7ZQdShj`mnc$_0=s`eJl~~sJlHlh>@`|(rJyJvk(e`KmZ`fh0yv00G{XByHii? z&XSG*=4KZlilP-ugrRFH=ra<{0|08Z8UP>?&D->`L>QtdT641tmje(>gyFANAqWDI z%MvN>7i}JB-DQvqp}1d!T$YF+2*h8lB9;hW4gdh83I$TiUbWLTfPsY=hIc~s*03y*mK7V@4 z^j+~lMNzEv)h$p0%4Lc8t~Xu0Q;}ef8_38hnBxX^DiX7!=TGe_iehyw3e1LqTK^jA zcXj~)#ibGeu>Ti{g0=uY?Cse=FfY7mdLbjHY)@TN5#&Nh#?!XNTj%ivp!)7zN5f*W zgv^5!ipkO`j(C};$17>**<Fq)I5ex za%3ELClAnF4QvnnJ@-kl_krypm@uGgD!ioPt7lciR(H}oFt9z;9N2cG>gxfR4TIUl z65;NU(BurnevZK3--r60UHJR^U^Wbx4FmP(&Hn&Uf4++#7lO$d-K_iB;5J9JIO@JJd1Plnj{T?KH!pP-gs0|0Dp%(IS&N+g=c@~}a+5+eeT(j-Q zIYF&|%?8lfxX?;T=b=4>bDndN&}|X^Yjcc}vy)9En#bnGybZ{?0qC0QN-8%G&IzPiOK-;JB2*xZ;urKfhiforyU;7rr5 z0CL%^m3{aSbF&MO%Mx*GwOifjrlWRGpFP6j%a