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:
@@ -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))
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user