Basic gibbing (#2973)

* Adds gibbing

* Adds adminbused absurd-damage foamblade

* Sane parts

* BaseOrgan -> BaseMechanism

* Do not do random offset on shared, fix killing oneself with click attacks

* BaseMechanism -> BaseHumanOrgan -> *stuff*

* Account for prediction, again

* Add gibbing sound
This commit is contained in:
Vera Aguilera Puerto
2021-01-10 20:12:34 +01:00
committed by GitHub
parent 8def38aed4
commit 12c733654c
18 changed files with 172 additions and 29 deletions

View File

@@ -51,39 +51,42 @@ namespace Content.Client.GameObjects.EntitySystems
var attacker = EntityManager.GetEntity(msg.Attacker); var attacker = EntityManager.GetEntity(msg.Attacker);
var lunge = attacker.EnsureComponent<MeleeLungeComponent>(); if (!attacker.Deleted)
lunge.SetData(msg.Angle);
var entity = EntityManager.SpawnEntity(weaponArc.Prototype, attacker.Transform.Coordinates);
entity.Transform.LocalRotation = msg.Angle;
var weaponArcAnimation = entity.GetComponent<MeleeWeaponArcAnimationComponent>();
weaponArcAnimation.SetData(weaponArc, msg.Angle, attacker, msg.ArcFollowAttacker);
// Due to ISpriteComponent limitations, weapons that don't use an RSI won't have this effect.
if (EntityManager.TryGetEntity(msg.Source, out var source) && msg.TextureEffect && source.TryGetComponent(out ISpriteComponent sourceSprite)
&& sourceSprite.BaseRSI?.Path != null)
{ {
var sys = Get<EffectSystem>(); var lunge = attacker.EnsureComponent<MeleeLungeComponent>();
var curTime = _gameTiming.CurTime; lunge.SetData(msg.Angle);
var effect = new EffectSystemMessage
var entity = EntityManager.SpawnEntity(weaponArc.Prototype, attacker.Transform.Coordinates);
entity.Transform.LocalRotation = msg.Angle;
var weaponArcAnimation = entity.GetComponent<MeleeWeaponArcAnimationComponent>();
weaponArcAnimation.SetData(weaponArc, msg.Angle, attacker, msg.ArcFollowAttacker);
// Due to ISpriteComponent limitations, weapons that don't use an RSI won't have this effect.
if (EntityManager.TryGetEntity(msg.Source, out var source) && msg.TextureEffect && source.TryGetComponent(out ISpriteComponent sourceSprite)
&& sourceSprite.BaseRSI?.Path != null)
{ {
EffectSprite = sourceSprite.BaseRSI.Path.ToString(), var sys = Get<EffectSystem>();
RsiState = sourceSprite.LayerGetState(0).Name, var curTime = _gameTiming.CurTime;
Coordinates = attacker.Transform.Coordinates, var effect = new EffectSystemMessage
Color = Vector4.Multiply(new Vector4(255, 255, 255, 125), 1.0f), {
ColorDelta = Vector4.Multiply(new Vector4(0, 0, 0, -10), 1.0f), EffectSprite = sourceSprite.BaseRSI.Path.ToString(),
Velocity = msg.Angle.ToVec(), RsiState = sourceSprite.LayerGetState(0).Name,
Acceleration = msg.Angle.ToVec() * 5f, Coordinates = attacker.Transform.Coordinates,
Born = curTime, Color = Vector4.Multiply(new Vector4(255, 255, 255, 125), 1.0f),
DeathTime = curTime.Add(TimeSpan.FromMilliseconds(300f)), ColorDelta = Vector4.Multiply(new Vector4(0, 0, 0, -10), 1.0f),
}; Velocity = msg.Angle.ToVec(),
sys.CreateEffect(effect); Acceleration = msg.Angle.ToVec() * 5f,
Born = curTime,
DeathTime = curTime.Add(TimeSpan.FromMilliseconds(300f)),
};
sys.CreateEffect(effect);
}
} }
foreach (var uid in msg.Hits) foreach (var uid in msg.Hits)
{ {
if (!EntityManager.TryGetEntity(uid, out var hitEntity)) if (!EntityManager.TryGetEntity(uid, out var hitEntity) || hitEntity.Deleted)
{ {
continue; continue;
} }

View File

@@ -1,15 +1,20 @@
#nullable enable #nullable enable
using System; using System;
using Content.Server.Commands.Observer; using Content.Server.Commands.Observer;
using Content.Shared.Audio;
using Content.Shared.GameObjects.Components.Body; using Content.Shared.GameObjects.Components.Body;
using Content.Shared.GameObjects.Components.Body.Part; using Content.Shared.GameObjects.Components.Body.Part;
using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Mobs.State; using Content.Shared.GameObjects.Components.Mobs.State;
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.Utility;
using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.Components.Container;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Console;
using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Player;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Log; using Robust.Shared.Log;
using Robust.Shared.Players; using Robust.Shared.Players;
@@ -41,6 +46,7 @@ namespace Content.Server.GameObjects.Components.Body
base.OnRemovePart(slot, part); base.OnRemovePart(slot, part);
_partContainer.ForceRemove(part.Owner); _partContainer.ForceRemove(part.Owner);
part.Owner.RandomOffset(0.25f);
} }
public override void Initialize() public override void Initialize()
@@ -88,5 +94,29 @@ namespace Content.Server.GameObjects.Components.Body
new Ghost().Execute(shell, (IPlayerSession) session, Array.Empty<string>()); new Ghost().Execute(shell, (IPlayerSession) session, Array.Empty<string>());
} }
} }
public override void Gib(bool gibParts = false)
{
base.Gib(gibParts);
EntitySystem.Get<AudioSystem>()
.PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("gib"), Owner.Transform.Coordinates,
AudioHelpers.WithVariation(0.025f));
if (Owner.TryGetComponent(out ContainerManagerComponent? container))
{
foreach (var cont in container.GetAllContainers())
{
foreach (var ent in cont.ContainedEntities)
{
cont.ForceRemove(ent);
ent.Transform.Coordinates = Owner.Transform.Coordinates;
ent.RandomOffset(0.25f);
}
}
}
Owner.Delete();
}
} }
} }

