using System.Collections.Generic; using Gamesmiths.Forge.Attributes; using Gamesmiths.Forge.Core; using Gamesmiths.Forge.Effects; using Gamesmiths.Forge.Effects.Calculator; using Gamesmiths.Forge.Effects.Magnitudes; using Gamesmiths.Forge.Effects.Modifiers; using Gamesmiths.Forge.Events; using Gamesmiths.Forge.Godot.Core; using Gamesmiths.Forge.Godot.Resources; using Gamesmiths.Forge.Godot.Resources.Calculators; using Gamesmiths.Forge.Tags; using Godot; namespace Movementtests.tools.calculators; public record DamageDone(DamageType DamageType, float Damage, float OverkillDamage); public class DamageExecution : CustomExecution { private readonly DamageType _damageType; private readonly ForgeTagContainer? _damageDealerEventTags; private readonly ForgeTagContainer? _damageReceiverEventTags; // Define attributes to capture and modify public AttributeCaptureDefinition TargetHealth { get; } public AttributeCaptureDefinition TargetIncomingDamage { get; } public DamageExecution(DamageType damageType, ForgeTagContainer? damageDealerEventTags, ForgeTagContainer? damageReceiverEventTags) { // Capture target mana and magic resistance TargetHealth = new AttributeCaptureDefinition( "CharacterAttributeSet.Health", AttributeCaptureSource.Target, false); TargetIncomingDamage = new AttributeCaptureDefinition( "MetaAttributeSet.IncomingDamage", AttributeCaptureSource.Target); // Register attributes for capture AttributesToCapture.Add(TargetHealth); AttributesToCapture.Add(TargetIncomingDamage); _damageType = damageType; _damageDealerEventTags = damageDealerEventTags; _damageReceiverEventTags = damageReceiverEventTags; } public override ModifierEvaluatedData[] EvaluateExecution( Effect effect, IForgeEntity target, EffectEvaluatedData? effectEvaluatedData) { var results = new List(); float targetIncomingDamage = CaptureAttributeMagnitude( TargetIncomingDamage, effect, target, effectEvaluatedData); if (targetIncomingDamage <= 0) { return [.. results]; } if (effectEvaluatedData?.TryGetContextData(out float multiplier) == true) { targetIncomingDamage *= multiplier; } // Apply health reduction to target if attribute exists if (TargetHealth.TryGetAttribute(target, out EntityAttribute? targetHealthAttribute)) { results.Add(new ModifierEvaluatedData( targetHealthAttribute, ModifierOperation.FlatBonus, -targetIncomingDamage)); // Negative for damage } var finalDamage = targetIncomingDamage; var overkillDamage = 0.0f; if (targetHealthAttribute!.CurrentValue - targetIncomingDamage <= targetHealthAttribute.Min) { finalDamage = targetHealthAttribute.CurrentValue - targetHealthAttribute.Min; overkillDamage = targetIncomingDamage - finalDamage; } if (_damageReceiverEventTags is null) return [.. results]; target.Events.Raise(new EventData { EventTags = _damageReceiverEventTags.GetTagContainer(), Source = effect.Ownership.Owner, Target = target, EventMagnitude = finalDamage, Payload = new DamageDone(_damageType, finalDamage, overkillDamage) }); if (effect.Ownership.Source is null || _damageDealerEventTags is null) { return [.. results]; } effect.Ownership.Source.Events.Raise(new EventData { EventTags = _damageDealerEventTags.GetTagContainer(), Source = effect.Ownership.Owner, Target = target, EventMagnitude = finalDamage, Payload = new DamageDone(_damageType, finalDamage, overkillDamage) }); return [.. results]; } } [Tool] [GlobalClass] public partial class ForgeDamageExecution : ForgeCustomExecution { [Export] public DamageType DamageType { get; set; } = DamageType.Physical; [Export] public ForgeTagContainer? DamageDealerEventTags { get; set; } [Export] public ForgeTagContainer? DamageReceiverEventTags { get; set; } public override CustomExecution GetExecutionClass() { return new DamageExecution(DamageType, DamageDealerEventTags, DamageReceiverEventTags); } }