Damage visualizer for simple mobs (#1332)

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
This commit is contained in:
metalgearsloth
2020-07-23 10:04:03 +10:00
committed by GitHub
parent 9585c7b82d
commit 56737b635f
11 changed files with 146 additions and 16 deletions

View File

@@ -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<DamageStateVisualData, string> _stateMap = new Dictionary<DamageStateVisualData,string>();
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<ISpriteComponent>();
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
}
}

View File

@@ -116,7 +116,7 @@ namespace Content.Server.AI.Utility.AiLogic
_planner = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AiActionSystem>();
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;
}

View File

@@ -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))
{

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -14,6 +14,20 @@
{
"name": "standing",
"directions": 4
},
{
"name": "dead",
"directions": 1
},
{
"name": "sleeping",
"directions": 1,
"delays": [
[
1.0,
1.0
]
]
}
]
}

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB