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
This commit is contained in:
creadth
2020-09-03 21:35:39 +03:00
committed by GitHub
parent 5f79d3e31d
commit b8bf100277
7 changed files with 50 additions and 38 deletions

View File

@@ -152,6 +152,13 @@ namespace Content.Server.Body
[ViewVariables] [ViewVariables]
public IReadOnlyCollection<IMechanism> Mechanisms => _mechanisms; public IReadOnlyCollection<IMechanism> Mechanisms => _mechanisms;
/// <summary>
/// Represents if body part is vital for creature.
/// If the last vital body part is removed creature dies
/// </summary>
[ViewVariables]
public bool IsVital { get; private set; }
/// <summary> /// <summary>
/// This method is called by /// This method is called by
/// <see cref="IBodyManagerComponent.PreMetabolism"/> before /// <see cref="IBodyManagerComponent.PreMetabolism"/> before
@@ -451,6 +458,7 @@ namespace Content.Server.Body
RSIPath = data.RSIPath; RSIPath = data.RSIPath;
RSIState = data.RSIState; RSIState = data.RSIState;
MaxDurability = data.Durability; MaxDurability = data.Durability;
IsVital = data.IsVital;
if (!prototypeManager.TryIndex(data.DamageContainerPresetId, if (!prototypeManager.TryIndex(data.DamageContainerPresetId,
out DamageContainerPrototype damageContainerData)) out DamageContainerPrototype damageContainerData))

View File

@@ -82,6 +82,11 @@ namespace Content.Server.Body
// TODO: SpriteComponent rework // TODO: SpriteComponent rework
public Color? RSIColor { get; set; } public Color? RSIColor { get; set; }
/// <summary>
/// If body part is vital
/// </summary>
public bool IsVital { get; }
bool HasProperty<T>() where T : BodyPartProperty; bool HasProperty<T>() where T : BodyPartProperty;
bool HasProperty(Type type); bool HasProperty(Type type);

View File

@@ -279,16 +279,11 @@ namespace Content.Server.GameObjects.Components.Body
if (speedSum <= 0.001f || _activeLegs.Count <= 0) if (speedSum <= 0.001f || _activeLegs.Count <= 0)
{ {
// Case: no way of moving. Fall down.
EntitySystem.Get<StandingStateSystem>().Down(Owner);
playerMover.BaseWalkSpeed = 0.8f; playerMover.BaseWalkSpeed = 0.8f;
playerMover.BaseSprintSpeed = 2.0f; playerMover.BaseSprintSpeed = 2.0f;
} }
else else
{ {
// Case: have at least one leg. Set move speed.
EntitySystem.Get<StandingStateSystem>().Standing(Owner);
// Extra legs stack diminishingly. // Extra legs stack diminishingly.
// Final speed = speed sum/(leg count-log4(leg count)) // Final speed = speed sum/(leg count-log4(leg count))
playerMover.BaseWalkSpeed = playerMover.BaseWalkSpeed =
@@ -568,28 +563,10 @@ namespace Content.Server.GameObjects.Components.Body
{ {
DebugTools.AssertNotNull(part); DebugTools.AssertNotNull(part);
if (!_parts.ContainsValue(part)) var slotName = _parts.FirstOrDefault(x => x.Value == part).Key;
{ if (string.IsNullOrEmpty(slotName)) return;
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<string> connections))
{
// TODO: Optimize
foreach (var connectionName in connections)
{
if (TryGetBodyPart(connectionName, out var result) && !ConnectedToCenterPart(result))
{
DisconnectBodyPart(connectionName, dropEntity);
}
}
}
OnBodyChanged();
} }
/// <summary> /// <summary>
@@ -757,6 +734,21 @@ namespace Content.Server.GameObjects.Components.Body
SendNetworkMessage(mechanismMessage); 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<StandingStateSystem>().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; return true;
} }

View File

@@ -33,6 +33,8 @@ namespace Content.Shared.Body.Part
private string _rsiState; private string _rsiState;
private int _size; private int _size;
private string _surgeryDataName; private string _surgeryDataName;
private bool _isVital;
[ViewVariables] public string Name => _name; [ViewVariables] public string Name => _name;
@@ -66,6 +68,8 @@ namespace Content.Shared.Body.Part
[ViewVariables] public string ID => _id; [ViewVariables] public string ID => _id;
[ViewVariables] public bool IsVital => _isVital;
public virtual void LoadFrom(YamlMappingNode mapping) public virtual void LoadFrom(YamlMappingNode mapping)
{ {
var serializer = YamlObjectSerializer.NewReader(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 _resistanceSetId, "resistances", string.Empty);
serializer.DataField(ref _properties, "properties", new List<IExposeData>()); serializer.DataField(ref _properties, "properties", new List<IExposeData>());
serializer.DataField(ref _mechanisms, "mechanisms", new List<string>()); serializer.DataField(ref _mechanisms, "mechanisms", new List<string>());
serializer.DataField(ref _isVital, "isVital", false);
foreach (var property in _properties) foreach (var property in _properties)
{ {

View File

@@ -367,17 +367,20 @@ namespace Content.Shared.GameObjects.Components.Damage
protected virtual void OnHealthChanged(HealthChangedEventArgs e) protected virtual void OnHealthChanged(HealthChangedEventArgs e)
{ {
if (DeadThreshold != -1 && TotalDamage > DeadThreshold) if (CurrentDamageState != DamageState.Dead)
{ {
CurrentDamageState = DamageState.Dead; if (DeadThreshold != -1 && TotalDamage > DeadThreshold)
} {
else if (CriticalThreshold != -1 && TotalDamage > CriticalThreshold) CurrentDamageState = DamageState.Dead;
{ }
CurrentDamageState = DamageState.Critical; else if (CriticalThreshold != -1 && TotalDamage > CriticalThreshold)
} {
else CurrentDamageState = DamageState.Critical;
{ }
CurrentDamageState = DamageState.Alive; else
{
CurrentDamageState = DamageState.Alive;
}
} }
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, e); Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, e);

View File

@@ -33,6 +33,7 @@
damageContainer: biologicalDamageContainer damageContainer: biologicalDamageContainer
resistances: defaultResistances resistances: defaultResistances
surgeryDataType: Content.Server.Body.Surgery.BiologicalSurgeryData surgeryDataType: Content.Server.Body.Surgery.BiologicalSurgeryData
isVital: true
mechanisms: mechanisms:
- mechanism.Brain.BasicHuman - mechanism.Brain.BasicHuman
- mechanism.Eyes.BasicHuman - mechanism.Eyes.BasicHuman

View File

@@ -112,8 +112,6 @@
sprite: Mobs/Customization/human_hair.rsi sprite: Mobs/Customization/human_hair.rsi
- map: ["enum.Slots.MASK"] - map: ["enum.Slots.MASK"]
- map: ["enum.Slots.HEAD"] - map: ["enum.Slots.HEAD"]
- map: ["hand-left"]
- map: ["hand-right"]
- type: Icon - type: Icon
sprite: Mobs/Species/Human/parts.rsi sprite: Mobs/Species/Human/parts.rsi
state: full state: full