From 56737b635f40c6269862f945bf79919338434789 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 23 Jul 2020 10:04:03 +1000 Subject: [PATCH] Damage visualizer for simple mobs (#1332) Co-authored-by: Metal Gear Sloth Co-authored-by: Pieter-Jan Briers --- .../Components/Mobs/DamageStateVisualizer.cs | 78 ++++++++++++++++++ .../AI/Utility/AiLogic/UtilityAI.cs | 17 ++-- .../Components/Mobs/DamageStates.cs | 8 ++ .../AI/Steering/AiSteeringSystem.cs | 4 + .../Components/Mobs/SharedDamageState.cs | 19 +++++ .../Prototypes/Entities/Mobs/NPCs/xeno.yml | 22 +++-- .../Mobs/Species/xeno_hunter.rsi/dead.png | Bin 0 -> 6014 bytes .../{xeno.rsi => xeno_hunter.rsi}/meta.json | 14 ++++ .../{xeno.rsi => xeno_hunter.rsi}/running.png | Bin .../Mobs/Species/xeno_hunter.rsi/sleeping.png | Bin 0 -> 7639 bytes .../standing.png | Bin 11 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 Content.Client/GameObjects/Components/Mobs/DamageStateVisualizer.cs create mode 100644 Content.Shared/GameObjects/Components/Mobs/SharedDamageState.cs create mode 100644 Resources/Textures/Mobs/Species/xeno_hunter.rsi/dead.png rename Resources/Textures/Mobs/Species/{xeno.rsi => xeno_hunter.rsi}/meta.json (59%) rename Resources/Textures/Mobs/Species/{xeno.rsi => xeno_hunter.rsi}/running.png (100%) create mode 100644 Resources/Textures/Mobs/Species/xeno_hunter.rsi/sleeping.png rename Resources/Textures/Mobs/Species/{xeno.rsi => xeno_hunter.rsi}/standing.png (100%) diff --git a/Content.Client/GameObjects/Components/Mobs/DamageStateVisualizer.cs b/Content.Client/GameObjects/Components/Mobs/DamageStateVisualizer.cs new file mode 100644 index 0000000000..556e066e1f --- /dev/null +++ b/Content.Client/GameObjects/Components/Mobs/DamageStateVisualizer.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using Content.Shared.GameObjects.Components.Mobs; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; +using DrawDepth = Content.Shared.GameObjects.DrawDepth; + +namespace Content.Client.GameObjects.Components.Mobs +{ + [UsedImplicitly] + public sealed class DamageStateVisualizer : AppearanceVisualizer + { + private DamageStateVisualData _data = DamageStateVisualData.Normal; + private Dictionary _stateMap = new Dictionary(); + private int? _originalDrawDepth = null; + + public override void LoadData(YamlMappingNode node) + { + base.LoadData(node); + if (node.TryGetNode("normal", out var normal)) + { + _stateMap.Add(DamageStateVisualData.Normal, normal.AsString()); + } + + if (node.TryGetNode("crit", out var crit)) + { + _stateMap.Add(DamageStateVisualData.Crit, crit.AsString()); + } + + if (node.TryGetNode("dead", out var dead)) + { + _stateMap.Add(DamageStateVisualData.Dead, dead.AsString()); + } + } + + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + var sprite = component.Owner.GetComponent(); + if (!component.TryGetData(DamageStateVisuals.State, out DamageStateVisualData data)) + { + return; + } + + if (_data == data) + { + return; + } + + _data = data; + + if (_stateMap.TryGetValue(_data, out var state)) + { + sprite.LayerSetState(DamageStateVisualLayers.Base, state); + } + + // So they don't draw over mobs anymore + if (_data == DamageStateVisualData.Dead) + { + _originalDrawDepth = sprite.DrawDepth; + sprite.DrawDepth = (int) DrawDepth.FloorObjects; + } + else if (_originalDrawDepth != null) + { + sprite.DrawDepth = _originalDrawDepth.Value; + _originalDrawDepth = null; + } + } + } + + public enum DamageStateVisualLayers + { + Base + } +} diff --git a/Content.Server/AI/Utility/AiLogic/UtilityAI.cs b/Content.Server/AI/Utility/AiLogic/UtilityAI.cs index 5847deb850..791727b637 100644 --- a/Content.Server/AI/Utility/AiLogic/UtilityAI.cs +++ b/Content.Server/AI/Utility/AiLogic/UtilityAI.cs @@ -116,7 +116,7 @@ namespace Content.Server.AI.Utility.AiLogic _planner = IoCManager.Resolve().GetEntitySystem(); if (SelfEntity.TryGetComponent(out DamageableComponent damageableComponent)) { - damageableComponent.DamageThresholdPassed += DeathHandle; + damageableComponent.DamageThresholdPassed += DamageThresholdHandle; } } @@ -125,22 +125,25 @@ namespace Content.Server.AI.Utility.AiLogic // TODO: If DamageableComponent removed still need to unsubscribe? if (SelfEntity.TryGetComponent(out DamageableComponent damageableComponent)) { - damageableComponent.DamageThresholdPassed -= DeathHandle; + damageableComponent.DamageThresholdPassed -= DamageThresholdHandle; } var currentOp = CurrentAction?.ActionOperators.Peek(); currentOp?.Shutdown(Outcome.Failed); } - private void DeathHandle(object sender, DamageThresholdPassedEventArgs eventArgs) + private void DamageThresholdHandle(object sender, DamageThresholdPassedEventArgs eventArgs) { - if (eventArgs.DamageThreshold.ThresholdType == ThresholdType.Death) + if (!SelfEntity.TryGetComponent(out SpeciesComponent speciesComponent)) + { + return; + } + + if (speciesComponent.CurrentDamageState is DeadState) { _isDead = true; } - - // TODO: If we get healed - double-check what it should be - if (eventArgs.DamageThreshold.ThresholdType == ThresholdType.None) + else { _isDead = false; } diff --git a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs index 6ee267da41..69e354e7bc 100644 --- a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs +++ b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs @@ -1,6 +1,8 @@ using Content.Server.GameObjects.Components.Mobs; using Content.Server.Mobs; +using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.EntitySystems; +using Robust.Server.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; @@ -25,6 +27,8 @@ namespace Content.Server.GameObjects { public void EnterState(IEntity entity) { + entity.TryGetComponent(out AppearanceComponent appearanceComponent); + appearanceComponent?.SetData(DamageStateVisuals.State, DamageStateVisualData.Normal); } public void ExitState(IEntity entity) @@ -104,6 +108,8 @@ namespace Content.Server.GameObjects if(entity.TryGetComponent(out StunnableComponent stun)) stun.CancelAll(); + entity.TryGetComponent(out AppearanceComponent appearanceComponent); + appearanceComponent?.SetData(DamageStateVisuals.State, DamageStateVisualData.Crit); StandingStateHelper.Down(entity); } @@ -186,6 +192,8 @@ namespace Content.Server.GameObjects stun.CancelAll(); StandingStateHelper.Down(entity); + entity.TryGetComponent(out AppearanceComponent appearanceComponent); + appearanceComponent?.SetData(DamageStateVisuals.State, DamageStateVisualData.Dead); if (entity.TryGetComponent(out ICollidableComponent collidable)) { diff --git a/Content.Server/GameObjects/EntitySystems/AI/Steering/AiSteeringSystem.cs b/Content.Server/GameObjects/EntitySystems/AI/Steering/AiSteeringSystem.cs index ff51d9af76..ba92f7122d 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/Steering/AiSteeringSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/Steering/AiSteeringSystem.cs @@ -634,6 +634,10 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Steering // God there's so many ways to do this // err for now we'll just assume the first entity is the center and just add a vector for it var collisionEntity = _entityManager.GetEntity(uid); + + //Pathfinding updates are deferred so this may not be done yet. + if (collisionEntity.Deleted) continue; + // if we're moving in the same direction then ignore // So if 2 entities are moving towards each other and both detect a collision they'll both move in the same direction // i.e. towards the right diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedDamageState.cs b/Content.Shared/GameObjects/Components/Mobs/SharedDamageState.cs new file mode 100644 index 0000000000..b6cc81cef2 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Mobs/SharedDamageState.cs @@ -0,0 +1,19 @@ +using System; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Mobs +{ + [Serializable, NetSerializable] + public enum DamageStateVisuals + { + State + } + + [Serializable, NetSerializable] + public enum DamageStateVisualData + { + Normal, + Crit, + Dead + } +} \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml index ed6b0bdc1c..d2873913a9 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml @@ -1,7 +1,7 @@ # Hacky for the stress test so don't even consider adding to this - type: entity save: false - name: Xeno + name: Xeno hunter id: XenoMob_Content description: They mostly come at night. Mostly. drawdepth: Mobs @@ -14,15 +14,16 @@ - left - right - type: MovementSpeedModifier - # Organs - type: InteractionOutline - type: Sprite drawdepth: Mobs - sprite: Mobs/Species/xeno.rsi - state: running + layers: + - map: ["enum.DamageStateVisualLayers.Base"] + state: running + sprite: Mobs/Species/xeno_hunter.rsi - type: Icon - sprite: Mobs/Species/xeno.rsi - state: running + sprite: Mobs/Species/xeno_hunter.rsi + state: standing - type: Clickable - type: Physics mass: 85 @@ -48,13 +49,16 @@ - type: Damageable - type: CombatMode - type: Teleportable - - type: CharacterInfo - type: FootstepSound - - type: HumanoidAppearance - type: Stunnable - - type: AnimationPlayer - type: UnarmedCombat range: 1.5 arcwidth: 0 arc: claw damage: 90 + - type: Appearance + visuals: + - type: DamageStateVisualizer2D + normal: running + dead: dead + \ No newline at end of file diff --git a/Resources/Textures/Mobs/Species/xeno_hunter.rsi/dead.png b/Resources/Textures/Mobs/Species/xeno_hunter.rsi/dead.png new file mode 100644 index 0000000000000000000000000000000000000000..6768e30ca1282a37ddda59ff1127ea8655089de7 GIT binary patch literal 6014 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/xeno.rsi/meta.json b/Resources/Textures/Mobs/Species/xeno_hunter.rsi/meta.json similarity index 59% rename from Resources/Textures/Mobs/Species/xeno.rsi/meta.json rename to Resources/Textures/Mobs/Species/xeno_hunter.rsi/meta.json index b6ea7da0c2..c8115c140c 100644 --- a/Resources/Textures/Mobs/Species/xeno.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/xeno_hunter.rsi/meta.json @@ -14,6 +14,20 @@ { "name": "standing", "directions": 4 + }, + { + "name": "dead", + "directions": 1 + }, + { + "name": "sleeping", + "directions": 1, + "delays": [ + [ + 1.0, + 1.0 + ] + ] } ] } \ No newline at end of file diff --git a/Resources/Textures/Mobs/Species/xeno.rsi/running.png b/Resources/Textures/Mobs/Species/xeno_hunter.rsi/running.png similarity index 100% rename from Resources/Textures/Mobs/Species/xeno.rsi/running.png rename to Resources/Textures/Mobs/Species/xeno_hunter.rsi/running.png diff --git a/Resources/Textures/Mobs/Species/xeno_hunter.rsi/sleeping.png b/Resources/Textures/Mobs/Species/xeno_hunter.rsi/sleeping.png new file mode 100644 index 0000000000000000000000000000000000000000..1368da006b0af4cc15559162b83b40226fecfd60 GIT binary patch literal 7639 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 FV1m14@J#>! literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/xeno.rsi/standing.png b/Resources/Textures/Mobs/Species/xeno_hunter.rsi/standing.png similarity index 100% rename from Resources/Textures/Mobs/Species/xeno.rsi/standing.png rename to Resources/Textures/Mobs/Species/xeno_hunter.rsi/standing.png