View File

@@ -11,6 +11,7 @@ using Content.Shared.GameObjects.Components.Body.Surgery;
using Content.Shared.GameObjects.Verbs; using Content.Shared.GameObjects.Verbs;
using Content.Shared.Interfaces; using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
using Content.Shared.Utility;
using Robust.Server.Console; using Robust.Server.Console;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.Components.Container;
@@ -57,6 +58,7 @@ namespace Content.Server.GameObjects.Components.Body.Part
base.OnRemoveMechanism(mechanism); base.OnRemoveMechanism(mechanism);
_mechanismContainer.Remove(mechanism.Owner); _mechanismContainer.Remove(mechanism.Owner);
mechanism.Owner.RandomOffset(0.25f);
} }
public override void Initialize() public override void Initialize()

View File

@@ -0,0 +1,27 @@
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Body;
using JetBrains.Annotations;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior
{
[UsedImplicitly]
public class GibBehavior : IThresholdBehavior
{
private bool _recursive = true;
public void ExposeData(ObjectSerializer serializer)
{
serializer.DataField(ref _recursive, "recursive", true);
}
public void Trigger(IEntity owner, DestructibleSystem system)
{
if (owner.TryGetComponent(out IBody body))
{
body.Gib(_recursive);
}
}
}
}

View File

@@ -79,7 +79,7 @@ namespace Content.Server.GameObjects.Components.Recycling
// Mobs are a special case! // Mobs are a special case!
if (CanGib(entity)) if (CanGib(entity))
{ {
entity.Delete(); // TODO: Gib entity.GetComponent<IBody>().Gib(true);
Bloodstain(); Bloodstain();
return; return;
} }

View File

@@ -247,5 +247,10 @@ namespace Content.Shared.GameObjects.Components.Body
/// <param name="index">The index to look in.</param> /// <param name="index">The index to look in.</param>
/// <returns>A pair of the part name and body part occupying it.</returns> /// <returns>A pair of the part name and body part occupying it.</returns>
KeyValuePair<string, IBodyPart> PartAt(int index); KeyValuePair<string, IBodyPart> PartAt(int index);
/// <summary>
/// Gibs this body.
/// </summary>
void Gib(bool gibParts = false);
} }
} }

View File

@@ -116,5 +116,10 @@ namespace Content.Shared.GameObjects.Components.Body.Part
/// false otherwise. /// false otherwise.
/// </returns> /// </returns>
bool DeleteMechanism(IMechanism mechanism); bool DeleteMechanism(IMechanism mechanism);
/// <summary>
/// Gibs the body part.
/// </summary>
void Gib();
} }
} }

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Shared.GameObjects.Components.Body.Mechanism; using Content.Shared.GameObjects.Components.Body.Mechanism;
using Content.Shared.GameObjects.Components.Body.Surgery; using Content.Shared.GameObjects.Components.Body.Surgery;
using Content.Shared.Utility;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
@@ -313,6 +314,14 @@ namespace Content.Shared.GameObjects.Components.Body.Part
protected virtual void OnAddedToBody(IBody body) { } protected virtual void OnAddedToBody(IBody body) { }
protected virtual void OnRemovedFromBody(IBody old) { } protected virtual void OnRemovedFromBody(IBody old) { }
public virtual void Gib()
{
foreach (var mechanism in _mechanisms)
{
RemoveMechanism(mechanism);
}
}
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]

View File

@@ -1,6 +1,7 @@
#nullable enable #nullable enable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Content.Shared.Damage; using Content.Shared.Damage;
@@ -11,7 +12,10 @@ using Content.Shared.GameObjects.Components.Body.Template;
using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Utility;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Containers;
using Robust.Shared.GameObjects.Systems; using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
@@ -19,6 +23,7 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
using Component = Robust.Shared.GameObjects.Component;
namespace Content.Shared.GameObjects.Components.Body namespace Content.Shared.GameObjects.Components.Body
{ {
@@ -697,6 +702,17 @@ namespace Content.Shared.GameObjects.Components.Body
} }
} }
} }
public virtual void Gib(bool gibParts = false)
{
foreach (var (_, part) in Parts)
{
RemovePart(part);
if (gibParts)
part.Gib();
}
}
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,24 @@
- type: entity
id: BaseMechanism
parent: BaseItem
name: "base mechanism"
abstract: true
components:
- type: Mechanism
- type: entity
id: BaseHumanOrgan
parent: BaseMechanism
name: "base human organ"
abstract: true
components:
- type: Sprite
netsync: false
sprite: Mobs/Species/Human/organs.rsi
- type: entity - type: entity
id: BrainHuman id: BrainHuman
parent: BaseHumanOrgan
name: "human brain" name: "human brain"
description: "The source of incredible, unending intelligence. Honk." description: "The source of incredible, unending intelligence. Honk."
components: components:
@@ -16,6 +35,7 @@
- type: entity - type: entity
id: EyesHuman id: EyesHuman
parent: BaseHumanOrgan
name: "human eyes" name: "human eyes"
description: "Ocular organ capable of turning light into a colorful visual." description: "Ocular organ capable of turning light into a colorful visual."
components: components:
@@ -30,6 +50,7 @@
- type: entity - type: entity
id: HeartHuman id: HeartHuman
parent: BaseHumanOrgan
name: "human heart" name: "human heart"
description: "Pumps blood throughout a body. Essential for any entity with blood." description: "Pumps blood throughout a body. Essential for any entity with blood."
components: components:
@@ -46,6 +67,7 @@
- type: entity - type: entity
id: LungsHuman id: LungsHuman
parent: BaseHumanOrgan
name: "human lungs" name: "human lungs"
description: "Filters oxygen from an atmosphere, which is then sent into the bloodstream to be used as an electron carrier." description: "Filters oxygen from an atmosphere, which is then sent into the bloodstream to be used as an electron carrier."
components: components:
@@ -62,6 +84,7 @@
- type: entity - type: entity
id: StomachHuman id: StomachHuman
parent: BaseHumanOrgan
name: "human stomach" name: "human stomach"
description: "Gross. This is hard to stomach." description: "Gross. This is hard to stomach."
components: components:
@@ -82,6 +105,7 @@
- type: entity - type: entity
id: LiverHuman id: LiverHuman
parent: BaseHumanOrgan
name: "human liver" name: "human liver"
description: "Filters impurities out of a bloodstream and provides other important functionality to a human." description: "Filters impurities out of a bloodstream and provides other important functionality to a human."
components: components:
@@ -96,6 +120,7 @@
- type: entity - type: entity
id: KidneysHuman id: KidneysHuman
parent: BaseHumanOrgan
name: "human kidneys" name: "human kidneys"
description: "Filters toxins out of a bloodstream." description: "Filters toxins out of a bloodstream."
components: components:

View File

@@ -1,6 +1,7 @@
# TODO BODY: Part damage # TODO BODY: Part damage
- type: entity - type: entity
id: PartHuman id: PartHuman
parent: BaseItem
name: "human body part" name: "human body part"
abstract: true abstract: true

View File

@@ -161,6 +161,11 @@
0: !type:NormalMobState {} 0: !type:NormalMobState {}
100: !type:CriticalMobState {} 100: !type:CriticalMobState {}
200: !type:DeadMobState {} 200: !type:DeadMobState {}
- type: Destructible
thresholds:
400:
behaviors:
- !type:GibBehavior { }
- type: HeatResistance - type: HeatResistance
- type: Appearance - type: Appearance
visuals: visuals:

View File

@@ -528,7 +528,6 @@
- type: Sprite - type: Sprite
sprite: Objects/Fun/toys.rsi sprite: Objects/Fun/toys.rsi
state: foamblade state: foamblade
- type: MeleeWeapon - type: MeleeWeapon
range: 2.0 range: 2.0
arcwidth: 0 arcwidth: 0
@@ -539,6 +538,15 @@
HeldPrefix: foamblade HeldPrefix: foamblade
- type: ItemCooldown - type: ItemCooldown
- type: entity
name: foamblade
parent: FoamBlade
id: FoamBladeAdminbus
suffix: adminbused
components:
- type: MeleeWeapon
damage: 1000
# MISC # MISC
- type: entity - type: entity

View File

@@ -0,0 +1,6 @@
- type: soundCollection
id: gib
files:
- /Audio/Effects/gib1.ogg
- /Audio/Effects/gib2.ogg
- /Audio/Effects/gib3.ogg

View File

@@ -103,6 +103,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Fluidsynth/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Fluidsynth/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=freepats/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=freepats/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=gamemode/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=gamemode/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Gibs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=godmode/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=godmode/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Grindable/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Grindable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hardcode/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=hardcode/@EntryIndexedValue">True</s:Boolean>