diff --git a/Content.Client/GameObjects/Components/Nutrition/CreamPiedVisualizer.cs b/Content.Client/GameObjects/Components/Nutrition/CreamPiedVisualizer.cs new file mode 100644 index 0000000000..2bb5ad6541 --- /dev/null +++ b/Content.Client/GameObjects/Components/Nutrition/CreamPiedVisualizer.cs @@ -0,0 +1,33 @@ +using Content.Shared.GameObjects.Components.Nutrition; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; + +namespace Content.Client.GameObjects.Components.Nutrition +{ + [UsedImplicitly] + public class CreamPiedVisualizer : AppearanceVisualizer + { + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (component.TryGetData(CreamPiedVisuals.Creamed, out var pied)) + { + SetPied(component, pied); + } + } + + private void SetPied(AppearanceComponent component, bool pied) + { + var sprite = component.Owner.GetComponent(); + + sprite.LayerSetVisible(CreamPiedVisualLayers.Pie, pied); + } + } + + public enum CreamPiedVisualLayers + { + Pie, + } +} diff --git a/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs b/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs index 644149c31e..febe086fb6 100644 --- a/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs @@ -27,7 +27,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Fluids { [RegisterComponent] - class SprayComponent : SharedSprayComponent, IAfterInteract, IUse, IActivate + class SprayComponent : SharedSprayComponent, IAfterInteract, IUse, IActivate, IDropped { public const float SprayDistance = 3f; @@ -211,5 +211,11 @@ namespace Content.Server.GameObjects.Components.Fluids if(Owner.TryGetComponent(out AppearanceComponent appearance)) appearance.SetData(SprayVisuals.Safety, _safety); } + + public void Dropped(DroppedEventArgs eventArgs) + { + if(_hasSafety && Owner.TryGetComponent(out AppearanceComponent appearance)) + appearance.SetData(SprayVisuals.Safety, _safety); + } } } diff --git a/Content.Server/GameObjects/Components/Nutrition/CreamPieComponent.cs b/Content.Server/GameObjects/Components/Nutrition/CreamPieComponent.cs new file mode 100644 index 0000000000..96f1ef2719 --- /dev/null +++ b/Content.Server/GameObjects/Components/Nutrition/CreamPieComponent.cs @@ -0,0 +1,35 @@ +using Content.Server.GameObjects.Components.Chemistry; +using Content.Server.GameObjects.Components.Fluids; +using Content.Shared.Audio; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; + +namespace Content.Server.GameObjects.Components.Nutrition +{ + [RegisterComponent] + public class CreamPieComponent : Component, ILand + { + public override string Name => "CreamPie"; + + public void PlaySound() + { + EntitySystem.Get() + .PlayFromEntity(AudioHelpers.GetRandomFileFromSoundCollection("desecration"), Owner, + AudioHelpers.WithVariation(0.125f)); + } + + public void Land(LandEventArgs eventArgs) + { + PlaySound(); + + if (Owner.TryGetComponent(out SolutionContainerComponent solution)) + { + solution.Solution.SpillAt(Owner, "PuddleSmear", false); + } + + Owner.Delete(); + } + } +} diff --git a/Content.Server/GameObjects/Components/Nutrition/CreamPiedComponent.cs b/Content.Server/GameObjects/Components/Nutrition/CreamPiedComponent.cs new file mode 100644 index 0000000000..917ca65617 --- /dev/null +++ b/Content.Server/GameObjects/Components/Nutrition/CreamPiedComponent.cs @@ -0,0 +1,67 @@ +using Content.Server.GameObjects.Components.Mobs; +using Content.Server.Utility; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Nutrition; +using Content.Shared.Interfaces; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.ViewVariables; +using Serilog; + +namespace Content.Server.GameObjects.Components.Nutrition +{ + [RegisterComponent] + public class CreamPiedComponent : SharedCreamPiedComponent, IReagentReaction, IThrowCollide + { + private bool _creamPied; + + [ViewVariables] + public bool CreamPied + { + get => _creamPied; + private set + { + _creamPied = value; + if (Owner.TryGetComponent(out AppearanceComponent appearance)) + { + appearance.SetData(CreamPiedVisuals.Creamed, CreamPied); + } + } + } + + public void Wash() + { + if(CreamPied) + CreamPied = false; + } + + public ReagentUnit ReagentReactTouch(ReagentPrototype reagent, ReagentUnit volume) + { + switch (reagent.ID) + { + case "chem.SpaceCleaner": + case "chem.H2O": + Wash(); + break; + } + + return ReagentUnit.Zero; + } + + public void HitBy(ThrowCollideEventArgs eventArgs) + { + if (!eventArgs.Thrown.TryGetComponent(out CreamPieComponent creamPie) || CreamPied) return; + + CreamPied = true; + Owner.PopupMessage(Loc.GetString("You have been creamed by {0:theName}!", eventArgs.Thrown)); + Owner.PopupMessageOtherClients(Loc.GetString("{0:theName} has been creamed by {1:theName}!", Owner, eventArgs.Thrown)); + + if (Owner.TryGetComponent(out StunnableComponent stun)) + { + stun.Paralyze(1f); + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs b/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs index e3d2c73f04..68aba32267 100644 --- a/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs +++ b/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs @@ -39,6 +39,9 @@ namespace Content.Server.GameObjects.Components.Projectiles return; _shouldStop = true; // hit something hard => stop after this collision + + // Raise an event. + EntitySystem.Get().ThrowCollideInteraction(User, Owner, entity, Owner.Transform.Coordinates); } if (entity.TryGetComponent(out IDamageableComponent damage)) { diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs index 78d7c24bbd..377748da11 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -28,7 +28,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Weapon.Melee { [RegisterComponent] - public class StunbatonComponent : MeleeWeaponComponent, IUse, IExamine, IMapInit, IInteractUsing + public class StunbatonComponent : MeleeWeaponComponent, IUse, IExamine, IMapInit, IInteractUsing, IThrowCollide { [Dependency] private readonly IRobustRandom _robustRandom = default!; @@ -282,5 +282,15 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee component.EjectCell(user); } } + + public void DoHit(ThrowCollideEventArgs eventArgs) + { + if (!Activated || Cell == null || !Cell.TryUseCharge(EnergyPerUse) || !eventArgs.Target.TryGetComponent(out StunnableComponent stunnable)) + return; + + EntitySystem.Get().PlayAtCoords("/Audio/Weapons/egloves.ogg", Owner.Transform.Coordinates, AudioHelpers.WithVariation(0.25f)); + + stunnable.Paralyze(_paralyzeTime); + } } } diff --git a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs index a2c2ab5fe9..1849062235 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs @@ -625,6 +625,32 @@ namespace Content.Server.GameObjects.EntitySystems.Click } } + /// + /// Calls ThrowCollide on all components that implement the IThrowCollide interface + /// on a thrown entity and the target entity it hit. + /// + public void ThrowCollideInteraction(IEntity user, IEntity thrown, IEntity target, EntityCoordinates location) + { + var collideMsg = new ThrowCollideMessage(user, thrown, target, location); + RaiseLocalEvent(collideMsg); + if (collideMsg.Handled) + { + return; + } + + var eventArgs = new ThrowCollideEventArgs(user, thrown, target, location); + + foreach (var comp in thrown.GetAllComponents().ToArray()) + { + comp.DoHit(eventArgs); + } + + foreach (var comp in target.GetAllComponents().ToArray()) + { + comp.HitBy(eventArgs); + } + } + /// /// Calls Equipped on all components that implement the IEquipped interface /// on an entity that has been equipped. diff --git a/Content.Shared/GameObjects/Components/Nutrition/SharedCreamPiedComponent.cs b/Content.Shared/GameObjects/Components/Nutrition/SharedCreamPiedComponent.cs new file mode 100644 index 0000000000..9a427f6366 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Nutrition/SharedCreamPiedComponent.cs @@ -0,0 +1,17 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Nutrition +{ + public class SharedCreamPiedComponent : Component + { + public override string Name => "CreamPied"; + } + + [Serializable, NetSerializable] + public enum CreamPiedVisuals + { + Creamed, + } +} diff --git a/Content.Shared/Interfaces/GameObjects/Components/Interaction/IThrowCollide.cs b/Content.Shared/Interfaces/GameObjects/Components/Interaction/IThrowCollide.cs new file mode 100644 index 0000000000..d5a255cad9 --- /dev/null +++ b/Content.Shared/Interfaces/GameObjects/Components/Interaction/IThrowCollide.cs @@ -0,0 +1,72 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; + +namespace Content.Shared.Interfaces.GameObjects.Components +{ + public interface IThrowCollide + { + void HitBy(ThrowCollideEventArgs eventArgs) {} + void DoHit(ThrowCollideEventArgs eventArgs) {} + } + + public class ThrowCollideEventArgs : EventArgs + { + /// + /// The entity that threw and hit . + /// + public IEntity User { get; } + + /// + /// The entity thrown by that hit + /// + public IEntity Thrown { get; } + + /// + /// The entity hit with by + /// + public IEntity Target { get; } + public EntityCoordinates Location { get; } + + public ThrowCollideEventArgs(IEntity user, IEntity thrown, IEntity target, EntityCoordinates location) + { + User = user; + Thrown = thrown; + Target = target; + Location = location; + } + } + + public class ThrowCollideMessage : EntitySystemMessage + { + /// + /// If this message has already been "handled" by a previous system. + /// + public bool Handled { get; set; } + + /// + /// The entity that threw . + /// + public IEntity User { get; } + + /// + /// The entity thrown by that hit + /// + public IEntity Thrown { get; } + + /// + /// The entity hit with by + /// + public IEntity Target { get; } + public EntityCoordinates Location { get; } + + public ThrowCollideMessage(IEntity user, IEntity thrown, IEntity target, EntityCoordinates location) + { + User = user; + Thrown = thrown; + Target = target; + Location = location; + } + } +} diff --git a/Resources/Audio/Effects/desecration-01.ogg b/Resources/Audio/Effects/desecration-01.ogg new file mode 100644 index 0000000000..29bc568c57 Binary files /dev/null and b/Resources/Audio/Effects/desecration-01.ogg differ diff --git a/Resources/Audio/Effects/desecration-02.ogg b/Resources/Audio/Effects/desecration-02.ogg new file mode 100644 index 0000000000..761a73a7b9 Binary files /dev/null and b/Resources/Audio/Effects/desecration-02.ogg differ diff --git a/Resources/Audio/Effects/desecration-03.ogg b/Resources/Audio/Effects/desecration-03.ogg new file mode 100644 index 0000000000..876de18de5 Binary files /dev/null and b/Resources/Audio/Effects/desecration-03.ogg differ diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index a10b7404e9..dd896b04ba 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -112,6 +112,10 @@ sprite: Mobs/Customization/human_hair.rsi - map: ["enum.Slots.MASK"] - map: ["enum.Slots.HEAD"] + - map: ["enum.CreamPiedVisualLayers.Pie"] + sprite: Effects/creampie.rsi + state: creampie_human + visible: false - type: Icon sprite: Mobs/Species/Human/parts.rsi state: full @@ -159,6 +163,7 @@ visuals: - type: RotationVisualizer - type: BuckleVisualizer + - type: CreamPiedVisualizer - type: CombatMode - type: Climbing - type: Cuffable @@ -176,6 +181,7 @@ proper: true - type: Pullable - type: DoAfter + - type: CreamPied - type: Strippable - type: UserInterface interfaces: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/food.yml b/Resources/Prototypes/Entities/Objects/Consumable/food.yml index 8f9755ceb2..947092610f 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/food.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/food.yml @@ -231,6 +231,7 @@ components: - type: Food trash: TrashPlate + - type: CreamPie - type: SolutionContainer contents: reagents: diff --git a/Resources/Prototypes/SoundCollections/desceration.yml b/Resources/Prototypes/SoundCollections/desceration.yml new file mode 100644 index 0000000000..a6c4be7b00 --- /dev/null +++ b/Resources/Prototypes/SoundCollections/desceration.yml @@ -0,0 +1,6 @@ +- type: soundCollection + id: desecration + files: + - /Audio/Effects/desecration-01.ogg + - /Audio/Effects/desecration-02.ogg + - /Audio/Effects/desecration-03.ogg diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_ai.png b/Resources/Textures/Effects/creampie.rsi/creampie_ai.png new file mode 100644 index 0000000000..9d00d4f1fa Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_ai.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_corgi.png b/Resources/Textures/Effects/creampie.rsi/creampie_corgi.png new file mode 100644 index 0000000000..fc971385f3 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_corgi.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_drone.png b/Resources/Textures/Effects/creampie.rsi/creampie_drone.png new file mode 100644 index 0000000000..4530d20115 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_drone.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_engborg.png b/Resources/Textures/Effects/creampie.rsi/creampie_engborg.png new file mode 100644 index 0000000000..ed4a6d94d8 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_engborg.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_hardsuit.png b/Resources/Textures/Effects/creampie.rsi/creampie_hardsuit.png new file mode 100644 index 0000000000..115cb78751 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_hardsuit.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_helmet.png b/Resources/Textures/Effects/creampie.rsi/creampie_helmet.png new file mode 100644 index 0000000000..de2866287d Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_helmet.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_human.png b/Resources/Textures/Effects/creampie.rsi/creampie_human.png new file mode 100644 index 0000000000..7bfc562907 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_human.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_janborg.png b/Resources/Textures/Effects/creampie.rsi/creampie_janborg.png new file mode 100644 index 0000000000..6d8a6772e0 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_janborg.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_lizard.png b/Resources/Textures/Effects/creampie.rsi/creampie_lizard.png new file mode 100644 index 0000000000..866cb6b314 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_lizard.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_medborg.png b/Resources/Textures/Effects/creampie.rsi/creampie_medborg.png new file mode 100644 index 0000000000..ea4476bd79 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_medborg.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_monkey.png b/Resources/Textures/Effects/creampie.rsi/creampie_monkey.png new file mode 100644 index 0000000000..0456b10fa2 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_monkey.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_secborg.png b/Resources/Textures/Effects/creampie.rsi/creampie_secborg.png new file mode 100644 index 0000000000..6e8a1558d3 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_secborg.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_standborg.png b/Resources/Textures/Effects/creampie.rsi/creampie_standborg.png new file mode 100644 index 0000000000..8b79077dc4 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_standborg.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_xeno_crit.png b/Resources/Textures/Effects/creampie.rsi/creampie_xeno_crit.png new file mode 100644 index 0000000000..e6bfcc5141 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_xeno_crit.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_xeno_dead.png b/Resources/Textures/Effects/creampie.rsi/creampie_xeno_dead.png new file mode 100644 index 0000000000..e6bfcc5141 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_xeno_dead.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_xeno_sleep.png b/Resources/Textures/Effects/creampie.rsi/creampie_xeno_sleep.png new file mode 100644 index 0000000000..94cb3aa63e Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_xeno_sleep.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_xenomorph.png b/Resources/Textures/Effects/creampie.rsi/creampie_xenomorph.png new file mode 100644 index 0000000000..e51fed1e4f Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_xenomorph.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/meta.json b/Resources/Textures/Effects/creampie.rsi/meta.json new file mode 100644 index 0000000000..4ae015b294 --- /dev/null +++ b/Resources/Textures/Effects/creampie.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA 3.0", "copyright": "Taken from https://github.com/tgstation/tgstation at 0d9c9a8233dfc3fc55edc538955a761a6328bee0", "states": [{"name": "creampie_ai", "directions": 1, "delays": [[1.0]]}, {"name": "creampie_corgi", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_drone", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_engborg", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_hardsuit", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_helmet", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_human", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_janborg", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_lizard", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_medborg", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_monkey", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_secborg", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_standborg", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_xeno_crit", "directions": 1, "delays": [[1.0]]}, {"name": "creampie_xeno_dead", "directions": 1, "delays": [[1.0]]}, {"name": "creampie_xeno_sleep", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "creampie_xenomorph", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file