As discussed on the Discord, xenos are not humans (#1840)

* As discussed on the Discord, xenos are not humans

* Add living component for living beings without a defined body

* Merge LivingDamageable and Damageable components

* Fix ruinable and state manager inconsistencies

* Fix ruinable exposedata

* Fix new destructibles yamls

* Fix healing not healing

* Fix alive not being a valid state

* Fix valid state checking
This commit is contained in:
DrSmugleaf 2020-08-22 13:40:22 +02:00 committed by GitHub
parent f7c71b500f
commit bb923aa230
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 175 additions and 108 deletions

View File

@ -18,14 +18,12 @@ using Content.Shared.Body.Template;
using Content.Shared.GameObjects.Components.Body;
using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Movement;
using Robust.Server.GameObjects;
using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Players;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
@ -138,11 +136,6 @@ namespace Content.Server.GameObjects.Components.Body
base.Initialize();
LoadBodyPreset(Preset);
foreach (var behavior in Owner.GetAllComponents<IOnHealthChangedBehavior>())
{
HealthChangedEvent += behavior.OnHealthChanged;
}
}
protected override void Startup()

View File

@ -41,8 +41,6 @@ namespace Content.Server.GameObjects.Components.Damage
switch (eventArgs.Severity)
{
case ExplosionSeverity.Destruction:
PerformDestruction();
break;
case ExplosionSeverity.Heavy:
PerformDestruction();
break;

View File

@ -5,7 +5,6 @@ using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Damage
{
@ -18,13 +17,6 @@ namespace Content.Server.GameObjects.Components.Damage
{
private DamageState _currentDamageState;
/// <summary>
/// How much HP this component can sustain before triggering
/// <see cref="PerformDestruction"/>.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public int MaxHp { get; private set; }
/// <summary>
/// Sound played upon destruction.
/// </summary>
@ -35,29 +27,24 @@ namespace Content.Server.GameObjects.Components.Damage
public override DamageState CurrentDamageState => _currentDamageState;
public override void Initialize()
{
base.Initialize();
HealthChangedEvent += OnHealthChanged;
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(this, ruinable => ruinable.MaxHp, "maxHP", 100);
serializer.DataReadWriteFunction(
"deadThreshold",
100,
t => DeadThreshold = t ,
() => DeadThreshold ?? -1);
serializer.DataField(this, ruinable => ruinable.DestroySound, "destroySound", string.Empty);
}
public override void OnRemove()
protected override void EnterState(DamageState state)
{
base.OnRemove();
HealthChangedEvent -= OnHealthChanged;
}
base.EnterState(state);
private void OnHealthChanged(HealthChangedEventArgs e)
{
if (CurrentDamageState != DamageState.Dead && TotalDamage >= MaxHp)
if (state == DamageState.Dead)
{
PerformDestruction();
}

View File

@ -187,7 +187,12 @@ namespace Content.Server.GameObjects.Components.Mobs
{
case RuinableComponent ruinable:
{
var modifier = (int) (ruinable.TotalDamage / (ruinable.MaxHp / 7f));
if (ruinable.DeadThreshold == null)
{
break;
}
var modifier = (int) (ruinable.TotalDamage / (ruinable.DeadThreshold / 7f));
status.ChangeStatusEffectIcon(StatusEffect.Health,
"/Textures/Interface/StatusEffects/Human/human" + modifier + ".png");
@ -196,8 +201,12 @@ namespace Content.Server.GameObjects.Components.Mobs
}
case BodyManagerComponent body:
{
// TODO: Declare body max normal damage (currently 100)
var modifier = (int) (body.TotalDamage / (100f / 7f));
if (body.CriticalThreshold == null)
{
return;
}
var modifier = (int) (body.TotalDamage / (body.CriticalThreshold / 7f));
status.ChangeStatusEffectIcon(StatusEffect.Health,
"/Textures/Interface/StatusEffects/Human/human" + modifier + ".png");

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Damage;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
@ -11,15 +10,6 @@ namespace Content.Shared.GameObjects.Components.Body
public override string Name => "BodyManager";
public override uint? NetID => ContentNetIDs.BODY_MANAGER;
public override List<DamageState> SupportedDamageStates => new List<DamageState> {DamageState.Alive, DamageState.Critical, DamageState.Dead};
public override DamageState CurrentDamageState =>
CurrentDamageState = TotalDamage > 200
? DamageState.Dead
: TotalDamage > 100
? DamageState.Critical
: DamageState.Alive;
}
[Serializable, NetSerializable]

View File

@ -27,15 +27,62 @@ namespace Content.Shared.GameObjects.Components.Damage
public override string Name => "Damageable";
public event Action<HealthChangedEventArgs> HealthChangedEvent = default!;
private DamageState _currentDamageState;
public event Action<HealthChangedEventArgs>? HealthChangedEvent;
/// <summary>
/// The threshold of damage, if any, above which the entity enters crit.
/// -1 means that this entity cannot go into crit.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public int? CriticalThreshold { get; set; }
/// <summary>
/// The threshold of damage, if any, above which the entity dies.
/// -1 means that this entity cannot die.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public int? DeadThreshold { get; set; }
[ViewVariables] private ResistanceSet Resistance { get; set; } = default!;
[ViewVariables] private DamageContainer Damage { get; set; } = default!;
public virtual List<DamageState> SupportedDamageStates => new List<DamageState> {DamageState.Alive};
public virtual List<DamageState> SupportedDamageStates
{
get
{
var states = new List<DamageState> {DamageState.Alive};
public virtual DamageState CurrentDamageState { get; protected set; } = DamageState.Alive;
if (CriticalThreshold != null)
{
states.Add(DamageState.Critical);
}
if (DeadThreshold != null)
{
states.Add(DamageState.Dead);
}
return states;
}
}
public virtual DamageState CurrentDamageState
{
get => _currentDamageState;
set
{
var old = _currentDamageState;
_currentDamageState = value;
if (old != value)
{
EnterState(value);
}
}
}
[ViewVariables] public int TotalDamage => Damage.TotalDamage;
@ -47,6 +94,18 @@ namespace Content.Shared.GameObjects.Components.Damage
{
base.ExposeData(serializer);
serializer.DataReadWriteFunction(
"criticalThreshold",
-1,
t => CriticalThreshold = t == -1 ? (int?) null : t,
() => CriticalThreshold ?? -1);
serializer.DataReadWriteFunction(
"deadThreshold",
-1,
t => DeadThreshold = t == -1 ? (int?) null : t,
() => DeadThreshold ?? -1);
if (serializer.Reading)
{
// Doesn't write to file, TODO?
@ -75,6 +134,16 @@ namespace Content.Shared.GameObjects.Components.Damage
}
}
public override void Initialize()
{
base.Initialize();
foreach (var behavior in Owner.GetAllComponents<IOnHealthChangedBehavior>())
{
HealthChangedEvent += behavior.OnHealthChanged;
}
}
public bool TryGetDamage(DamageType type, out int damage)
{
return Damage.TryGetDamageValue(type, out damage);
@ -218,10 +287,26 @@ namespace Content.Shared.GameObjects.Components.Damage
OnHealthChanged(args);
}
protected virtual void EnterState(DamageState state) { }
protected virtual void OnHealthChanged(HealthChangedEventArgs e)
{
if (DeadThreshold != -1 && TotalDamage > DeadThreshold)
{
CurrentDamageState = DamageState.Dead;
}
else if (CriticalThreshold != -1 && TotalDamage > CriticalThreshold)
{
CurrentDamageState = DamageState.Critical;
}
else
{
CurrentDamageState = DamageState.Alive;
}
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, e);
HealthChangedEvent?.Invoke(e);
Dirty();
}
}

View File

@ -59,7 +59,7 @@
- type: SnapGrid
offset: Center
- type: Destructible
maxHP: 500
deadThreshold: 500
placement:
mode: SnapgridCenter

View File

@ -18,7 +18,7 @@
- type: Anchorable
- type: Pullable
- type: Destructible
maxHP: 50
deadThreshold: 50
- type: entity
name: bar stool
@ -51,7 +51,7 @@
- type: Anchorable
- type: Pullable
- type: Destructible
maxHP: 50
deadThreshold: 50
- type: entity
name: dark office chair
@ -86,7 +86,7 @@
- type: Anchorable
- type: Pullable
- type: Destructible
maxHP: 50
deadThreshold: 50
- type: entity
parent: Chair
@ -134,6 +134,6 @@
position: Down
rotation: -90
- type: Destructible
maxHP: 75
deadThreshold: 75
placement:
mode: SnapgridCenter

View File

@ -18,7 +18,7 @@
- type: SnapGrid
offset: Center
- type: Destructible
maxHP: 50
deadThreshold: 50
- type: UserInterface
interfaces:
- key: enum.InstrumentUiKey.Key
@ -43,7 +43,7 @@
name: minimoog
parent: BasePlaceableInstrument
id: MinimoogInstrument
description: 'This is a minimoog, like a space piano, but more spacey!'
description: 'This is a minimoog, like a space piano, but more spacey!'
components:
- type: Instrument
program: 81

View File

@ -14,7 +14,7 @@
- type: Clickable
- type: InteractionOutline
- type: Destructible
maxHP: 100
deadThreshold: 100
- type: Physics
- type: ShuttleController
- type: Strap

View File

@ -24,7 +24,7 @@
base: solid_
- type: Climbable
- type: Destructible
maxHP: 50
deadThreshold: 50
spawnOnDestroy: SteelSheet1
# TODO: drop wood instead of steel when destroyed when that's added
@ -40,5 +40,5 @@
key: wood
base: wood_
- type: Destructible
maxHP: 50
deadThreshold: 50
spawnOnDestroy: SteelSheet1

View File

@ -29,7 +29,7 @@
- type: Clickable
- type: InteractionOutline
- type: Breakable
maxHP: 150
deadThreshold: 150
- type: GravityGenerator
- type: UserInterface
interfaces:

View File

@ -35,7 +35,7 @@
offset: Center
- type: MedicalScanner
- type: Destructible
maxHP: 100
deadThreshold: 100
- type: Appearance
visuals:
- type: MedicalScannerVisualizer

View File

@ -51,7 +51,7 @@
- type: PowerConsumer
drawRate: 50
- type: Breakable
maxHP: 100
deadThreshold: 100
- type: Anchorable
- type: entity
@ -290,7 +290,7 @@
- type: SnapGrid
offset: Center
- type: Breakable
maxHP: 100
deadThreshold: 100
#Depriciated, to be removed from maps

View File

@ -31,7 +31,7 @@
- type: SnapGrid
offset: Center
- type: Breakable
maxHP: 50
deadThreshold: 50
- type: UserInterface
interfaces:
- key: enum.VendingMachineUiKey.Key

View File

@ -42,7 +42,7 @@
- type: EntityStorage
- type: PlaceableSurface
- type: Destructible
maxHP: 100
deadThreshold: 100
- type: Appearance
visuals:
- type: StorageVisualizer

View File

@ -26,7 +26,7 @@
mass: 15
Anchored: false
- type: Destructible
maxHP: 10
deadThreshold: 10
- type: Solution
maxVol: 1500
caps: 2

View File

@ -37,7 +37,7 @@
CanWeldShut: false
- type: PlaceableSurface
- type: Destructible
maxHP: 100
deadThreshold: 100
- type: Appearance
visuals:
- type: StorageVisualizer

View File

@ -17,7 +17,7 @@
- !type:PhysShapeAabb
layer: [MobMask]
- type: Destructible
maxHP: 100
deadThreshold: 100
- type: Occluder
sizeX: 32
sizeY: 32

View File

@ -15,7 +15,7 @@
- !type:PhysShapeAabb
layer: [MobMask, Opaque]
- type: Destructible
maxHP: 50
deadThreshold: 50
spawnOnDestroy: SteelSheet1
- type: SnapGrid
offset: Edge

View File

@ -46,7 +46,7 @@
bulb: Tube
- type: PowerReceiver
- type: Destructible
maxHP: 50
deadThreshold: 50
- type: entity
name: small light
@ -69,4 +69,4 @@
bulb: Bulb
- type: PowerReceiver
- type: Destructible
maxHP: 25
deadThreshold: 25

View File

@ -25,7 +25,7 @@
- VaultImpassable
- SmallImpassable
- type: Destructible
maxHP: 100
deadThreshold: 100
- type: SnapGrid
offset: Center
- type: LowWall

View File

@ -26,7 +26,7 @@
- VaultImpassable
- SmallImpassable
- type: Destructible
maxHP: 500
deadThreshold: 500
spawnOnDestroy: Girder
- type: Occluder
sizeX: 32
@ -49,7 +49,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/brick.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -65,7 +65,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/clock.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -81,7 +81,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/clown.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -98,7 +98,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/cult.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -114,7 +114,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/debug.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -130,7 +130,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/diamond.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -147,7 +147,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/gold.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -163,7 +163,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/ice.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -179,7 +179,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/metal.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -195,7 +195,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/plasma.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -211,7 +211,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/plastic.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -229,7 +229,7 @@
sprite: Constructible/Structures/Walls/solid.rsi
state: rgeneric
- type: Destructible
maxHP: 600
deadThreshold: 600
spawnOnDestroy: Girder
- type: ReinforcedWall
key: walls
@ -247,7 +247,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/riveted.rsi
- type: Destructible
maxHP: 1000
deadThreshold: 1000
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -263,7 +263,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/sandstone.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -279,7 +279,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/silver.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -296,7 +296,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/solid.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
destroySound: /Audio/Effects/metalbreak.ogg
- type: IconSmooth
@ -313,7 +313,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/uranium.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls
@ -329,7 +329,7 @@
- type: Icon
sprite: Constructible/Structures/Walls/wood.rsi
- type: Destructible
maxHP: 300
deadThreshold: 300
spawnOnDestroy: Girder
- type: IconSmooth
key: walls

View File

@ -28,7 +28,7 @@
- VaultImpassable
- SmallImpassable
- type: Destructible
maxHP: 100
deadThreshold: 100
- type: SnapGrid
offset: Center
- type: Airtight

View File

@ -39,9 +39,9 @@
layer:
- Opaque
- MobImpassable
- type: BodyManager
BaseTemplate: bodyTemplate.Humanoid
BasePreset: bodyPreset.BasicHuman
- type: Damageable
criticalThreshold: 50
deadThreshold: 100
- type: HeatResistance
- type: CombatMode
- type: Teleportable

View File

@ -34,9 +34,9 @@
layer:
- Opaque
- MobImpassable
- type: BodyManager
BaseTemplate: bodyTemplate.Humanoid
BasePreset: bodyPreset.BasicHuman
- type: Damageable
criticalThreshold: 50
deadThreshold: 100
- type: HeatResistance
- type: CombatMode
- type: Teleportable

View File

@ -34,9 +34,9 @@
layer:
- Opaque
- MobImpassable
- type: BodyManager
baseTemplate: bodyTemplate.Humanoid
basePreset: bodyPreset.BasicHuman
- type: Damageable
criticalThreshold: 100
deadThreshold: 200
- type: MobStateManager
- type: HeatResistance
- type: CombatMode

View File

@ -31,9 +31,9 @@
layer:
- Opaque
- MobImpassable
- type: BodyManager
BaseTemplate: bodyTemplate.Humanoid
BasePreset: bodyPreset.BasicHuman
- type: Damageable
criticalThreshold: 50
deadThreshold: 100
- type: HeatResistance
- type: CombatMode
- type: Teleportable

View File

@ -36,9 +36,9 @@
layer:
- Opaque
- MobImpassable
- type: BodyManager
baseTemplate: bodyTemplate.Humanoid
basePreset: bodyPreset.BasicHuman
- type: Damageable
criticalThreshold: 150
deadThreshold: 200
- type: Metabolism
- type: MobStateManager
- type: HeatResistance

View File

@ -126,6 +126,8 @@
- Opaque
- MobImpassable
- type: BodyManager
criticalThreshold: 100
deadThreshold: 200
baseTemplate: bodyTemplate.Humanoid
basePreset: bodyPreset.BasicHuman
- type: Metabolism
@ -256,6 +258,8 @@
layer:
- MobImpassable
- type: BodyManager
criticalThreshold: 100
deadThreshold: 200
baseTemplate: bodyTemplate.Humanoid
basePreset: bodyPreset.BasicHuman
- type: MobStateManager

View File

@ -22,7 +22,7 @@
lightImpactRange: 4
flashRange: 7
- type: Destructible
maxHP: 10
deadThreshold: 10
- type: Appearance
visuals:
- type: TimerTriggerVisualizer
@ -48,7 +48,7 @@
delay: 3.5
- type: FlashExplosive
- type: Destructible
maxHP: 10
deadThreshold: 10
- type: Appearance
visuals:
- type: TimerTriggerVisualizer
@ -78,7 +78,7 @@
lightImpactRange: 7
flashRange: 10
- type: Destructible
maxHP: 10
deadThreshold: 10
- type: Appearance
visuals:
- type: TimerTriggerVisualizer

View File

@ -65,6 +65,7 @@
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters&gt;&lt;Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;/ExcludeFilters&gt;&lt;/data&gt;</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Collidable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Cooldowns/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=crit/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=firelocks/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=diminishingly/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=flashable/@EntryIndexedValue">True</s:Boolean>