using Jovian.Logger; using System; using System.Collections.Generic; using System.Linq; using ZLinq; using UnityEngine; namespace Nox.Game { public interface IModifier { string Name { get; } Guid Id { get; } ModifierTarget Target { get; } ModifierTarget ScalingSource { get; } ModifierOperation Operation { get; } float Value { get; } IReadOnlyList Requirements { get; } } public interface IModifiersFactory { IReadOnlyCollection GetAll(); IModifier GetById(Guid modifierId); IReadOnlyCollection GetModifiersFor(IEntityDefinition character); bool TryAddModifier(IEntityDefinition character, Guid modiferId); } public enum ModifierOperation { None, Flat, Addition, Multiplication, Percentage } public enum ModifierTargetType { None, Attribute, Stat, CombatScore } [Serializable] public sealed class ModifierTarget { [field: SerializeField] public ModifierTargetType Type { get; set; } [field: SerializeField] public AttributeType AttributeType { get; set; } [field: SerializeField] public StatType StatType { get; set; } [field: SerializeField] public CombatScoreType CombatScoreType { get; set; } public bool Matches(StatType statType) { return Type == ModifierTargetType.Stat && StatType == statType; } public bool Matches(AttributeType attributeType) { return Type == ModifierTargetType.Attribute && AttributeType == attributeType; } public bool Matches(CombatScoreType combatScoreType) { return Type == ModifierTargetType.CombatScore && CombatScoreType == combatScoreType; } public bool IsSet => Type != ModifierTargetType.None; public override string ToString() { return Type switch { ModifierTargetType.Attribute => AttributeType.ToString(), ModifierTargetType.Stat => StatType.ToString(), ModifierTargetType.CombatScore => CombatScoreType.ToString(), _ => "None" }; } } [Serializable] public sealed class ModifierRequirement { [field: SerializeField] public AttributeType Attribute { get; set; } [field: SerializeField] public int MinimumValue { get; set; } public bool IsMet(EntityAttributes attributes) { if(Attribute == AttributeType.None || attributes?.attributes == null) { return true; } return attributes.GetValue(Attribute) >= MinimumValue; } } [Serializable] public sealed class ModifierDefinition : IModifier { [field: SerializeField] public string Name { get; set; } public Guid Id { get; set; } = Guid.NewGuid(); [field: SerializeField] public ModifierTarget Target { get; set; } [field: SerializeField] public ModifierTarget ScalingSource { get; set; } [field: SerializeField] public ModifierOperation Operation { get; set; } [field: SerializeField] public float Value { get; set; } [field: SerializeField] public List Requirements { get; set; } = new(); IReadOnlyList IModifier.Requirements => Requirements; } [Serializable] public sealed class ModifiersData { public List modifiers = new(); public override string ToString() { return $"Modifiers: {string.Join(", ", modifiers.Select(modifier => $"{modifier.Name}"))}"; } } public class ModifiersFactory : IModifiersFactory { private readonly ModifiersRegistry modifiersRegistry; private readonly Dictionary modifierPool = new(); public ModifiersFactory(ModifiersRegistry modifiersRegistry) { this.modifiersRegistry = modifiersRegistry; var allAvailableModifiers = modifiersRegistry.modifiersData; foreach(var modifier in allAvailableModifiers.modifiers) { modifierPool.Add(modifier.Id, modifier); } } public IReadOnlyCollection GetAll() { return modifiersRegistry.modifiersData.modifiers; } public IModifier GetById(Guid modifierId) { return modifiersRegistry.modifiersData.modifiers.AsValueEnumerable().FirstOrDefault(m => m.Id == modifierId); } public IReadOnlyCollection GetModifiersFor(IEntityDefinition character) { return character.Modifiers.modifiers; } public bool TryAddModifier(IEntityDefinition character, Guid modifierId) { if(character == null) { return false; } if(modifierId == Guid.Empty) { GlobalLogger.LogException("Cannot add a modifier with an empty ID!", LogCategory.GameLogic); return false; } if(character.Modifiers.modifiers.AsValueEnumerable().Any(p => p != null && p.Id == modifierId)) { return false; } if(!modifierPool.TryGetValue(modifierId, out var modifier)) { return false; } character.Modifiers.modifiers.Add(new ModifierDefinition { Id = modifier.Id, Name = modifier.Name, Target = modifier.Target, ScalingSource = modifier.ScalingSource, Operation = modifier.Operation, Value = modifier.Value, Requirements = modifier.Requirements?.ToList() ?? new List() }); return true; } } }