From b8bf1002770a948970a04c41321101475d96b411 Mon Sep 17 00:00:00 2001 From: creadth Date: Thu, 3 Sep 2020 21:35:39 +0300 Subject: [PATCH] Feature/1754 kill player on body parts missing (#2014) * Moved the uplink creation code to the PresetSuspicion.Start method to ensure uplink created when we give the traitor role Moved the starting TC balance to cvars * Added isVital flag for body parts Automatically killing creature if last vital body part removed Marked head as vital part --- Content.Server/Body/BodyPart.cs | 8 ++++ Content.Server/Body/IBodyPart.cs | 5 +++ .../Components/Body/BodyManagerComponent.cs | 44 ++++++++----------- Content.Shared/Body/Part/BodyPartPrototype.cs | 5 +++ .../Components/Damage/DamageableComponent.cs | 23 +++++----- .../Prototypes/Body/Parts/humanoid_parts.yml | 1 + .../Entities/Mobs/Species/human.yml | 2 - 7 files changed, 50 insertions(+), 38 deletions(-) diff --git a/Content.Server/Body/BodyPart.cs b/Content.Server/Body/BodyPart.cs index b176118af4..544ce651ec 100644 --- a/Content.Server/Body/BodyPart.cs +++ b/Content.Server/Body/BodyPart.cs @@ -152,6 +152,13 @@ namespace Content.Server.Body [ViewVariables] public IReadOnlyCollection Mechanisms => _mechanisms; + /// + /// Represents if body part is vital for creature. + /// If the last vital body part is removed creature dies + /// + [ViewVariables] + public bool IsVital { get; private set; } + /// /// This method is called by /// before @@ -451,6 +458,7 @@ namespace Content.Server.Body RSIPath = data.RSIPath; RSIState = data.RSIState; MaxDurability = data.Durability; + IsVital = data.IsVital; if (!prototypeManager.TryIndex(data.DamageContainerPresetId, out DamageContainerPrototype damageContainerData)) diff --git a/Content.Server/Body/IBodyPart.cs b/Content.Server/Body/IBodyPart.cs index 19d1ae9123..eaa49d0e06 100644 --- a/Content.Server/Body/IBodyPart.cs +++ b/Content.Server/Body/IBodyPart.cs @@ -82,6 +82,11 @@ namespace Content.Server.Body // TODO: SpriteComponent rework public Color? RSIColor { get; set; } + /// + /// If body part is vital + /// + public bool IsVital { get; } + bool HasProperty() where T : BodyPartProperty; bool HasProperty(Type type); diff --git a/Content.Server/GameObjects/Components/Body/BodyManagerComponent.cs b/Content.Server/GameObjects/Components/Body/BodyManagerComponent.cs index c7e658e2b9..29329a75dd 100644 --- a/Content.Server/GameObjects/Components/Body/BodyManagerComponent.cs +++ b/Content.Server/GameObjects/Components/Body/BodyManagerComponent.cs @@ -279,16 +279,11 @@ namespace Content.Server.GameObjects.Components.Body if (speedSum <= 0.001f || _activeLegs.Count <= 0) { - // Case: no way of moving. Fall down. - EntitySystem.Get().Down(Owner); playerMover.BaseWalkSpeed = 0.8f; playerMover.BaseSprintSpeed = 2.0f; } else { - // Case: have at least one leg. Set move speed. - EntitySystem.Get().Standing(Owner); - // Extra legs stack diminishingly. // Final speed = speed sum/(leg count-log4(leg count)) playerMover.BaseWalkSpeed = @@ -568,28 +563,10 @@ namespace Content.Server.GameObjects.Components.Body { DebugTools.AssertNotNull(part); - if (!_parts.ContainsValue(part)) - { - return; - } + var slotName = _parts.FirstOrDefault(x => x.Value == part).Key; + if (string.IsNullOrEmpty(slotName)) return; + DisconnectBodyPart(slotName, dropEntity); - var slotName = Parts.FirstOrDefault(x => x.Value == part).Key; - RemoveBodyPart(slotName, dropEntity); - - // Call disconnect on all limbs that were hanging off this limb - if (TryGetBodyPartConnections(slotName, out List connections)) - { - // TODO: Optimize - foreach (var connectionName in connections) - { - if (TryGetBodyPart(connectionName, out var result) && !ConnectedToCenterPart(result)) - { - DisconnectBodyPart(connectionName, dropEntity); - } - } - } - - OnBodyChanged(); } /// @@ -757,6 +734,21 @@ namespace Content.Server.GameObjects.Components.Body SendNetworkMessage(mechanismMessage); } + if (CurrentDamageState == DamageState.Dead) return true; + + // creadth: fall down if no legs + if (part.PartType == BodyPartType.Leg && Parts.Count(x => x.Value.PartType == BodyPartType.Leg) == 0) + { + EntitySystem.Get().Down(Owner); + } + + // creadth: immediately kill entity if last vital part removed + if (part.IsVital && Parts.Count(x => x.Value.PartType == part.PartType) == 0) + { + CurrentDamageState = DamageState.Dead; + ForceHealthChangedEvent(); + } + return true; } diff --git a/Content.Shared/Body/Part/BodyPartPrototype.cs b/Content.Shared/Body/Part/BodyPartPrototype.cs index 7d6158dce3..dd3f64a544 100644 --- a/Content.Shared/Body/Part/BodyPartPrototype.cs +++ b/Content.Shared/Body/Part/BodyPartPrototype.cs @@ -33,6 +33,8 @@ namespace Content.Shared.Body.Part private string _rsiState; private int _size; private string _surgeryDataName; + private bool _isVital; + [ViewVariables] public string Name => _name; @@ -66,6 +68,8 @@ namespace Content.Shared.Body.Part [ViewVariables] public string ID => _id; + [ViewVariables] public bool IsVital => _isVital; + public virtual void LoadFrom(YamlMappingNode mapping) { var serializer = YamlObjectSerializer.NewReader(mapping); @@ -86,6 +90,7 @@ namespace Content.Shared.Body.Part serializer.DataField(ref _resistanceSetId, "resistances", string.Empty); serializer.DataField(ref _properties, "properties", new List()); serializer.DataField(ref _mechanisms, "mechanisms", new List()); + serializer.DataField(ref _isVital, "isVital", false); foreach (var property in _properties) { diff --git a/Content.Shared/GameObjects/Components/Damage/DamageableComponent.cs b/Content.Shared/GameObjects/Components/Damage/DamageableComponent.cs index 7fdfeba0ac..551ffd026d 100644 --- a/Content.Shared/GameObjects/Components/Damage/DamageableComponent.cs +++ b/Content.Shared/GameObjects/Components/Damage/DamageableComponent.cs @@ -367,17 +367,20 @@ namespace Content.Shared.GameObjects.Components.Damage protected virtual void OnHealthChanged(HealthChangedEventArgs e) { - if (DeadThreshold != -1 && TotalDamage > DeadThreshold) + if (CurrentDamageState != DamageState.Dead) { - CurrentDamageState = DamageState.Dead; - } - else if (CriticalThreshold != -1 && TotalDamage > CriticalThreshold) - { - CurrentDamageState = DamageState.Critical; - } - else - { - CurrentDamageState = DamageState.Alive; + 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); diff --git a/Resources/Prototypes/Body/Parts/humanoid_parts.yml b/Resources/Prototypes/Body/Parts/humanoid_parts.yml index 5437b3e6a3..a9964674e2 100644 --- a/Resources/Prototypes/Body/Parts/humanoid_parts.yml +++ b/Resources/Prototypes/Body/Parts/humanoid_parts.yml @@ -33,6 +33,7 @@ damageContainer: biologicalDamageContainer resistances: defaultResistances surgeryDataType: Content.Server.Body.Surgery.BiologicalSurgeryData + isVital: true mechanisms: - mechanism.Brain.BasicHuman - mechanism.Eyes.BasicHuman diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index f309bea3d5..e672beebd5 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -112,8 +112,6 @@ sprite: Mobs/Customization/human_hair.rsi - map: ["enum.Slots.MASK"] - map: ["enum.Slots.HEAD"] - - map: ["hand-left"] - - map: ["hand-right"] - type: Icon sprite: Mobs/Species/Human/parts.rsi state: full