1
0

SharedSuicideSystem.cs 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. using Content.Shared.Damage;
  2. using Content.Shared.Damage.Prototypes;
  3. using Content.Shared.Mobs.Components;
  4. using Robust.Shared.Prototypes;
  5. using System.Linq;
  6. namespace Content.Shared.Chat;
  7. public sealed class SharedSuicideSystem : EntitySystem
  8. {
  9. [Dependency] private readonly DamageableSystem _damageableSystem = default!;
  10. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  11. /// <summary>
  12. /// Applies lethal damage spread out across the damage types given.
  13. /// </summary>
  14. public void ApplyLethalDamage(Entity<DamageableComponent> target, DamageSpecifier damageSpecifier)
  15. {
  16. // Create a new damageSpecifier so that we don't make alterations to the original DamageSpecifier
  17. // Failing to do this will permanently change a weapon's damage making it insta-kill people
  18. var appliedDamageSpecifier = new DamageSpecifier(damageSpecifier);
  19. if (!TryComp<MobThresholdsComponent>(target, out var mobThresholds))
  20. return;
  21. // Mob thresholds are sorted from alive -> crit -> dead,
  22. // grabbing the last key will give us how much damage is needed to kill a target from zero
  23. // The exact lethal damage amount is adjusted based on their current damage taken
  24. var lethalAmountOfDamage = mobThresholds.Thresholds.Keys.Last() - target.Comp.TotalDamage;
  25. var totalDamage = appliedDamageSpecifier.GetTotal();
  26. // Removing structural because it causes issues against entities that cannot take structural damage,
  27. // then getting the total to use in calculations for spreading out damage.
  28. appliedDamageSpecifier.DamageDict.Remove("Structural");
  29. // Split the total amount of damage needed to kill the target by every damage type in the DamageSpecifier
  30. foreach (var (key, value) in appliedDamageSpecifier.DamageDict)
  31. {
  32. appliedDamageSpecifier.DamageDict[key] = Math.Ceiling((double) (value * lethalAmountOfDamage / totalDamage));
  33. }
  34. _damageableSystem.TryChangeDamage(target, appliedDamageSpecifier, true, origin: target);
  35. }
  36. /// <summary>
  37. /// Applies lethal damage in a single type, specified by a single damage type.
  38. /// </summary>
  39. public void ApplyLethalDamage(Entity<DamageableComponent> target, ProtoId<DamageTypePrototype>? damageType)
  40. {
  41. if (!TryComp<MobThresholdsComponent>(target, out var mobThresholds))
  42. return;
  43. // Mob thresholds are sorted from alive -> crit -> dead,
  44. // grabbing the last key will give us how much damage is needed to kill a target from zero
  45. // The exact lethal damage amount is adjusted based on their current damage taken
  46. var lethalAmountOfDamage = mobThresholds.Thresholds.Keys.Last() - target.Comp.TotalDamage;
  47. // We don't want structural damage for the same reasons listed above
  48. if (!_prototypeManager.TryIndex(damageType, out var damagePrototype) || damagePrototype.ID == "Structural")
  49. {
  50. Log.Error($"{nameof(SharedSuicideSystem)} could not find the damage type prototype associated with {damageType}. Falling back to Blunt");
  51. damagePrototype = _prototypeManager.Index<DamageTypePrototype>("Blunt");
  52. }
  53. var damage = new DamageSpecifier(damagePrototype, lethalAmountOfDamage);
  54. _damageableSystem.TryChangeDamage(target, damage, true, origin: target);
  55. }
  56. }