// DeltaV Start - Fix EvenHealing with Limbs. using System.Linq; using Content.Shared._Shitmed.Targeting; using Content.Shared.Body.Systems; // DeltaV End - Fix EvenHealing with Limbs. using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.EntityEffects; using Content.Shared.FixedPoint; using Content.Shared.Localizations; using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Shared.EntityEffects.Effects; /// /// Version of that distributes the healing to groups /// public sealed partial class EvenHealthChange : EntityEffect { /// /// Damage to heal, collected into entire damage groups. /// [DataField(required: true)] public Dictionary, FixedPoint2> Damage = new(); /// /// Should this effect scale the damage by the amount of chemical in the solution? /// Useful for touch reactions, like styptic powder or acid. /// Only usable if the EntityEffectBaseArgs is an EntityEffectReagentArgs. /// [DataField] public bool ScaleByQuantity; /// /// Should this effect ignore damage modifiers? /// [DataField] public bool IgnoreResistances = true; protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) { var damages = new List(); var heals = false; var deals = false; var damagableSystem = entSys.GetEntitySystem(); var universalReagentDamageModifier = damagableSystem.UniversalReagentDamageModifier; var universalReagentHealModifier = damagableSystem.UniversalReagentHealModifier; foreach (var (group, amount) in Damage) { var groupProto = prototype.Index(group); var sign = FixedPoint2.Sign(amount); var mod = 1f; if (sign < 0) { heals = true; mod = universalReagentHealModifier; } else if (sign > 0) { deals = true; mod = universalReagentDamageModifier; } damages.Add( Loc.GetString("health-change-display", ("kind", groupProto.LocalizedName), ("amount", MathF.Abs(amount.Float() * mod)), ("deltasign", sign) )); } var healsordeals = heals ? (deals ? "both" : "heals") : (deals ? "deals" : "none"); return Loc.GetString("reagent-effect-guidebook-even-health-change", ("chance", Probability), ("changes", ContentLocalizationManager.FormatList(damages)), ("healsordeals", healsordeals)); } public override void Effect(EntityEffectBaseArgs args) { if (!args.EntityManager.TryGetComponent(args.TargetEntity, out var damageable)) return; var protoMan = IoCManager.Resolve(); var scale = FixedPoint2.New(1); if (args is EntityEffectReagentArgs reagentArgs) { scale = ScaleByQuantity ? reagentArgs.Quantity * reagentArgs.Scale : reagentArgs.Scale; } var damagableSystem = args.EntityManager.System(); var dspec = GetDamageSpec(protoMan, damageable); // DeltaV - Fix EvenHealing with Limbs. damagableSystem.TryChangeDamage( args.TargetEntity, dspec * scale, IgnoreResistances, interruptsDoAfters: false, doPartDamage: false); // DeltaV - Fix EvenHealing with Limbs. // DeltaV Start - Fix EvenHealing with Limbs. var bodySystem = args.EntityManager.System(); var bodyParts = SharedTargetingSystem.GetValidParts(); foreach (var bodyPart in bodyParts) { var (targetType, targetSymmetry) = bodySystem.ConvertTargetBodyPart(bodyPart); if (bodySystem.GetBodyChildrenOfType(args.TargetEntity, targetType, symmetry: targetSymmetry) is { } part) { if (!args.EntityManager.TryGetComponent(part.FirstOrDefault().Id, out var damageablePart)) continue; dspec = GetDamageSpec(protoMan, damageablePart); if (dspec.GetTotal() == 0) continue; damagableSystem.TryChangeDamage( args.TargetEntity, dspec * scale, IgnoreResistances, interruptsDoAfters: false, targetPart: bodyPart, onlyDamageParts: true, canSever: false); } } // DeltaV End - Fix EvenHealing with Limbs. } private DamageSpecifier GetDamageSpec(IPrototypeManager protoMan, DamageableComponent damageable) // DeltaV - Fix EvenHealing with Limbs. { var damageSpecifier = new DamageSpecifier(); // DeltaV - Fix EvenHealing with Limbs. foreach (var (group, amount) in Damage) { var groupProto = protoMan.Index(group); var groupDamage = new Dictionary(); foreach (var damageId in groupProto.DamageTypes) { var damageAmount = damageable.Damage.DamageDict.GetValueOrDefault(damageId); if (damageAmount != FixedPoint2.Zero) groupDamage.Add(damageId, damageAmount); } var sum = groupDamage.Values.Sum(); foreach (var (damageId, damageAmount) in groupDamage) { var existing = damageSpecifier.DamageDict.GetOrNew(damageId); // DeltaV - Fix EvenHealing with Limbs. damageSpecifier.DamageDict[damageId] = existing + damageAmount / sum * amount; // DeltaV - Fix EvenHealing with Limbs. } } return damageSpecifier; // DeltaV - Fix EvenHealing with Limbs. } }