// MIT License - Copyright (c) 2025 wallstop
// Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE
namespace WallstopStudios.UnityHelpers.Tags
{
using System;
using System.Text.Json.Serialization;
using Core.Extension;
using Core.Helper;
using ProtoBuf;
using WallstopStudios.UnityHelpers.Core.Attributes;
///
/// Declarative change applied to an .
/// Each instance represents a single operation (add, multiply, or override) referenced by an .
///
///
/// Key properties:
///
/// - Non-destructive: temporary handles can add/remove modifications without mutating base values.
/// - Deterministic ordering: always processes Addition, then Multiplication, then Override.
/// - Flexible authoring: supports both instant (permanent) and duration-based effects.
///
/// Stack processing order:
///
/// - Addition (value += x)
/// - Multiplication (value *= x)
/// - Override (value = x)
///
///
/// The field must match an field on the target .
/// The Attribute Metadata Cache generator can provide editor dropdowns to avoid typos. Unknown names are ignored at runtime.
///
/// Sample definitions:
///
/// // +50 flat health
/// new AttributeModification { attribute = "Health", action = ModificationAction.Addition, value = 50f };
///
/// // +50% speed
/// new AttributeModification { attribute = "Speed", action = ModificationAction.Multiplication, value = 1.5f };
///
/// // Hard-set defense to 0
/// new AttributeModification { attribute = "Defense", action = ModificationAction.Override, value = 0f };
///
/// Authoring tips:
///
/// - Use Addition for flat buffs/debuffs; Multiplication for percentage-style adjustments.
/// - Reserve Override for hard clamps (it always executes last).
/// - Negative Addition subtracts; Multiplication values below 1.0 reduce the attribute.
///
///
[Serializable]
[ProtoContract]
public struct AttributeModification
: IEquatable,
IComparable,
IComparable
{
///
/// The name of the attribute to modify. This should match a field name in an subclass.
///
[StringInList(typeof(AttributeUtilities), nameof(AttributeUtilities.GetAllAttributeNames))]
[ProtoMember(1)]
public string attribute;
///
/// The type of modification action to perform (Addition, Multiplication, or Override).
///
[ProtoMember(2)]
public ModificationAction action;
///
/// The value to use for the modification. Interpretation depends on the :
/// - Addition: The amount to add (can be negative for subtraction)
/// - Multiplication: The multiplier to apply (e.g., 1.5 for +50%, 0.5 for -50%)
/// - Override: The new absolute value to set
///
[ProtoMember(3)]
public float value;
[JsonConstructor]
public AttributeModification(string attribute, ModificationAction action, float value)
{
this.attribute = attribute;
this.action = action;
this.value = value;
}
///
/// Converts this modification to a JSON string representation.
///
/// A JSON string representing this modification.
public override string ToString()
{
return this.ToJson();
}
public int CompareTo(object obj)
{
if (obj is AttributeModification other)
{
return CompareTo(other);
}
return -1;
}
public int CompareTo(AttributeModification other)
{
return ((int)action).CompareTo((int)other.action);
}
///
/// Determines whether two attribute modifications are not equal.
///
/// The first modification to compare.
/// The second modification to compare.
/// true if the modifications are not equal; otherwise, false.
public static bool operator !=(AttributeModification lhs, AttributeModification rhs)
{
return !(lhs == rhs);
}
///
/// Determines whether two attribute modifications are equal.
///
/// The first modification to compare.
/// The second modification to compare.
/// true if the modifications are equal; otherwise, false.
public static bool operator ==(AttributeModification lhs, AttributeModification rhs)
{
return lhs.Equals(rhs);
}
///
/// Determines whether this modification equals the specified object.
///
/// The object to compare with.
/// true if the object is an AttributeModification with equal values; otherwise, false.
public override bool Equals(object obj)
{
return obj is AttributeModification other && Equals(other);
}
///
/// Determines whether this modification equals another modification by comparing all fields.
///
/// The modification to compare with.
/// true if all fields are equal; otherwise, false.
public bool Equals(AttributeModification other)
{
return string.Equals(attribute, other.attribute, StringComparison.Ordinal)
&& action == other.action
&& value.Equals(other.value);
}
///
/// Returns the hash code for this modification.
///
/// A hash code combining the attribute name, action, and value.
public override int GetHashCode()
{
return Objects.HashCode(attribute, action, value);
}
}
}