From 7e2ffe9cb68761ec1f8067d1e32333954b71af01 Mon Sep 17 00:00:00 2001 From: chillu Date: Mon, 25 Aug 2025 22:47:49 +0200 Subject: [PATCH 01/11] feat: initial applier refactor --- ModiBuff/ModiBuff.Tests/ApplierTests.cs | 36 ++++++++---- .../Unit/ModifierApplierReference.cs | 16 ++++++ ModiBuff/ModiBuff.Units/Unit/Unit.cs | 56 ++++++++++++++++++- .../Core/Modifier/Components/Check/ICheck.cs | 35 ++++++++++++ 4 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 ModiBuff/ModiBuff.Units/Unit/ModifierApplierReference.cs diff --git a/ModiBuff/ModiBuff.Tests/ApplierTests.cs b/ModiBuff/ModiBuff.Tests/ApplierTests.cs index 9dc68d08..373029ef 100644 --- a/ModiBuff/ModiBuff.Tests/ApplierTests.cs +++ b/ModiBuff/ModiBuff.Tests/ApplierTests.cs @@ -25,8 +25,7 @@ public void DamageApplier_Attack_Damage() { Setup(); - var applier = Recipes.GetGenerator("InitDamage"); - Unit.AddApplierModifier(applier, ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage").Value, ApplierType.Attack); Unit.Attack(Enemy); @@ -40,8 +39,7 @@ public void HealApplier_Attack_Heal() .Effect(new HealEffect(10), EffectOn.Init); Setup(); - var applier = Recipes.GetGenerator("InitStrongHeal"); - Unit.AddApplierModifier(applier, ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitStrongHeal").Value, ApplierType.Attack); Enemy.TakeDamage(10, Enemy); Unit.Attack(Enemy); //Heal appliers triggers first, then attack damage @@ -56,8 +54,8 @@ public void DamageSelfApplier_Attack_DamageSelf() .Effect(new DamageEffect(5, targeting: Targeting.SourceTarget), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageSelf"), ApplierType.Attack); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamageSelf").Value, ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage").Value, ApplierType.Attack); Unit.Attack(Enemy); @@ -69,10 +67,10 @@ public void DamageApplier_Cast_Damage() { Setup(); - var applier = Recipes.GetGenerator("InitDamage"); - Unit.AddApplierModifier(applier, ApplierType.Cast); + int id = IdManager.GetId("InitDamage").Value; + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage").Value, ApplierType.Cast); - Unit.TryCast(applier.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); } @@ -97,7 +95,7 @@ public void DamageApplier_Interval() } [Test] - public void InitDamageCostMana() + public void InitDamageCostManaOld() { AddRecipe("InitDamage_CostMana") .ApplyCost(CostType.Mana, 5) @@ -114,6 +112,24 @@ public void InitDamageCostMana() Assert.AreEqual(EnemyHealth - 5, Enemy.Health); } + [Test] + public void InitDamageCostMana() + { + AddRecipe("InitDamage_CostMana") + .ApplyCost(CostType.Mana, 5) + .Effect(new DamageEffect(5), EffectOn.Init); + Setup(); + + int id = IdManager.GetId("InitDamage_CostMana").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] { new CostCheck(CostType.Mana, 5) }); + //TODO Needs to get fed apply cost state, or done entirely through MB.Units + + Unit.TryCast(id, Enemy); + + Assert.AreEqual(UnitMana - 5, Unit.Mana); + Assert.AreEqual(EnemyHealth - 5, Enemy.Health); + } + [Test] public void NestedStackApplier() { diff --git a/ModiBuff/ModiBuff.Units/Unit/ModifierApplierReference.cs b/ModiBuff/ModiBuff.Units/Unit/ModifierApplierReference.cs new file mode 100644 index 00000000..a0963c50 --- /dev/null +++ b/ModiBuff/ModiBuff.Units/Unit/ModifierApplierReference.cs @@ -0,0 +1,16 @@ +namespace ModiBuff.Core.Units +{ + public readonly struct ModifierApplierReference + { + public int Id { get; init; } + public ApplierType Type { get; init; } + public ICheck[] Checks { get; init; } + + public ModifierApplierReference(int id, ApplierType type, ICheck[] checks = null) + { + Id = id; + Type = type; + Checks = checks; + } + } +} \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Units/Unit/Unit.cs b/ModiBuff/ModiBuff.Units/Unit/Unit.cs index d96fe34f..b264275f 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Unit.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Unit.cs @@ -64,6 +64,8 @@ public partial class Unit : IUpdatable, IModifierOwner, IModifierApplierOwner, I private readonly StatusEffectController _singleInstanceStatusEffectController; private readonly DurationLessStatusEffectController _durationLessStatusEffectController; + private readonly Dictionary> _modifierAppliers; + private readonly Dictionary _modifierLevels; private static int _idCounter; @@ -121,6 +123,12 @@ public Unit(float health = 500, float damage = 10, float healValue = 5, float ma _singleInstanceStatusEffectController = new StatusEffectController(); _durationLessStatusEffectController = new DurationLessStatusEffectController(); + _modifierAppliers = new Dictionary>() + { + { ApplierType.Attack, new List<(int Id, ICheck[] Checks)>() }, + { ApplierType.Cast, new List<(int Id, ICheck[] Checks)>() }, + }; + _modifierLevels = new Dictionary(); } @@ -206,7 +214,28 @@ public float Attack(IUnit target) bool wasDead = killableTarget != null && killableTarget.IsDead; if (target is IModifierOwner modifierOwner) + { this.ApplyAllAttackModifier(modifierOwner); + foreach ((int id, var checks) in _modifierAppliers[ApplierType.Attack]) + { + bool success = true; + for (int i = 0; i < checks?.Length; i++) + { + if (checks[i].Check(this)) + continue; + + success = false; + break; + } + + if (success) + { + for (int i = 0; i < checks?.Length; i++) + checks[i].Use(this); + modifierOwner.ModifierController.Add(id, modifierOwner, this); + } + } + } if (++_onAttackCounter <= MaxEventCount) { @@ -349,8 +378,10 @@ public void TryCast(int modifierId, IUnit target) return; if (!StatusEffectController.HasLegalAction(LegalAction.Cast)) return; - if (!this.CanCastModifier(modifierId)) + if (!_modifierAppliers.TryGetValue(ApplierType.Cast, out var appliers) || !appliers.Contains(modifierId)) return; + //if (!this.CanCastModifier(modifierId)) + // return; if (++_onCastCounter <= MaxEventCount) { @@ -444,6 +475,29 @@ public void StrongDispel(IUnit source) ResetEventCounters(); } + //---Appliers--- + + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) + { + if (checks is { Length: > 0 }) + { + if (_modifierAppliers.TryGetValue(applierType, out var list)) + { + list.Add((modifierId, checks)); + return; + } + + _modifierAppliers[applierType] = + new List<(int Id, ICheck[] Checks)>(new[] { (modifierId, checks) }); + return; + } + + _modifierAppliers[applierType].Add(modifierId); + } + + public void AddApplierModifierNew(ModifierApplierReference applierReference) => + AddApplierModifierNew(applierReference.Id, applierReference.Type); + //---Aura--- public void AddAuraTargets(int id, params Unit[] targets) => _auraTargets[id].AddRange(targets); diff --git a/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs b/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs index bd3ba81f..a7231706 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs @@ -1,6 +1,41 @@ +using System; + namespace ModiBuff.Core { public interface ICheck { } + + public static class CheckExtensions + { + public static bool Check(this ICheck check, IUnit source) + { + switch (check) + { + case INoUnitCheck noUnitCheck: + if (!noUnitCheck.Check()) + return false; + break; + case IUnitCheck unitCheck: + if (!unitCheck.Check(source)) + return false; + break; + default: + Logger.LogError("[ModiBuff] Unhandled check type: " + check.GetType()); + throw new ArgumentOutOfRangeException(); + } + + return true; + } + + public static void Use(this ICheck check, IUnit source) + { + switch (check) + { + case IUsableCheck usableCheck: + usableCheck.Use(source); + break; + } + } + } } \ No newline at end of file From cd0682ad2d00830607b54cea674823d67358ca89 Mon Sep 17 00:00:00 2001 From: chillu Date: Tue, 26 Aug 2025 22:52:09 +0200 Subject: [PATCH 02/11] feat: continued porting tests to new applier logic --- ModiBuff/ModiBuff.Tests/ApplierTests.cs | 19 ------ .../ModiBuff.Tests/CallbackEffectTests.cs | 2 +- .../DestroyableProjectileTests.cs | 2 +- .../Unit/ModifierApplierReference.cs | 16 ----- ModiBuff/ModiBuff.Units/Unit/Unit.cs | 68 ++++++++++++------- .../Core/Modifier/Components/Check/ICheck.cs | 3 + 6 files changed, 48 insertions(+), 62 deletions(-) delete mode 100644 ModiBuff/ModiBuff.Units/Unit/ModifierApplierReference.cs diff --git a/ModiBuff/ModiBuff.Tests/ApplierTests.cs b/ModiBuff/ModiBuff.Tests/ApplierTests.cs index 373029ef..7aee2e5e 100644 --- a/ModiBuff/ModiBuff.Tests/ApplierTests.cs +++ b/ModiBuff/ModiBuff.Tests/ApplierTests.cs @@ -94,24 +94,6 @@ public void DamageApplier_Interval() Assert.AreEqual(EnemyHealth - 10, Enemy.Health); } - [Test] - public void InitDamageCostManaOld() - { - AddRecipe("InitDamage_CostMana") - .ApplyCost(CostType.Mana, 5) - .Effect(new DamageEffect(5), EffectOn.Init); - Setup(); - - var generator = Recipes.GetGenerator("InitDamage_CostMana"); - - Unit.AddApplierModifier(generator, ApplierType.Cast); - - Unit.TryCast(generator.Id, Enemy); - - Assert.AreEqual(UnitMana - 5, Unit.Mana); - Assert.AreEqual(EnemyHealth - 5, Enemy.Health); - } - [Test] public void InitDamageCostMana() { @@ -122,7 +104,6 @@ public void InitDamageCostMana() int id = IdManager.GetId("InitDamage_CostMana").Value; Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] { new CostCheck(CostType.Mana, 5) }); - //TODO Needs to get fed apply cost state, or done entirely through MB.Units Unit.TryCast(id, Enemy); diff --git a/ModiBuff/ModiBuff.Tests/CallbackEffectTests.cs b/ModiBuff/ModiBuff.Tests/CallbackEffectTests.cs index a7b3be0e..4f9f9686 100644 --- a/ModiBuff/ModiBuff.Tests/CallbackEffectTests.cs +++ b/ModiBuff/ModiBuff.Tests/CallbackEffectTests.cs @@ -210,7 +210,7 @@ public void SilenceSourceWhenSilenced() Setup(); Unit.AddModifierSelf("SilenceSourceWhenSilenced"); - Enemy.AddApplierModifier(Recipes.GetGenerator("Silence"), ApplierType.Cast); + Enemy.AddApplierModifierNew(IdManager.GetId("Silence").Value, ApplierType.Cast); Enemy.TryCast("Silence", Unit); Assert.True(Unit.StatusEffectController.HasStatusEffect(StatusEffectType.Silence)); Assert.True(Enemy.StatusEffectController.HasStatusEffect(StatusEffectType.Silence)); diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DestroyableProjectileTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DestroyableProjectileTests.cs index 10994ba1..b85d58a6 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DestroyableProjectileTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DestroyableProjectileTests.cs @@ -78,7 +78,7 @@ public void DestroyProjectileOnXHits() { Setup(); - Enemy.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Attack); + Enemy.AddApplierModifierNew(IdManager.GetId("InitDamage").Value, ApplierType.Attack); Enemy.Attack(Unit); Assert.AreEqual(HitsToDestroy - 2, Unit.Health); diff --git a/ModiBuff/ModiBuff.Units/Unit/ModifierApplierReference.cs b/ModiBuff/ModiBuff.Units/Unit/ModifierApplierReference.cs deleted file mode 100644 index a0963c50..00000000 --- a/ModiBuff/ModiBuff.Units/Unit/ModifierApplierReference.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ModiBuff.Core.Units -{ - public readonly struct ModifierApplierReference - { - public int Id { get; init; } - public ApplierType Type { get; init; } - public ICheck[] Checks { get; init; } - - public ModifierApplierReference(int id, ApplierType type, ICheck[] checks = null) - { - Id = id; - Type = type; - Checks = checks; - } - } -} \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Units/Unit/Unit.cs b/ModiBuff/ModiBuff.Units/Unit/Unit.cs index b264275f..bb4e2616 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Unit.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Unit.cs @@ -215,26 +215,8 @@ public float Attack(IUnit target) if (target is IModifierOwner modifierOwner) { - this.ApplyAllAttackModifier(modifierOwner); - foreach ((int id, var checks) in _modifierAppliers[ApplierType.Attack]) - { - bool success = true; - for (int i = 0; i < checks?.Length; i++) - { - if (checks[i].Check(this)) - continue; - - success = false; - break; - } - - if (success) - { - for (int i = 0; i < checks?.Length; i++) - checks[i].Use(this); - modifierOwner.ModifierController.Add(id, modifierOwner, this); - } - } + //this.ApplyAllAttackModifier(modifierOwner); + DoChecks(modifierOwner, ApplierType.Attack); } if (++_onAttackCounter <= MaxEventCount) @@ -378,11 +360,27 @@ public void TryCast(int modifierId, IUnit target) return; if (!StatusEffectController.HasLegalAction(LegalAction.Cast)) return; - if (!_modifierAppliers.TryGetValue(ApplierType.Cast, out var appliers) || !appliers.Contains(modifierId)) + if (!_modifierAppliers.TryGetValue(ApplierType.Cast, out var appliers)) + return; + + (int Id, ICheck[] Checks)? applier = null; + for (int i = 0; i < appliers.Count; i++) + { + if (appliers[i].Id == modifierId) + { + applier = appliers[i]; + break; + } + } + + if (applier == null) return; //if (!this.CanCastModifier(modifierId)) // return; + for (int i = 0; i < applier.Value.Checks?.Length; i++) + applier.Value.Checks[i].Use(this); + if (++_onCastCounter <= MaxEventCount) { for (int i = 0; i < _onCastEffects.Count; i++) @@ -477,7 +475,7 @@ public void StrongDispel(IUnit source) //---Appliers--- - public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[]? checks = null) { if (checks is { Length: > 0 }) { @@ -492,11 +490,31 @@ public void AddApplierModifierNew(int modifierId, ApplierType applierType, IChec return; } - _modifierAppliers[applierType].Add(modifierId); + _modifierAppliers[applierType].Add((modifierId, null)); } - public void AddApplierModifierNew(ModifierApplierReference applierReference) => - AddApplierModifierNew(applierReference.Id, applierReference.Type); + private void DoChecks(IModifierOwner target, ApplierType applierType) + { + foreach ((int id, var checks) in _modifierAppliers[applierType]) + { + bool success = true; + for (int i = 0; i < checks?.Length; i++) + { + if (checks[i].Check(this)) + continue; + + success = false; + break; + } + + if (!success) + continue; + + for (int i = 0; i < checks?.Length; i++) + checks[i].Use(this); + target.ModifierController.Add(id, target, this); + } + } //---Aura--- diff --git a/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs b/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs index a7231706..00c8e1e3 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; namespace ModiBuff.Core { @@ -8,6 +9,7 @@ public interface ICheck public static class CheckExtensions { + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Check(this ICheck check, IUnit source) { switch (check) @@ -28,6 +30,7 @@ public static bool Check(this ICheck check, IUnit source) return true; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Use(this ICheck check, IUnit source) { switch (check) From 28d30cb162e53ef6a86f37189541a97a8f3ce6e4 Mon Sep 17 00:00:00 2001 From: chillu Date: Wed, 27 Aug 2025 18:38:28 +0200 Subject: [PATCH 03/11] feat: continued check refactor --- .../ModiBuff.Examples/BasicConsole/Unit.cs | 28 +++++++++++++++- ModiBuff/ModiBuff.Tests/ApplierTests.cs | 9 +++--- ModiBuff/ModiBuff.Tests/CastTests.cs | 3 +- .../PartialUnitTests/AttackUnitTests.cs | 5 ++- .../PartialUnitTests/DamagableUnitTests.cs | 25 +++++++++++++++ .../ModifierApplierUnitTests.cs | 25 +++++++++++++++ .../ModiBuff.Units/Checks/ConditionCheck.cs | 22 +++++++++++++ .../ModiBuff.Units/Checks/LegalActionCheck.cs | 15 +++++++++ .../ModiBuff.Units/Checks/ModifierIdCheck.cs | 11 +++++++ ModiBuff/ModiBuff.Units/Checks/StatCheck.cs | 32 +++++++++++++++++++ .../Checks/StatusEffectCheck.cs | 15 +++++++++ .../Core/Modifier/Components/Check/ICheck.cs | 11 +++---- .../Components/Effect/ApplierEffect.cs | 1 + .../Core/Unit/IModifierApplierOwner.cs | 1 + 14 files changed, 188 insertions(+), 15 deletions(-) create mode 100644 ModiBuff/ModiBuff.Units/Checks/ConditionCheck.cs create mode 100644 ModiBuff/ModiBuff.Units/Checks/LegalActionCheck.cs create mode 100644 ModiBuff/ModiBuff.Units/Checks/ModifierIdCheck.cs create mode 100644 ModiBuff/ModiBuff.Units/Checks/StatCheck.cs create mode 100644 ModiBuff/ModiBuff.Units/Checks/StatusEffectCheck.cs diff --git a/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs b/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs index 42e1c9b0..45189203 100644 --- a/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs +++ b/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using ModiBuff.Core; using ModiBuff.Core.Units; using ModiBuff.Core.Units.Interfaces.NonGeneric; @@ -20,9 +21,11 @@ public sealed class Unit : IModifierOwner, IUpdatable, IDamagable, IAttacker, IH //We simply add modifier ids to it, and it will handle the rest public ModifierController ModifierController { get; } - //TODO Explain public ModifierApplierController ModifierApplierController { get; } + //TODO Explain + private readonly Dictionary> _modifierAppliers; + //Basic implementation of status effects, unit can't attack when it's disarmed //Move when it's rooted/frozen/stunned, etc. public ISingleInstanceStatusEffectController StatusEffectController { get; } @@ -48,6 +51,11 @@ public Unit(string name, float health, float damage) //Remember to rent the modifier controllers in the constructor ModifierController = ModifierControllerPool.Instance.Rent(); ModifierApplierController = ModifierControllerPool.Instance.RentApplier(); + _modifierAppliers = new Dictionary> + { + { ApplierType.Attack, new List<(int, ICheck[])>() }, + { ApplierType.Cast, new List<(int, ICheck[])>() } + }; StatusEffectController = new StatusEffectController(); _targetingSystem = new TargetingSystem(); } @@ -141,6 +149,24 @@ public float Heal(float heal, IUnit source) return Health - originalHealth; } + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) + { + if (checks?.Length > 0) + { + if (_modifierAppliers.TryGetValue(applierType, out var list)) + { + list.Add((modifierId, checks)); + return; + } + + _modifierAppliers[applierType] = + new List<(int Id, ICheck[] Checks)>(new[] { (modifierId, checks) }); + return; + } + + _modifierAppliers[applierType].Add((modifierId, null)); + } + public string GetDebugString() { return $"Unit, health: {Health}/{MaxHealth}, damage: {Damage}"; diff --git a/ModiBuff/ModiBuff.Tests/ApplierTests.cs b/ModiBuff/ModiBuff.Tests/ApplierTests.cs index 7aee2e5e..b5bb5988 100644 --- a/ModiBuff/ModiBuff.Tests/ApplierTests.cs +++ b/ModiBuff/ModiBuff.Tests/ApplierTests.cs @@ -239,12 +239,13 @@ public void Cast_AddApplier() AddRecipe("AddApplier_Effect") .Effect(new ApplierEffect("InitDamage"), EffectOn.Init) .RemoveApplier(5, ApplierType.Cast, false); - AddEffect("AddApplier_ApplierEffect", new ApplierEffect("AddApplier_Effect", ApplierType.Cast, false)); + AddRecipe("AddApplier_ApplierEffect") + .Effect(new ApplierEffect("AddApplier_Effect", ApplierType.Cast, false), EffectOn.Init); Setup(); - Unit.AddEffectApplier("AddApplier_ApplierEffect"); Unit.TryCast("AddApplier_Effect", Enemy); - Unit.TryCastEffect("AddApplier_ApplierEffect", Unit); + Unit.AddModifierSelf("AddApplier_ApplierEffect"); + Unit.TryCast("AddApplier_ApplierEffect", Unit); Unit.TryCast("AddApplier_Effect", Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); @@ -270,7 +271,7 @@ public void ConditionalApplierBasedOnUnitType() .Remove(5).Refresh(); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("ConditionalApplierBasedOnUnitType"), ApplierType.Cast); + Unit.AddApplierModifierNew(IdManager.GetId("ConditionalApplierBasedOnUnitType").Value, ApplierType.Cast); Enemy.TakeDamage(5, Enemy); Ally.TakeDamage(5, Ally); diff --git a/ModiBuff/ModiBuff.Tests/CastTests.cs b/ModiBuff/ModiBuff.Tests/CastTests.cs index a2d574a1..d8301437 100644 --- a/ModiBuff/ModiBuff.Tests/CastTests.cs +++ b/ModiBuff/ModiBuff.Tests/CastTests.cs @@ -59,7 +59,8 @@ public void AttackInitDamageChecks_OnEnemy() .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageFullHealth"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamageFullHealth").Value, ApplierType.Attack, + new ICheck[] { new ConditionCheck(ConditionType.HealthIsFull) }); Unit.Attack(Enemy); diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs index 1941e0c0..89d5b4a2 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs @@ -11,8 +11,7 @@ public sealed class AttackUnitTests : PartialUnitModifierTests UnitFactory = (health, damage, heal, mana, type, tag) => new AttackUnit(damage, type); - public sealed class AttackUnit : IUnit, IModifierOwner, IAttacker, IUpdatable, IUnitEntity, - IModifierApplierOwner + public sealed class AttackUnit : IUnit, IModifierOwner, IAttacker, IUpdatable, IUnitEntity { public UnitTag UnitTag { get; } public UnitType UnitType { get; } @@ -39,7 +38,7 @@ public void Update(float delta) public float Attack(IUnit target) { - this.ApplyAllAttackModifier((IModifierOwner)target); + //this.ApplyAllAttackModifier((IModifierOwner)target); return ((IDamagable)target).TakeDamage(Damage, this); } diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs index 059cc459..c6f27636 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs @@ -25,6 +25,8 @@ public sealed class DamagableUnit : IUnit, IModifierOwner, IDamagable, IUpdatabl public ModifierController ModifierController { get; } public ModifierApplierController ModifierApplierController { get; } + private readonly Dictionary> _modifierAppliers; + public DamagableUnit(float health, UnitType unitType = UnitType.Good) { UnitType = unitType; @@ -33,6 +35,11 @@ public DamagableUnit(float health, UnitType unitType = UnitType.Good) ModifierController = ModifierControllerPool.Instance.Rent(); ModifierApplierController = ModifierControllerPool.Instance.RentApplier(); + _modifierAppliers = new Dictionary> + { + { ApplierType.Attack, new List<(int, ICheck[])>() }, + { ApplierType.Cast, new List<(int, ICheck[])>() } + }; } public void Update(float delta) @@ -61,6 +68,24 @@ public void UseHealth(float value) { Health -= value; } + + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) + { + if (checks?.Length > 0) + { + if (_modifierAppliers.TryGetValue(applierType, out var list)) + { + list.Add((modifierId, checks)); + return; + } + + _modifierAppliers[applierType] = + new List<(int Id, ICheck[] Checks)>(new[] { (modifierId, checks) }); + return; + } + + _modifierAppliers[applierType].Add((modifierId, null)); + } } [Test] diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs index b2056d54..58513dea 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using ModiBuff.Core; using ModiBuff.Core.Units; using ModiBuff.Core.Units.Interfaces.NonGeneric; @@ -22,6 +23,7 @@ public sealed class ModifierApplierUnit : IUnit, IModifierApplierOwner, IDamagab public float Damage { get; } public ModifierApplierController ModifierApplierController { get; } + private readonly Dictionary> _modifierAppliers; public ModifierApplierUnit(float health, float damage, UnitType unitType = UnitType.Good) { @@ -31,6 +33,11 @@ public ModifierApplierUnit(float health, float damage, UnitType unitType = UnitT Damage = damage; ModifierApplierController = ModifierControllerPool.Instance.RentApplier(); + _modifierAppliers = new Dictionary> + { + { ApplierType.Attack, new List<(int, ICheck[])>() }, + { ApplierType.Cast, new List<(int, ICheck[])>() } + }; } public float Attack(IUnit target) @@ -50,6 +57,24 @@ public float TakeDamage(float damage, IUnit source) return dealtDamage; } + + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) + { + if (checks?.Length > 0) + { + if (_modifierAppliers.TryGetValue(applierType, out var list)) + { + list.Add((modifierId, checks)); + return; + } + + _modifierAppliers[applierType] = + new List<(int Id, ICheck[] Checks)>(new[] { (modifierId, checks) }); + return; + } + + _modifierAppliers[applierType].Add((modifierId, null)); + } } [Test] diff --git a/ModiBuff/ModiBuff.Units/Checks/ConditionCheck.cs b/ModiBuff/ModiBuff.Units/Checks/ConditionCheck.cs new file mode 100644 index 00000000..5583b0e0 --- /dev/null +++ b/ModiBuff/ModiBuff.Units/Checks/ConditionCheck.cs @@ -0,0 +1,22 @@ +using System; + +namespace ModiBuff.Core.Units +{ + public sealed class ConditionCheck : IUnitCheck + { + private readonly ConditionType _conditionType; + + public ConditionCheck(ConditionType conditionType) => _conditionType = conditionType; + + public bool Check(IUnit source) => _conditionType switch + { + ConditionType.HealthIsFull => source is IDamagable damagable && + ComparisonType.Equal.Check(damagable.Health, damagable.MaxHealth), + ConditionType.ManaIsFull => source is IManaOwner manaOwner && + ComparisonType.Equal.Check(manaOwner.Mana, manaOwner.MaxMana), + ConditionType.ManaIsEmpty => source is IManaOwner manaOwner2 && + ComparisonType.LessOrEqual.Check(manaOwner2.Mana, 0f), + _ => throw new ArgumentOutOfRangeException() + }; + } +} \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Units/Checks/LegalActionCheck.cs b/ModiBuff/ModiBuff.Units/Checks/LegalActionCheck.cs new file mode 100644 index 00000000..6aeeefce --- /dev/null +++ b/ModiBuff/ModiBuff.Units/Checks/LegalActionCheck.cs @@ -0,0 +1,15 @@ +namespace ModiBuff.Core.Units +{ + public sealed class LegalActionCheck : IUnitCheck + { + private readonly LegalAction _legalAction; + + public LegalActionCheck(LegalAction legalAction) => _legalAction = legalAction; + + public bool Check(IUnit source) + { + var statusEffectOwner = (IStatusEffectOwner)source; + return statusEffectOwner.StatusEffectController.HasLegalAction(_legalAction); + } + } +} \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Units/Checks/ModifierIdCheck.cs b/ModiBuff/ModiBuff.Units/Checks/ModifierIdCheck.cs new file mode 100644 index 00000000..659af552 --- /dev/null +++ b/ModiBuff/ModiBuff.Units/Checks/ModifierIdCheck.cs @@ -0,0 +1,11 @@ +namespace ModiBuff.Core.Units +{ + public sealed class ModifierIdCheck : IUnitCheck + { + private readonly int _modifierId; + + public ModifierIdCheck(int modifierId) => _modifierId = modifierId; + + public bool Check(IUnit source) => ((IModifierOwner)source).ModifierController.Contains(_modifierId); + } +} \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Units/Checks/StatCheck.cs b/ModiBuff/ModiBuff.Units/Checks/StatCheck.cs new file mode 100644 index 00000000..d021555b --- /dev/null +++ b/ModiBuff/ModiBuff.Units/Checks/StatCheck.cs @@ -0,0 +1,32 @@ +using System; + +namespace ModiBuff.Core.Units +{ + public sealed class StatCheck : IUnitCheck + { + private readonly StatType _statType; + private readonly ComparisonType _comparisonType; + private readonly float _statValue; + + public StatCheck(StatType statType, ComparisonType comparisonType, float statValue) + { + _statType = statType; + _comparisonType = comparisonType; + _statValue = statValue; + } + + public bool Check(IUnit source) + { + float value = _statType switch + { + StatType.Health => ((IDamagable)source).Health, + StatType.MaxHealth => ((IDamagable)source).MaxHealth, + StatType.Mana => ((IManaOwner)source).Mana, + StatType.Damage => ((IAttacker)source).Damage, + _ => throw new ArgumentOutOfRangeException() + }; + + return _comparisonType.Check(value, _statValue); + } + } +} \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Units/Checks/StatusEffectCheck.cs b/ModiBuff/ModiBuff.Units/Checks/StatusEffectCheck.cs new file mode 100644 index 00000000..5b44d28f --- /dev/null +++ b/ModiBuff/ModiBuff.Units/Checks/StatusEffectCheck.cs @@ -0,0 +1,15 @@ +namespace ModiBuff.Core.Units +{ + public sealed class StatusEffectCheck : IUnitCheck + { + private readonly StatusEffectType _statusEffectType; + + public StatusEffectCheck(StatusEffectType statusEffectType) => _statusEffectType = statusEffectType; + + public bool Check(IUnit source) + { + var statusEffectOwner = (IStatusEffectOwner)source; + return statusEffectOwner.StatusEffectController.HasStatusEffect(_statusEffectType); + } + } +} \ No newline at end of file diff --git a/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs b/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs index 00c8e1e3..24ede481 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs @@ -33,12 +33,11 @@ public static bool Check(this ICheck check, IUnit source) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Use(this ICheck check, IUnit source) { - switch (check) - { - case IUsableCheck usableCheck: - usableCheck.Use(source); - break; - } + if (check is IUsableCheck usableCheck) + usableCheck.Use(source); + + if (check is IStateCheck stateCheck) + stateCheck.RestartState(); } } } \ No newline at end of file diff --git a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs b/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs index 540f37b1..e1190759 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs @@ -72,6 +72,7 @@ public void Effect(IUnit target, IUnit source) return; } + modifierApplierOwnerTarget.AddApplierModifierNew(modifierId, _applierType.Value); modifierApplierOwnerTarget.ModifierApplierController.TryAddApplier(modifierId, _hasApplyChecks, _applierType.Value); break; diff --git a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs index c9428d8f..2766773b 100644 --- a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs +++ b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs @@ -3,5 +3,6 @@ namespace ModiBuff.Core public interface IModifierApplierOwner : IUnit { ModifierApplierController ModifierApplierController { get; } + void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[]? checks = null); } } \ No newline at end of file From 5fdf9345bb18763d91eb7000f650fa287a3b3d88 Mon Sep 17 00:00:00 2001 From: chillu Date: Wed, 27 Aug 2025 22:30:24 +0200 Subject: [PATCH 04/11] feat: updatable checks in unit, further porting of tests to new applier logic --- ModiBuff/ModiBuff.Tests/CastTests.cs | 30 +++++---- ModiBuff/ModiBuff.Tests/ConditionTests.cs | 78 +++++++++++++---------- ModiBuff/ModiBuff.Tests/CooldownTests.cs | 32 ++++++---- ModiBuff/ModiBuff.Tests/CostTests.cs | 32 ++++++---- ModiBuff/ModiBuff.Units/Unit/Unit.cs | 39 +++++++++--- ModiBuff/ModiBuff/Core/Unit/ICaster.cs | 2 +- 6 files changed, 130 insertions(+), 83 deletions(-) diff --git a/ModiBuff/ModiBuff.Tests/CastTests.cs b/ModiBuff/ModiBuff.Tests/CastTests.cs index d8301437..523ebc86 100644 --- a/ModiBuff/ModiBuff.Tests/CastTests.cs +++ b/ModiBuff/ModiBuff.Tests/CastTests.cs @@ -11,9 +11,10 @@ public void CastInitDamageNoChecks_OnEnemy() { Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Cast); + int id = IdManager.GetId("InitDamage").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); - Unit.TryCast(IdManager.GetId("InitDamage").Value, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); } @@ -22,19 +23,20 @@ public void CastInitDamageNoChecks_OnEnemy() public void CastInitDamageChecks_OnEnemy() { AddRecipe("InitDamageFullHealth") - .ApplyCondition(ConditionType.HealthIsFull) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageFullHealth"), ApplierType.Cast); + int id = IdManager.GetId("InitDamageFullHealth").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast, + new ICheck[] { new ConditionCheck(ConditionType.HealthIsFull) }); - Unit.TryCast(IdManager.GetId("InitDamageFullHealth").Value, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Unit.TakeDamage(5, Enemy); - Unit.TryCast(IdManager.GetId("InitDamageFullHealth").Value, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); } @@ -44,7 +46,7 @@ public void AttackInitDamageNoChecks_OnEnemy() { Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage").Value, ApplierType.Attack); Unit.Attack(Enemy); @@ -55,7 +57,6 @@ public void AttackInitDamageNoChecks_OnEnemy() public void AttackInitDamageChecks_OnEnemy() { AddRecipe("InitDamageFullHealth") - .ApplyCondition(ConditionType.HealthIsFull) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); @@ -77,18 +78,18 @@ public void AttackInitDamageChecks_OnEnemy() public void CastInitDamageChecksDelayedUse_OnEnemy() { AddRecipe("InitDamageFullHealth") - .ApplyCondition(ConditionType.HealthIsFull) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); int id = IdManager.GetId("InitDamageFullHealth").Value; - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageFullHealth"), ApplierType.Cast); + Unit.AddApplierModifierNew(id, ApplierType.Cast, + new ICheck[] { new ConditionCheck(ConditionType.HealthIsFull) }); - Assert.True(Unit.TryCastCheck(id)); + Assert.True(Unit.TryCast(id, Unit)); Assert.AreEqual(EnemyHealth, Enemy.Health); - Assert.True(Unit.TryCastNoChecks(id, Enemy)); + Assert.True(Unit.TryCast(id, Enemy)); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); } @@ -101,10 +102,11 @@ public void CastOnCastEventRecursion() .CallbackUnit(CallbackUnitType.OnCast); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Cast); + int id = IdManager.GetId("InitDamage").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); Unit.AddModifierSelf("CastInitDamageEvent"); - Unit.TryCast(IdManager.GetId("InitDamage").Value, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5 - 5 * Unit.MaxEventCount, Enemy.Health); } diff --git a/ModiBuff/ModiBuff.Tests/ConditionTests.cs b/ModiBuff/ModiBuff.Tests/ConditionTests.cs index b868122d..1f117977 100644 --- a/ModiBuff/ModiBuff.Tests/ConditionTests.cs +++ b/ModiBuff/ModiBuff.Tests/ConditionTests.cs @@ -14,12 +14,15 @@ public void HealthCondition_OnApply_InitDamage() .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamage_ApplyCondition_HealthAbove100"); + int id = IdManager.GetId("InitDamage_ApplyCondition_HealthAbove100").Value; Unit.TakeDamage(UnitHealth - 6, Unit); //6hp left - Unit.AddApplierModifier(generator, ApplierType.Cast); - Unit.TryCast(generator.Id, Unit); + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + { + new StatCheck(StatType.Health, ComparisonType.GreaterOrEqual, 100) + }); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth - UnitHealth + 6, Unit.Health); } @@ -27,20 +30,25 @@ public void HealthCondition_OnApply_InitDamage() public void ManaCondition_OnApply_InitDamage() { AddRecipe("InitDamage_ApplyCondition_ManaBelow100") - .ApplyCondition(StatType.Mana, 100, ComparisonType.LessOrEqual) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamage_ApplyCondition_ManaBelow100"); + int id = IdManager.GetId("InitDamage_ApplyCondition_ManaBelow100").Value; - Unit.AddApplierModifier(generator, ApplierType.Cast); - Unit.TryCast(generator.Id, Unit); + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + { + new StatCheck(StatType.Mana, ComparisonType.LessOrEqual, 100) + }); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth, Unit.Health); Unit.UseMana(UnitMana - 100); //100 mana left - Unit.AddApplierModifier(generator, ApplierType.Cast); - Unit.TryCast(generator.Id, Unit); + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + { + new StatCheck(StatType.Mana, ComparisonType.LessOrEqual, 100) + }); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth - 5, Unit.Health); } @@ -111,20 +119,22 @@ public void HasModifier_OnEffect_InitDamage() [Test] public void HasModifier_OnApply_InitDamage() { - AddRecipe("FlagApply"); + int flagId = AddRecipe("FlagApply").Id; AddRecipe("InitDamage_ApplyCondition_ContainsModifier") - .ApplyCondition("FlagApply") .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamage_ApplyCondition_ContainsModifier"); + int id = IdManager.GetId("InitDamage_ApplyCondition_ContainsModifier").Value; - Unit.AddApplierModifier(generator, ApplierType.Cast); - Unit.TryCast(generator.Id, Unit); + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + { + new ModifierIdCheck(flagId) + }); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth, Unit.Health); Unit.AddModifierSelf("FlagApply"); - Unit.TryCast(generator.Id, Unit); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth - 5, Unit.Health); } @@ -155,21 +165,21 @@ public void HasStatusEffect_OnApply_InitDamage() AddRecipe("InitFreeze") .Effect(new StatusEffectEffect(StatusEffectType.Freeze, 2), EffectOn.Init); AddRecipe("InitDamage_ApplyCondition_FreezeStatusEffect") - .ApplyCondition(StatusEffectType.Freeze) .Effect(new DamageEffect(5), EffectOn.Init); AddRecipe("InitDamage_ApplyCondition_ActLegalAction") .ApplyCondition(LegalAction.Act) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamage_ApplyCondition_FreezeStatusEffect"); + int id = IdManager.GetId("InitDamage_ApplyCondition_FreezeStatusEffect").Value; - Unit.AddApplierModifier(generator, ApplierType.Cast); - Unit.TryCast(generator.Id, Unit); + Unit.AddApplierModifierNew(id, ApplierType.Cast, + new ICheck[] { new StatusEffectCheck(StatusEffectType.Freeze) }); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth, Unit.Health); Unit.AddModifierSelf("InitFreeze"); - Unit.TryCast(generator.Id, Unit); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth - 5, Unit.Health); } @@ -200,18 +210,18 @@ public void HasLegalAction_OnApply_InitDamage() AddRecipe("InitFreeze") .Effect(new StatusEffectEffect(StatusEffectType.Freeze, 2), EffectOn.Init); AddRecipe("InitDamage_ApplyCondition_ActLegalAction") - .ApplyCondition(LegalAction.Act) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamage_ApplyCondition_ActLegalAction"); + int id = IdManager.GetId("InitDamage_ApplyCondition_ActLegalAction").Value; - Unit.AddApplierModifier(generator, ApplierType.Cast); - Unit.TryCast(generator.Id, Unit); + Unit.AddApplierModifierNew(id, ApplierType.Cast, + new ICheck[] { new LegalActionCheck(LegalAction.Act) }); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth - 5, Unit.Health); Unit.AddModifierSelf("InitFreeze"); - Unit.TryCast(generator.Id, Unit); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth - 5, Unit.Health); } @@ -242,27 +252,29 @@ public void Combination_OnEffect_InitDamage() [Test] public void Combination_OnApply_InitDamage() { - AddRecipe("FlagApply"); + int flagId = AddRecipe("FlagApply").Id; AddRecipe("InitFreeze") .Effect(new StatusEffectEffect(StatusEffectType.Freeze, 2), EffectOn.Init); AddRecipe("InitDamage_ApplyCondition_Combination") - .ApplyCondition("FlagApply") - .ApplyCondition(StatusEffectType.Freeze) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamage_ApplyCondition_Combination"); + int id = IdManager.GetId("InitDamage_ApplyCondition_Combination").Value; - Unit.AddApplierModifier(generator, ApplierType.Cast); - Unit.TryCast(generator.Id, Unit); + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + { + new ModifierIdCheck(flagId), + new StatusEffectCheck(StatusEffectType.Freeze) + }); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth, Unit.Health); Unit.AddModifierSelf("InitFreeze"); - Unit.TryCast(generator.Id, Unit); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth, Unit.Health); Unit.AddModifierSelf("FlagApply"); - Unit.TryCast(generator.Id, Unit); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth - 5, Unit.Health); } diff --git a/ModiBuff/ModiBuff.Tests/CooldownTests.cs b/ModiBuff/ModiBuff.Tests/CooldownTests.cs index 969009e7..e354dfcc 100644 --- a/ModiBuff/ModiBuff.Tests/CooldownTests.cs +++ b/ModiBuff/ModiBuff.Tests/CooldownTests.cs @@ -10,11 +10,13 @@ public sealed class CooldownTests : ModifierTests public void InitDamage_Cooldown() { AddRecipe("InitDamage_Cooldown") - .ApplyCooldown(1) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage_Cooldown"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage_Cooldown").Value, ApplierType.Attack, new ICheck[] + { + new CooldownCheck(1) + }); Unit.Attack(Enemy); @@ -153,28 +155,29 @@ public void MultipleEffectsTwoEffectOnCooldownCheck() public void InitDamage_ChargesCooldown() { AddRecipe("InitDamage_Cooldown") - .ApplyChargesCooldown(1, 2) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage_Cooldown"), ApplierType.Cast); + int id = IdManager.GetId("InitDamage_Cooldown").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast, + new ICheck[] { new ChargesCooldownCheck(1, 2) }); - Unit.TryCast("InitDamage_Cooldown", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); // 1 more charge - Unit.TryCast("InitDamage_Cooldown", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5 - 5, Enemy.Health); // 0 charges - Unit.TryCast("InitDamage_Cooldown", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5 - 5, Enemy.Health); Unit.Update(1); Unit.Update(1); - Unit.TryCast("InitDamage_Cooldown", Enemy); - Unit.TryCast("InitDamage_Cooldown", Enemy); + Unit.TryCast(id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5 - 5 - 5 - 5, Enemy.Health); } @@ -186,21 +189,22 @@ public void InitDamage_ChargesCooldownUseWait() .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage_Cooldown"), ApplierType.Cast); + int id = IdManager.GetId("InitDamage_Cooldown").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] { new ChargesCooldownCheck(1, 2) }); - Unit.TryCast("InitDamage_Cooldown", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Unit.Update(1); // 2 charges - Unit.TryCast("InitDamage_Cooldown", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5 - 5, Enemy.Health); // 1 charge - Unit.TryCast("InitDamage_Cooldown", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5 - 5 - 5, Enemy.Health); - Unit.TryCast("InitDamage_Cooldown", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5 - 5 - 5, Enemy.Health); } } diff --git a/ModiBuff/ModiBuff.Tests/CostTests.cs b/ModiBuff/ModiBuff.Tests/CostTests.cs index b9f5f6ec..86a9f675 100644 --- a/ModiBuff/ModiBuff.Tests/CostTests.cs +++ b/ModiBuff/ModiBuff.Tests/CostTests.cs @@ -10,11 +10,13 @@ public sealed class CostTests : ModifierTests public void CostHealth() { AddRecipe("InitDamage_CostHealth") - .ApplyCost(CostType.Health, 5) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage_CostHealth"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage_CostHealth").Value, ApplierType.Attack, new ICheck[] + { + new CostCheck(CostType.Health, 5) + }); Unit.Attack(Unit); @@ -41,11 +43,13 @@ public void CostHealth_NotLethal() public void CostMana() { AddRecipe("InitDamage_CostMana") - .ApplyCost(CostType.Mana, 5) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage_CostMana"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage_CostMana").Value, ApplierType.Attack, new ICheck[] + { + new CostCheck(CostType.Mana, 5) + }); Unit.Attack(Unit); @@ -87,16 +91,18 @@ public void CostMana_Effect() public void CostHealth_HealSelf() { AddRecipe("InitDamage_CostHealth_HealSelf") - .ApplyCost(CostType.Health, 5) .Effect(new DamageEffect(5), EffectOn.Init) .Effect(new HealEffect(5, targeting: Targeting.SourceSource), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamage_CostHealth_HealSelf"); + int id = IdManager.GetId("InitDamage_CostHealth_HealSelf").Value; - Unit.AddApplierModifier(generator, ApplierType.Cast); + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + { + new CostCheck(CostType.Health, 5) + }); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Assert.AreEqual(UnitHealth, Unit.Health); @@ -110,13 +116,17 @@ public void CostSixtyPercentHealth_Damage() .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage_CostSixtyPercentHealth"), ApplierType.Cast); + int id = IdManager.GetId("InitDamage_CostSixtyPercentHealth").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + { + new CostPercentCheck(CostType.Health, 0.6f) + }); - Unit.TryCast("InitDamage_CostSixtyPercentHealth", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Assert.AreEqual(UnitHealth - UnitHealth * 0.6f, Unit.Health); - Unit.TryCast("InitDamage_CostSixtyPercentHealth", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Assert.AreEqual(UnitHealth - UnitHealth * 0.6f, Unit.Health); } diff --git a/ModiBuff/ModiBuff.Units/Unit/Unit.cs b/ModiBuff/ModiBuff.Units/Unit/Unit.cs index bb4e2616..c80b6f1e 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Unit.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Unit.cs @@ -65,6 +65,7 @@ public partial class Unit : IUpdatable, IModifierOwner, IModifierApplierOwner, I private readonly DurationLessStatusEffectController _durationLessStatusEffectController; private readonly Dictionary> _modifierAppliers; + private readonly List _updatableChecks; private readonly Dictionary _modifierLevels; @@ -128,6 +129,7 @@ public Unit(float health = 500, float damage = 10, float healValue = 5, float ma { ApplierType.Attack, new List<(int Id, ICheck[] Checks)>() }, { ApplierType.Cast, new List<(int Id, ICheck[] Checks)>() }, }; + _updatableChecks = new List(); _modifierLevels = new Dictionary(); } @@ -153,6 +155,8 @@ public void Update(float deltaTime) _singleInstanceStatusEffectController.Update(deltaTime); ModifierController.Update(deltaTime); ModifierApplierController.Update(deltaTime); + for (int i = 0; i < _updatableChecks.Count; i++) + _updatableChecks[i].Update(deltaTime); _callbackTimer += deltaTime; if (_callbackTimer >= CallbackTimerCooldown) @@ -352,16 +356,16 @@ public float Heal(IHealable target) return valueHealed; } - public void TryCast(int modifierId, IUnit target) + public bool TryCast(int modifierId, IUnit target) { if (!(target is IModifierOwner modifierTarget)) - return; + return false; if (!modifierId.IsLegalTarget((IUnitEntity)target, this)) - return; + return false; if (!StatusEffectController.HasLegalAction(LegalAction.Cast)) - return; + return false; if (!_modifierAppliers.TryGetValue(ApplierType.Cast, out var appliers)) - return; + return false; (int Id, ICheck[] Checks)? applier = null; for (int i = 0; i < appliers.Count; i++) @@ -374,12 +378,19 @@ public void TryCast(int modifierId, IUnit target) } if (applier == null) - return; - //if (!this.CanCastModifier(modifierId)) - // return; + return false; - for (int i = 0; i < applier.Value.Checks?.Length; i++) - applier.Value.Checks[i].Use(this); + if (applier.Value.Checks != null) + { + foreach (var check in applier.Value.Checks) + if (!check.Check(this)) + return false; + //if (!this.CanCastModifier(modifierId)) + // return; + + for (int i = 0; i < applier.Value.Checks.Length; i++) + applier.Value.Checks[i].Use(this); + } if (++_onCastCounter <= MaxEventCount) { @@ -396,6 +407,8 @@ public void TryCast(int modifierId, IUnit target) ResetEventCounters(); (target as ICallbackCounter)?.ResetEventCounters(); } + + return true; } public void AddDamage(float damage) @@ -482,11 +495,17 @@ public void AddApplierModifierNew(int modifierId, ApplierType applierType, IChec if (_modifierAppliers.TryGetValue(applierType, out var list)) { list.Add((modifierId, checks)); + foreach (var check in checks) + if (check is IUpdatableCheck updatableCheck) + _updatableChecks.Add(updatableCheck); return; } _modifierAppliers[applierType] = new List<(int Id, ICheck[] Checks)>(new[] { (modifierId, checks) }); + foreach (var check in checks) + if (check is IUpdatableCheck updatableCheck) + _updatableChecks.Add(updatableCheck); return; } diff --git a/ModiBuff/ModiBuff/Core/Unit/ICaster.cs b/ModiBuff/ModiBuff/Core/Unit/ICaster.cs index f719c74a..33b276b5 100644 --- a/ModiBuff/ModiBuff/Core/Unit/ICaster.cs +++ b/ModiBuff/ModiBuff/Core/Unit/ICaster.cs @@ -2,6 +2,6 @@ namespace ModiBuff.Core { public interface ICaster : IModifierApplierOwner { - void TryCast(int modifierId, IUnit target); + bool TryCast(int modifierId, IUnit target); } } \ No newline at end of file From 526d6a4c6d6da6ad843219fee88b2c2fb6e4fde3 Mon Sep 17 00:00:00 2001 From: chillu Date: Thu, 28 Aug 2025 23:09:03 +0200 Subject: [PATCH 05/11] feaT: most tests ported to new applier logic --- ModiBuff/ModiBuff.Tests/CastTests.cs | 2 +- .../CentralizedCustomLogicTests.cs | 25 +++--- ModiBuff/ModiBuff.Tests/MetaEffectTests.cs | 46 +++++------ .../ModifierAddReferenceTests.cs | 82 ------------------- ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs | 16 ++-- ModiBuff/ModiBuff.Tests/PostEffectTests.cs | 18 ++-- ModiBuff/ModiBuff.Tests/SaveLoadTests.cs | 16 ++-- ModiBuff/ModiBuff.Tests/StatusEffectTests.cs | 2 +- ModiBuff/ModiBuff.Tests/TargetTests.cs | 8 +- ModiBuff/ModiBuff.Tests/UnitTagTests.cs | 10 ++- .../ModiBuff.Units/Unit/Recipes/UnitRecipe.cs | 7 +- ModiBuff/ModiBuff.Units/Unit/Unit.cs | 16 ++-- .../ModiBuff/Core/ModifierAddReference.cs | 29 ------- .../Core/Unit/ModifierOwnerExtensions.cs | 24 ------ 14 files changed, 85 insertions(+), 216 deletions(-) delete mode 100644 ModiBuff/ModiBuff.Tests/ModifierAddReferenceTests.cs delete mode 100644 ModiBuff/ModiBuff/Core/ModifierAddReference.cs diff --git a/ModiBuff/ModiBuff.Tests/CastTests.cs b/ModiBuff/ModiBuff.Tests/CastTests.cs index 523ebc86..04b2b9b5 100644 --- a/ModiBuff/ModiBuff.Tests/CastTests.cs +++ b/ModiBuff/ModiBuff.Tests/CastTests.cs @@ -89,7 +89,7 @@ public void CastInitDamageChecksDelayedUse_OnEnemy() Assert.True(Unit.TryCast(id, Unit)); Assert.AreEqual(EnemyHealth, Enemy.Health); - Assert.True(Unit.TryCast(id, Enemy)); + Assert.True(Unit.TryCastNoChecks(id, Enemy)); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); } diff --git a/ModiBuff/ModiBuff.Tests/CentralizedCustomLogicTests.cs b/ModiBuff/ModiBuff.Tests/CentralizedCustomLogicTests.cs index 8b9f6ece..a98f10b9 100644 --- a/ModiBuff/ModiBuff.Tests/CentralizedCustomLogicTests.cs +++ b/ModiBuff/ModiBuff.Tests/CentralizedCustomLogicTests.cs @@ -18,12 +18,13 @@ public void PoisonEffect() AddRecipe(PoisonRecipe); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("Poison"), ApplierType.Cast); - Unit.TryCast("Poison", Enemy); + int id = IdManager.GetId("Poison").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); + Unit.TryCast(id, Enemy); Enemy.Update(1); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); - Unit.TryCast("Poison", Enemy); + Unit.TryCast(id, Enemy); Enemy.Update(1); Assert.AreEqual(EnemyHealth - 5 - 5 * 2, Enemy.Health); } @@ -60,13 +61,14 @@ public void HealBasedOnPoisonStacksEvent(RecipeAddFunc recipe) Setup(); Enemy.AddModifierSelf("HealPerPoisonStack"); - Unit.AddApplierModifier(Recipes.GetGenerator("Poison"), ApplierType.Cast); - Unit.TryCast("Poison", Enemy); + int id = IdManager.GetId("Poison").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); + Unit.TryCast(id, Enemy); Enemy.Update(1); Enemy.AddModifierSelf("HealPerPoisonStack"); //Checks for stack behaviour Assert.AreEqual(EnemyHealth - 5 + 1, Enemy.Health); - Unit.TryCast("Poison", Enemy); + Unit.TryCast(id, Enemy); Enemy.Update(1); Assert.AreEqual(EnemyHealth - 5 + 1 - 5 * 2 + 1 * 2, Enemy.Health); } @@ -108,20 +110,21 @@ public void PoisonDamageThornsEvent() Setup(); Enemy.AddModifierSelf("PoisonThorns"); - Unit.AddApplierModifier(Recipes.GetGenerator("Poison"), ApplierType.Cast); + int id = IdManager.GetId("Poison").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); - Unit.TryCast("Poison", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(UnitHealth, Unit.Health); Enemy.Update(1); Assert.AreEqual(UnitHealth - 5, Unit.Health); - Unit.TryCast("Poison", Enemy); + Unit.TryCast(id, Enemy); Enemy.Update(1); Assert.AreEqual(UnitHealth - 5 - 5 * 2, Unit.Health); - Ally.AddApplierModifier(Recipes.GetGenerator("Poison"), ApplierType.Cast); - Ally.TryCast("Poison", Enemy); + Ally.AddApplierModifierNew(id, ApplierType.Cast); + Ally.TryCast(id, Enemy); Enemy.Update(1); Assert.AreEqual(UnitHealth - 5 - 5 * 2 - 5 * 2, Unit.Health); diff --git a/ModiBuff/ModiBuff.Tests/MetaEffectTests.cs b/ModiBuff/ModiBuff.Tests/MetaEffectTests.cs index 3b11aaf5..f87e6761 100644 --- a/ModiBuff/ModiBuff.Tests/MetaEffectTests.cs +++ b/ModiBuff/ModiBuff.Tests/MetaEffectTests.cs @@ -14,16 +14,16 @@ public void DamageBasedOnHealth() .SetMetaEffects(new StatPercentMetaEffect(StatType.Health, Targeting.SourceTarget)), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamageValueBasedOnStatMeta"); - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("InitDamageValueBasedOnStatMeta").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); - Unit.TryCast(generator.Id, Enemy); //5 * 1 + Unit.TryCast(id, Enemy); //5 * 1 Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Unit.TakeDamage(UnitHealth / 2f, Unit); - Unit.TryCast(generator.Id, Enemy); //5 * 0.5 + Unit.TryCast(id, Enemy); //5 * 0.5 Assert.AreEqual(EnemyHealth - 5 - 2.5f, Enemy.Health); } @@ -39,17 +39,17 @@ public void DamageBasedOnHealthAndMana() EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamageValueBasedOnHealthAndManaMeta"); - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("InitDamageValueBasedOnHealthAndManaMeta").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); - Unit.TryCast(generator.Id, Enemy); //5 * 1 + Unit.TryCast(id, Enemy); //5 * 1 Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Unit.TakeDamage(UnitHealth / 2f, Unit); Unit.UseMana(UnitMana / 2f); - Unit.TryCast(generator.Id, Enemy); //5 * 0.5 * 0.5 + Unit.TryCast(id, Enemy); //5 * 0.5 * 0.5 Assert.AreEqual(EnemyHealth - 5 - 1.25f, Enemy.Health); } @@ -65,21 +65,21 @@ public void CanCastHalfMulti_IsStunnedDoubleMulti() EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamageValueBasedOnStatusEffectMeta"); - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("InitDamageValueBasedOnStatusEffectMeta").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Enemy.StatusEffectController.ChangeStatusEffect(0, 0, StatusEffectType.Disarm, 1f, Unit); - Unit.TryCast(generator.Id, Enemy); //5 * 2f + Unit.TryCast(id, Enemy); //5 * 2f Assert.AreEqual(EnemyHealth - 5 - 10f, Enemy.Health); Enemy.Update(1f); Enemy.StatusEffectController.ChangeStatusEffect(0, 0, StatusEffectType.Silence, 1f, Unit); - Unit.TryCast(generator.Id, Enemy); //5 * 0.5f + Unit.TryCast(id, Enemy); //5 * 0.5f Assert.AreEqual(EnemyHealth - 5 - 10f - 2.5f, Enemy.Health); } @@ -92,15 +92,15 @@ public void DoubleMultiplierWhenSilenced() EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamageValue2XWhenDisarmedMeta"); - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("InitDamageValue2XWhenDisarmedMeta").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Unit.StatusEffectController.ChangeStatusEffect(0, 0, StatusEffectType.Disarm, 1f, Enemy); - Unit.TryCast(generator.Id, Enemy); //5 * 2f + Unit.TryCast(id, Enemy); //5 * 2f Assert.AreEqual(EnemyHealth - 5 - 10f, Enemy.Health); } @@ -114,26 +114,26 @@ public void ConditionalEffectsBasedOnManaUsage() EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamageDynamicEffectValueOnManaSpentMeta"); - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("InitDamageDynamicEffectValueOnManaSpentMeta").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); Unit.UseMana(UnitMana); Unit.UseMana(-3); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 2, Enemy.Health); Assert.AreEqual(0, Unit.Mana); Unit.UseMana(-2); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 2 - 1.5, Enemy.Health); Assert.AreEqual(0, Unit.Mana); Unit.UseMana(-1); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 2 - 1.5 - 1, Enemy.Health); Assert.AreEqual(0, Unit.Mana); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 2 - 1.5 - 1, Enemy.Health); Assert.AreEqual(0, Unit.Mana); } diff --git a/ModiBuff/ModiBuff.Tests/ModifierAddReferenceTests.cs b/ModiBuff/ModiBuff.Tests/ModifierAddReferenceTests.cs deleted file mode 100644 index 3d540214..00000000 --- a/ModiBuff/ModiBuff.Tests/ModifierAddReferenceTests.cs +++ /dev/null @@ -1,82 +0,0 @@ -using ModiBuff.Core; -using ModiBuff.Core.Units; -using NUnit.Framework; - -namespace ModiBuff.Tests -{ - public sealed class ModifierAddReferenceTests : ModifierTests - { - [Test] - public void AddSelfModifier() - { - Setup(); - - var generator = Recipes.GetGenerator("InitDamage"); - var modifierReference = new ModifierAddReference(generator); - - Unit.TryAddModifierReference(modifierReference); - - Assert.AreEqual(UnitHealth - 5, Unit.Health); - } - - [Test] - public void AddTargetModifier() - { - Setup(); - - var generator = Recipes.GetGenerator("InitDamage"); - var modifierReference = new ModifierAddReference(generator); - - Unit.TryAddModifierReference(modifierReference, Enemy); - - Assert.AreEqual(EnemyHealth - 5, Enemy.Health); - } - - [Test] - public void AddTargetApplyAttackModifier() - { - Setup(); - - var generator = Recipes.GetGenerator("InitDamage"); - var modifierReference = new ModifierAddReference(generator, ApplierType.Attack); - - Unit.TryAddModifierReference(modifierReference); - - Unit.Attack(Enemy); - - Assert.AreEqual(EnemyHealth - UnitDamage - 5, Enemy.Health); - } - - [Test] - public void AddSelfApplyAttackModifier() - { - AddRecipe("InitDamageSelf") - .Effect(new DamageEffect(5, targeting: Targeting.SourceTarget), EffectOn.Init); - Setup(); - - var generator = Recipes.GetGenerator("InitDamageSelf"); - var modifierReference = new ModifierAddReference(generator, ApplierType.Attack); - - Unit.TryAddModifierReference(modifierReference); - - Unit.Attack(Enemy); - - Assert.AreEqual(UnitHealth - 5, Unit.Health); - } - - [Test] - public void AddTargetApplyCastModifier() - { - Setup(); - - var generator = Recipes.GetGenerator("InitDamage"); - var modifierReference = new ModifierAddReference(generator, ApplierType.Cast); - - Unit.TryAddModifierReference(modifierReference); - - Unit.TryCast(generator.Id, Enemy); - - Assert.AreEqual(EnemyHealth - 5, Enemy.Health); - } - } -} \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs b/ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs index 1a556f23..6015f86b 100644 --- a/ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs +++ b/ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs @@ -69,11 +69,12 @@ public void CastInitDamageOnAlly_EnemyOnlyLegalTarget() .Effect(new DamageEffect(5f), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageEnemyOnly"), ApplierType.Cast); - Unit.TryCast(IdManager.GetId("InitDamageEnemyOnly").Value, Enemy); + int id = IdManager.GetId("InitDamageEnemyOnly").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth - 5f, Enemy.Health); - Unit.TryCast(IdManager.GetId("InitDamageEnemyOnly").Value, Ally); + Unit.TryCast(id, Ally); Assert.AreEqual(AllyHealth, Ally.Health); } @@ -85,13 +86,14 @@ public void CastInitAddDamageOnSelf_SelfOnlyLegalTarget() .Effect(new AddDamageEffect(5f), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitAddDamageSelfOnly"), ApplierType.Cast); - Unit.TryCast(IdManager.GetId("InitAddDamageSelfOnly").Value, Ally); + int id = IdManager.GetId("InitAddDamageSelfOnly").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); + Unit.TryCast(id, Ally); Assert.AreEqual(AllyDamage, Ally.Damage); - Unit.TryCast(IdManager.GetId("InitAddDamageSelfOnly").Value, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyDamage, Enemy.Damage); - Unit.TryCast(IdManager.GetId("InitAddDamageSelfOnly").Value, Unit); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitDamage + 5f, Unit.Damage); } diff --git a/ModiBuff/ModiBuff.Tests/PostEffectTests.cs b/ModiBuff/ModiBuff.Tests/PostEffectTests.cs index b4f6a8b0..4767476e 100644 --- a/ModiBuff/ModiBuff.Tests/PostEffectTests.cs +++ b/ModiBuff/ModiBuff.Tests/PostEffectTests.cs @@ -14,12 +14,12 @@ public void LifeSteal_OnDamageEffectInit() .SetPostEffects(new LifeStealPostEffect(0.5f, Targeting.SourceTarget)), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamageLifeStealPost"); - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("InitDamageLifeStealPost").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); Unit.TakeDamage(2.5f, Unit); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(UnitHealth, Unit.Health); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); @@ -33,12 +33,12 @@ public void AddDamage_OnKill_WithDamageEffectInit() .SetPostEffects(new AddDamageOnKillPostEffect(2, Targeting.SourceTarget)), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamageAddDamageOnKillPost"); - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("InitDamageAddDamageOnKillPost").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); Enemy.TakeDamage(EnemyHealth - 5, Unit); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(UnitDamage + 2, Unit.Damage); Assert.AreEqual(0, Enemy.Health); @@ -52,12 +52,12 @@ public void HealTargetDamageSelf() .SetPostEffects(new DamagePostEffect(Targeting.SourceTarget)), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("HealDamageSelfPost"); - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("HealDamageSelfPost").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); Enemy.TakeDamage(5, Enemy); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth, Enemy.Health); Assert.AreEqual(UnitHealth - 5, Unit.Health); diff --git a/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs b/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs index 09fe9238..80e9c7e6 100644 --- a/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs +++ b/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs @@ -180,22 +180,26 @@ public void SaveLoadEventCallbackState() public void SaveLoadApplierState() { AddRecipe("InitDamageChecks") - .ApplyCooldown(1) - .ApplyCost(CostType.Health, 5) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageChecks"), ApplierType.Cast); - Unit.TryCast("InitDamageChecks", Unit); + int id = IdManager.GetId("InitDamageChecks").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + { + new CooldownCheck(1), //TODO Serialialize state + new CostCheck(CostType.Health, 5) + }); + Unit.TryCast(id, Unit); Assert.AreEqual(UnitHealth - 5 - 5, Unit.Health); SaveLoadGameState(Unit, out var loadedUnit); - loadedUnit.TryCast("InitDamageChecks", loadedUnit); + id = IdManager.GetId("InitDamageChecks").Value; + loadedUnit.TryCast(id, loadedUnit); Assert.AreEqual(UnitHealth - 5 - 5, loadedUnit.Health); loadedUnit.Update(1); - loadedUnit.TryCast("InitDamageChecks", loadedUnit); + loadedUnit.TryCast(id, loadedUnit); Assert.AreEqual(UnitHealth - 5 - 5 - 5 - 5, loadedUnit.Health); } diff --git a/ModiBuff/ModiBuff.Tests/StatusEffectTests.cs b/ModiBuff/ModiBuff.Tests/StatusEffectTests.cs index d95e8cab..21df88fd 100644 --- a/ModiBuff/ModiBuff.Tests/StatusEffectTests.cs +++ b/ModiBuff/ModiBuff.Tests/StatusEffectTests.cs @@ -276,7 +276,7 @@ public void StunTwice_SameIdDifferentGenId_RevertFirst() Setup(); int id = IdManager.GetId("InitStunInstanceStackable_Revertible").Value; - Ally.ModifierApplierController.TryAddApplier(id, false, ApplierType.Cast); + Ally.AddApplierModifierNew(id, ApplierType.Cast); Unit.AddModifierSelf("InitStunInstanceStackable_Revertible"); //3s Assert.True(Unit.StatusEffectController.HasStatusEffect(StatusEffectType.Stun)); diff --git a/ModiBuff/ModiBuff.Tests/TargetTests.cs b/ModiBuff/ModiBuff.Tests/TargetTests.cs index ab41c9c0..0b03294d 100644 --- a/ModiBuff/ModiBuff.Tests/TargetTests.cs +++ b/ModiBuff/ModiBuff.Tests/TargetTests.cs @@ -14,11 +14,11 @@ public void MultiTarget_AddDamage_Revertible() .Remove(5); Setup(); - var generator = Recipes.GetGenerator("InitAddDamageRevertible"); - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("InitAddDamageRevertible").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); - Unit.TryCast(generator.Id, Enemy); - Unit.TryCast(generator.Id, Ally); + Unit.TryCast(id, Enemy); + Unit.TryCast(id, Ally); Assert.AreEqual(EnemyDamage + 5, Enemy.Damage); Assert.AreEqual(AllyDamage + 5, Ally.Damage); diff --git a/ModiBuff/ModiBuff.Tests/UnitTagTests.cs b/ModiBuff/ModiBuff.Tests/UnitTagTests.cs index 139dffc3..c163b49e 100644 --- a/ModiBuff/ModiBuff.Tests/UnitTagTests.cs +++ b/ModiBuff/ModiBuff.Tests/UnitTagTests.cs @@ -14,12 +14,13 @@ public void LifestealableUnit() .SetPostEffects(new LifeStealPostEffect(1f, Targeting.SourceTarget)), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageLifesteal"), ApplierType.Cast); + int id = IdManager.GetId("InitDamageLifesteal").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); Unit.TakeDamage(5, Unit); Assert.AreEqual(UnitHealth - 5, Unit.Health); - Unit.TryCast("InitDamageLifesteal", Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(UnitHealth, Unit.Health); } @@ -52,12 +53,13 @@ public void LifestealableUnit_NonLifestealableSource() const float health = 100f, damage = 5f; var nonLifeStealableUnit = new Unit(health, damage, unitTag: UnitTag.None); - nonLifeStealableUnit.AddApplierModifier(Recipes.GetGenerator("InitDamageLifesteal"), ApplierType.Cast); + int id = IdManager.GetId("InitDamageLifesteal").Value; + nonLifeStealableUnit.AddApplierModifierNew(id, ApplierType.Cast); nonLifeStealableUnit.TakeDamage(damage, nonLifeStealableUnit); Assert.AreEqual(health - damage, nonLifeStealableUnit.Health); - nonLifeStealableUnit.TryCast("InitDamageLifesteal", Unit); + nonLifeStealableUnit.TryCast(id, Unit); Assert.AreEqual(health, nonLifeStealableUnit.Health); } } diff --git a/ModiBuff/ModiBuff.Units/Unit/Recipes/UnitRecipe.cs b/ModiBuff/ModiBuff.Units/Unit/Recipes/UnitRecipe.cs index 625d7292..96b8019c 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Recipes/UnitRecipe.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Recipes/UnitRecipe.cs @@ -11,7 +11,7 @@ public sealed class UnitRecipe private float _damage; private float _health; - private ModifierAddReference[] _modifierAddReferences; + private (int Id, ApplierType? ApplierType)[] _modifiers; private readonly IModifierRecipes _modifierRecipes; @@ -23,8 +23,6 @@ public UnitRecipe(string name, UnitType unitType, ModifierRecipes modifierRecipe _modifierRecipes = modifierRecipes; } - //public Unit Create() => new Unit(_health, _damage, _modifierAddReferences, UnitType); - public UnitRecipe Health(float health) { _health = health; @@ -39,8 +37,7 @@ public UnitRecipe Damage(float damage) public UnitRecipe Modifiers(params (string name, ApplierType? applier)[] modifiers) { - _modifierAddReferences = modifiers - .Select(r => new ModifierAddReference(_modifierRecipes.GetGenerator(r.Item1), r.Item2)).ToArray(); + _modifiers = modifiers.Select(r => (ModifierIdManager.GetIdByName(r.name).Value, r.applier)).ToArray(); return this; } } diff --git a/ModiBuff/ModiBuff.Units/Unit/Unit.cs b/ModiBuff/ModiBuff.Units/Unit/Unit.cs index c80b6f1e..197d7ec6 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Unit.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Unit.cs @@ -134,14 +134,6 @@ public Unit(float health = 500, float damage = 10, float healValue = 5, float ma _modifierLevels = new Dictionary(); } - public Unit(float health, float damage, ModifierAddReference[] modifierAddReferences, - UnitType unitType, UnitTag unitTag) - : this(health, damage, unitType: unitType, unitTag: unitTag) - { - foreach (var modifierAddReference in modifierAddReferences) - this.TryAddModifierReference(modifierAddReference); - } - public static Unit LoadUnit(int oldId) { var unit = new Unit(0, 0, 0, 0, UnitType.Neutral, UnitTag.None); @@ -356,7 +348,11 @@ public float Heal(IHealable target) return valueHealed; } - public bool TryCast(int modifierId, IUnit target) + public bool TryCast(int modifierId, IUnit target) => TryCastInternal(modifierId, target); + + internal bool TryCastNoChecks(int modifierId, IUnit target) => TryCastInternal(modifierId, target, true); + + private bool TryCastInternal(int modifierId, IUnit target, bool skipChecks = false) { if (!(target is IModifierOwner modifierTarget)) return false; @@ -380,7 +376,7 @@ public bool TryCast(int modifierId, IUnit target) if (applier == null) return false; - if (applier.Value.Checks != null) + if (applier.Value.Checks != null && !skipChecks) { foreach (var check in applier.Value.Checks) if (!check.Check(this)) diff --git a/ModiBuff/ModiBuff/Core/ModifierAddReference.cs b/ModiBuff/ModiBuff/Core/ModifierAddReference.cs deleted file mode 100644 index 541bbe78..00000000 --- a/ModiBuff/ModiBuff/Core/ModifierAddReference.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace ModiBuff.Core -{ - /// - /// Used to store the data how a modifier should be added - /// - public sealed class ModifierAddReference - { - public int Id { get; } - - public bool IsApplierType => ApplierType != null; - public bool HasApplyChecks { get; } - public ApplierType? ApplierType { get; } - - public ModifierAddReference(IModifierGenerator generator, ApplierType? applierType = null) - { - Id = generator.Id; - if (generator is IModifierApplyCheckGenerator applyCheckGenerator) - HasApplyChecks = applyCheckGenerator.HasApplyChecks; - ApplierType = applierType; - } - - public ModifierAddReference(IModifierApplyCheckGenerator generator, ApplierType? applierType = null) - { - Id = generator.Id; - HasApplyChecks = generator.HasApplyChecks; - ApplierType = applierType; - } - } -} \ No newline at end of file diff --git a/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs b/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs index 10c2bfd2..ac482858 100644 --- a/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs +++ b/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs @@ -12,30 +12,6 @@ public static void Dispel(this IModifierOwner owner, DispelType dispelType, IUni owner.ModifierController.Dispel(dispelType, owner, source); } - public static void TryAddModifierReference(this IUnit owner, ModifierAddReference reference) - { - TryAddModifierReference(owner, reference, owner); - } - - public static void TryAddModifierReference(this IUnit owner, ModifierAddReference reference, IUnit target) - { - if (reference.IsApplierType) - { - if (owner is IModifierApplierOwner modifierApplierOwner) - modifierApplierOwner.ModifierApplierController.TryAddApplier(reference.Id, - reference.HasApplyChecks, reference.ApplierType!.Value); - else - Logger.LogError("[ModiBuff] Tried to add an applier to a unit that is not IModifierApplierOwner"); - } - else - { - if (owner is IModifierOwner modifierOwner) - modifierOwner.ModifierController.Add(reference.Id, target, owner); - else - Logger.LogError("[ModiBuff] Tried to add a modifier to a unit that is not IModifierOwner"); - } - } - //TODO Remove public static void TryCast(this IModifierApplierOwner owner, int modifierId, IModifierOwner target) { From 32e58aca5e31952899d326229a2822d5faf2d6e8 Mon Sep 17 00:00:00 2001 From: chillu Date: Fri, 29 Aug 2025 17:47:46 +0200 Subject: [PATCH 06/11] feat: serializing checks save load progress --- ModiBuff/ModiBuff.Tests/SaveLoadTests.cs | 6 +++- ModiBuff/ModiBuff.Units/Unit/Unit.cs | 38 ++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs b/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs index 80e9c7e6..97f565f3 100644 --- a/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs +++ b/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs @@ -276,11 +276,15 @@ public void SaveNewModifierApplierIdLoad() const string gameStateFile = "modifierApplierIdGameStateTest.json"; + int id = IdManager.GetId("DoTHealthCost").Value; //TODO save will not have modifier id redirection if (!File.Exists(_saveController.Path + "/" + gameStateFile)) { Unit.AddApplierModifier(Recipes.GetGenerator("DoT"), ApplierType.Cast); - Unit.AddApplierModifier(Recipes.GetGenerator("DoTHealthCost"), ApplierType.Cast); + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + { + new CostCheck(CostType.Health, 5) + }); SaveGameState(gameStateFile, Unit); } diff --git a/ModiBuff/ModiBuff.Units/Unit/Unit.cs b/ModiBuff/ModiBuff.Units/Unit/Unit.cs index 197d7ec6..4ef34334 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Unit.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Unit.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Runtime.CompilerServices; using ModiBuff.Core.Units.Interfaces.NonGeneric; @@ -594,7 +595,10 @@ public SaveData SaveState() { return new SaveData(Id, UnitTag, Health, MaxHealth, Damage, HealValue, Mana, MaxMana, UnitType, IsDead, ModifierController.SaveState(), ModifierApplierController.SaveState(), - _statusEffectController.SaveState(), _singleInstanceStatusEffectController.SaveState()); + _modifierAppliers.ToDictionary(a => a.Key, a => a.Value.Select(cs => (cs.Id, cs.Checks.Select( + c => (c as IStateCheck)?.SaveState())))), + _statusEffectController.SaveState(), + _singleInstanceStatusEffectController.SaveState()); } public void LoadState(SaveData data) @@ -610,6 +614,34 @@ public void LoadState(SaveData data) IsDead = data.IsDead; ModifierController.LoadState(data.ModifierControllerSaveData, this); ModifierApplierController.LoadState(data.ModifierApplierControllerSaveData); + _modifierAppliers.Clear(); + foreach (var kvp in data.Appliers) + { + var modifierApplier = new List<(int Id, ICheck[]? Checks)>(); + List checks = new List(); + foreach ((int id, var checkStates) in kvp.Value) + { + foreach (object state in checkStates) + { + IStateCheck? loadedCheck = null; +#if MODIBUFF_SYSTEM_TEXT_JSON + if (state.FromAnonymousJsonObjectToSaveData(loadedCheck)) + { + checks.Add(loadedCheck); + continue; + } +#endif + loadedCheck.LoadState((IStateCheck)state); + checks.Add(loadedCheck); + } + + modifierApplier.Add((id, checks.Count > 0 ? checks.ToArray() : null)); + checks.Clear(); + } + + _modifierAppliers[kvp.Key] = modifierApplier; + } + _statusEffectController.LoadState(data.MultiInstanceStatusEffectControllerSaveData); _singleInstanceStatusEffectController.LoadState(data.SingleInstanceStatusEffectControllerSaveData); } @@ -633,8 +665,8 @@ public readonly struct SaveData public readonly bool IsDead; public readonly ModifierController.SaveData ModifierControllerSaveData; - public readonly ModifierApplierController.SaveData ModifierApplierControllerSaveData; + public readonly IReadOnlyDictionary)>> Appliers; public readonly MultiInstanceStatusEffectController.SaveData MultiInstanceStatusEffectControllerSaveData; public readonly StatusEffectController.SaveData SingleInstanceStatusEffectControllerSaveData; @@ -645,6 +677,7 @@ public SaveData(int id, UnitTag unitTag, float health, float maxHealth, float da float mana, float maxMana, UnitType unitType, bool isDead, ModifierController.SaveData modifierControllerSaveData, ModifierApplierController.SaveData modifierApplierControllerSaveData, + IReadOnlyDictionary)>> appliers, MultiInstanceStatusEffectController.SaveData multiInstanceStatusEffectControllerSaveData, StatusEffectController.SaveData singleInstanceStatusEffectControllerSaveData) { @@ -660,6 +693,7 @@ public SaveData(int id, UnitTag unitTag, float health, float maxHealth, float da IsDead = isDead; ModifierControllerSaveData = modifierControllerSaveData; ModifierApplierControllerSaveData = modifierApplierControllerSaveData; + Appliers = appliers; MultiInstanceStatusEffectControllerSaveData = multiInstanceStatusEffectControllerSaveData; SingleInstanceStatusEffectControllerSaveData = singleInstanceStatusEffectControllerSaveData; } From 9d00171987d90148508609401d146b8df0faf78c Mon Sep 17 00:00:00 2001 From: chillu Date: Sat, 30 Aug 2025 16:51:07 +0200 Subject: [PATCH 07/11] feat: ported all tests to new applier system --- ModiBuff/ModiBuff.Tests/CastTests.cs | 4 +- ModiBuff/ModiBuff.Tests/ChanceTests.cs | 8 +- ModiBuff/ModiBuff.Tests/CostTests.cs | 12 ++- ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs | 8 +- .../PartialUnitTests/DamagableUnitTests.cs | 76 +++++++++++++++---- .../ModifierApplierUnitTests.cs | 15 ++-- .../PartialUnitTests/NoModifierUnitTests.cs | 8 +- ModiBuff/ModiBuff.Tests/SaveLoadTests.cs | 18 ++--- ModiBuff/ModiBuff.Tests/StatusEffectTests.cs | 9 +-- ModiBuff/ModiBuff.Tests/UnitTagTests.cs | 5 +- ModiBuff/ModiBuff.Tests/UnitTests.cs | 15 ++-- ModiBuff/ModiBuff.Units/Unit/Unit.cs | 44 ++++++----- 12 files changed, 144 insertions(+), 78 deletions(-) diff --git a/ModiBuff/ModiBuff.Tests/CastTests.cs b/ModiBuff/ModiBuff.Tests/CastTests.cs index 04b2b9b5..52608ef9 100644 --- a/ModiBuff/ModiBuff.Tests/CastTests.cs +++ b/ModiBuff/ModiBuff.Tests/CastTests.cs @@ -110,7 +110,7 @@ public void CastOnCastEventRecursion() Assert.AreEqual(EnemyHealth - 5 - 5 * Unit.MaxEventCount, Enemy.Health); } - //[Test] + [Test, Ignore("Advanced applier logic needed")] public void SelfApplyIfNotCast() { //Trigger duration timer, if duration timer ends, damages self @@ -151,7 +151,7 @@ public void SelfApplyIfNotCast() //Unit.AddEffectApplier("DurationDamageCast"); //Unit.TryCastEffect("DurationDamageCast", Unit); //Adds modifier, starts duration - Unit.AddApplierModifier(Recipes.GetGenerator("DurationDamageCast"), ApplierType.Cast); + Unit.AddApplierModifierNew(IdManager.GetId("DurationDamageCast").Value, ApplierType.Cast); Unit.TryCast("DurationDamageCast", Unit); //Adds modifier, starts duration Unit.TryCast("DurationDamageSelfCast", Enemy); //Removes modifier, applies damage to enemy diff --git a/ModiBuff/ModiBuff.Tests/ChanceTests.cs b/ModiBuff/ModiBuff.Tests/ChanceTests.cs index ce01892c..d80b34aa 100644 --- a/ModiBuff/ModiBuff.Tests/ChanceTests.cs +++ b/ModiBuff/ModiBuff.Tests/ChanceTests.cs @@ -10,11 +10,13 @@ public sealed class ChanceTests : ModifierTests public void Random_InitDamage() { AddRecipe("ChanceInitDamage") - .ApplyChance(0.5f) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("ChanceInitDamage"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("ChanceInitDamage").Value, ApplierType.Attack, new ICheck[] + { + new ChanceCheck(0.5f) + }); for (int i = 0; i < 50; i++) Unit.Attack(Enemy); @@ -64,7 +66,7 @@ public void Random_IntervalDamage_Effect() //DurationComp should not have modifier checks, cuz remove comp might be there, and that should always be called. //Fix this somehow (through recipes) - //[Test] + [Test, Ignore("Duration component currently does not support modifier checks, and won't either")] public void Random_DurationDamage_Effect() { AddRecipe("ChanceEffectDurationDamage") diff --git a/ModiBuff/ModiBuff.Tests/CostTests.cs b/ModiBuff/ModiBuff.Tests/CostTests.cs index 86a9f675..7f67d858 100644 --- a/ModiBuff/ModiBuff.Tests/CostTests.cs +++ b/ModiBuff/ModiBuff.Tests/CostTests.cs @@ -27,11 +27,13 @@ public void CostHealth() public void CostHealth_NotLethal() { AddRecipe("InitDamage_CostHealth") - .ApplyCost(CostType.Health, 5) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage_CostHealth"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage_CostHealth").Value, ApplierType.Attack, new ICheck[] + { + new CostCheck(CostType.Health, 5) + }); Unit.TakeDamage(UnitHealth - 1, Unit); Unit.Attack(Enemy); //Shouldn't activate, because the Unit would die @@ -60,11 +62,13 @@ public void CostMana() public void CostMana_NotEnough() { AddRecipe("InitDamage_CostMana") - .ApplyCost(CostType.Mana, 5) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage_CostMana"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage_CostMana").Value, ApplierType.Attack, new ICheck[] + { + new CostCheck(CostType.Mana, 5) + }); Unit.UseMana(UnitMana - 1); Unit.TakeDamage(UnitHealth - 1, Unit); diff --git a/ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs b/ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs index 6015f86b..5cd42079 100644 --- a/ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs +++ b/ModiBuff/ModiBuff.Tests/ModifierTagsTests.cs @@ -122,11 +122,11 @@ public void AutomaticTimeComponentTagging() }); Setup(); - var intervalGenerator = Recipes.GetGenerator("IntervalRefreshDamage"); - Assert.True(ModifierRecipes.GetTag(intervalGenerator.Id).HasTag(TagType.IsRefresh)); + int intervalId = IdManager.GetId("IntervalRefreshDamage").Value; + Assert.True(ModifierRecipes.GetTag(intervalId).HasTag(TagType.IsRefresh)); - var durationGenerator = Recipes.GetGenerator("DurationRefreshDamage"); - Assert.True(ModifierRecipes.GetTag(durationGenerator.Id).HasTag(TagType.IsRefresh)); + int durationId = IdManager.GetId("DurationRefreshDamage").Value; + Assert.True(ModifierRecipes.GetTag(durationId).HasTag(TagType.IsRefresh)); } } } \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs index c6f27636..a0994cd0 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs @@ -86,6 +86,48 @@ public void AddApplierModifierNew(int modifierId, ApplierType applierType, IChec _modifierAppliers[applierType].Add((modifierId, null)); } + + public bool TryCast(int modifierId, IUnit target) => TryCastInternal(modifierId, target); + + internal bool TryCastNoChecks(int modifierId, IUnit target) => TryCastInternal(modifierId, target, true); + + private bool TryCastInternal(int modifierId, IUnit target, bool skipChecks = false) + { + if (!(target is IModifierOwner modifierTarget)) + return false; + if (!modifierId.IsLegalTarget((IUnitEntity)target, this)) + return false; + if (!_modifierAppliers.TryGetValue(ApplierType.Cast, out var appliers)) + return false; + + (int Id, ICheck[] Checks)? applier = null; + for (int i = 0; i < appliers.Count; i++) + { + if (appliers[i].Id == modifierId) + { + applier = appliers[i]; + break; + } + } + + if (applier == null) + return false; + + if (applier.Value.Checks != null && !skipChecks) + { + foreach (var check in applier.Value.Checks) + if (!check.Check(this)) + return false; + + for (int i = 0; i < applier.Value.Checks.Length; i++) + applier.Value.Checks[i].Use(this); + } + + modifierTarget.ModifierController.Add(modifierId, modifierTarget, this); + + + return true; + } } [Test] @@ -143,41 +185,49 @@ public void TryDamagePostHeal_UnHealableUnit() public void InitDamageApplyCosts_UnitWithoutMana() { AddRecipe("InitDamageManaCost") - .ApplyCost(CostType.Mana, 5) .Effect(new DamageEffect(5), EffectOn.Init); AddRecipe("InitDamageHealthCost") - .ApplyCost(CostType.Health, 5) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageManaCost"), ApplierType.Cast); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageHealthCost"), ApplierType.Cast); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamageManaCost").Value, ApplierType.Cast, new ICheck[] + { + new CostCheck(CostType.Mana, 5) + }); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamageHealthCost").Value, ApplierType.Cast, new ICheck[] + { + new CostCheck(CostType.Health, 5) + }); - Unit.TryCast("InitDamageManaCost", Unit); + Unit.TryCast(IdManager.GetId("InitDamageManaCost").Value, Unit); Assert.AreEqual(UnitHealth, Unit.Health); - Unit.TryCast("InitDamageHealthCost", Unit); + Unit.TryCast(IdManager.GetId("InitDamageHealthCost").Value, Unit); Assert.AreEqual(UnitHealth - 5 - 5, Unit.Health); } - [Test] + [Test, Ignore("Effect checks, aka on target, not source")] public void InitDamageEffectCosts_UnitWithoutMana() { AddRecipe("InitDamageManaCost") - .EffectCost(CostType.Mana, 5) .Effect(new DamageEffect(5), EffectOn.Init); AddRecipe("InitDamageHealthCost") - .EffectCost(CostType.Health, 5) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageManaCost"), ApplierType.Cast); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageHealthCost"), ApplierType.Cast); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamageManaCost").Value, ApplierType.Cast, new ICheck[] + { + new CostCheck(CostType.Mana, 5) + }); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamageHealthCost").Value, ApplierType.Cast, new ICheck[] + { + new CostCheck(CostType.Health, 5) + }); - Unit.TryCast("InitDamageManaCost", Unit); + Unit.TryCast(IdManager.GetId("InitDamageManaCost").Value, Unit); Assert.AreEqual(UnitHealth, Unit.Health); - Unit.TryCast("InitDamageHealthCost", Unit); + Unit.TryCast(IdManager.GetId("InitDamageHealthCost").Value, Unit); Assert.AreEqual(UnitHealth - 5 - 5, Unit.Health); } diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs index 58513dea..8b3adb30 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs @@ -81,18 +81,23 @@ public void AddApplierModifierNew(int modifierId, ApplierType applierType, IChec public void TryApplyDamageAppliers_ModifierAppliersUnit() { AddRecipe("InitDamageCooldown") - .ApplyCooldown(1) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Attack); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageCooldown"), ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamage").Value, ApplierType.Attack); + Unit.AddApplierModifierNew(IdManager.GetId("InitDamageCooldown").Value, ApplierType.Attack, new ICheck[] + { + new CooldownCheck(1) + }); Unit.Attack(Unit); Assert.AreEqual(UnitHealth - UnitDamage, Unit.Health); - Enemy.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Attack); - Enemy.AddApplierModifier(Recipes.GetGenerator("InitDamageCooldown"), ApplierType.Attack); + Enemy.AddApplierModifierNew(IdManager.GetId("InitDamage").Value, ApplierType.Attack); + Enemy.AddApplierModifierNew(IdManager.GetId("InitDamageCooldown").Value, ApplierType.Attack, new ICheck[] + { + new CooldownCheck(1) + }); Enemy.Attack(Unit); Assert.AreEqual(UnitHealth - UnitDamage - EnemyDamage, Unit.Health); diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs index 50b9f75e..77c37d89 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs @@ -45,12 +45,14 @@ public float TakeDamage(float damage, IUnit source) public void TryApplyDamageAppliers_NoModifiersUnit() { AddRecipe("InitDamageCooldown") - .ApplyCooldown(1) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - Enemy.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Attack); - Enemy.AddApplierModifier(Recipes.GetGenerator("InitDamageCooldown"), ApplierType.Attack); + Enemy.AddApplierModifierNew(IdManager.GetId("InitDamage").Value, ApplierType.Attack); + Enemy.AddApplierModifierNew(IdManager.GetId("InitDamageCooldown").Value, ApplierType.Attack, new ICheck[] + { + new CooldownCheck(1) + }); Enemy.Attack(Unit); Assert.AreEqual(UnitHealth - EnemyDamage, Unit.Health); diff --git a/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs b/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs index 97f565f3..14881522 100644 --- a/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs +++ b/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs @@ -173,7 +173,7 @@ public void SaveLoadEventCallbackState() Assert.AreEqual(UnitDamage, loadedUnit.Damage); } - [Test] + [Test, Ignore("Needs serializing of all IChecks on runtime")] #if !MODIBUFF_SYSTEM_TEXT_JSON [Ignore("MODIBUFF_SYSTEM_TEXT_JSON not set. Skipping test")] #endif @@ -186,7 +186,7 @@ public void SaveLoadApplierState() int id = IdManager.GetId("InitDamageChecks").Value; Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] { - new CooldownCheck(1), //TODO Serialialize state + new CooldownCheck(1), new CostCheck(CostType.Health, 5) }); Unit.TryCast(id, Unit); @@ -259,7 +259,7 @@ public void SaveNewModifierIdLoad() Assert.AreEqual(UnitHealth - 20, loadedUnit.Health); } - [Test] + [Test, Ignore("Needs serializing of all IChecks on runtime")] #if !MODIBUFF_SYSTEM_TEXT_JSON [Ignore("MODIBUFF_SYSTEM_TEXT_JSON not set. Skipping test")] #endif @@ -269,19 +269,17 @@ public void SaveNewModifierApplierIdLoad() .Interval(1) .Effect(new DamageEffect(10), EffectOn.Interval); AddRecipe("DoTHealthCost") - .ApplyCost(CostType.Health, 5) .Interval(1) .Effect(new DamageEffect(10), EffectOn.Interval); Setup(); const string gameStateFile = "modifierApplierIdGameStateTest.json"; - int id = IdManager.GetId("DoTHealthCost").Value; //TODO save will not have modifier id redirection if (!File.Exists(_saveController.Path + "/" + gameStateFile)) { - Unit.AddApplierModifier(Recipes.GetGenerator("DoT"), ApplierType.Cast); - Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] + Unit.AddApplierModifierNew(IdManager.GetId("DoT").Value, ApplierType.Cast); + Unit.AddApplierModifierNew(IdManager.GetId("DoTHealthCost").Value, ApplierType.Cast, new ICheck[] { new CostCheck(CostType.Health, 5) }); @@ -355,7 +353,7 @@ public void SaveModifierNewEffectLoad() Assert.AreEqual(UnitHealth - damage + 5 + 2 + 5 + 4, loadedUnit.Health); } - //[Test] + [Test, Ignore("StatusEffectEffect does not save id & genId yet, so this test will fail")] public void SaveStatusEffectGenIdLoad() { AddRecipe("InitStun") @@ -441,8 +439,8 @@ public void SavePoisonEffectLoad() //TODO save will not have unit id redirection if (!File.Exists(_saveController.Path + "/" + gameStateFile)) { - Ally.AddApplierModifier(Recipes.GetGenerator("Poison"), ApplierType.Cast); - Enemy.AddApplierModifier(Recipes.GetGenerator("Poison"), ApplierType.Cast); + Ally.AddApplierModifierNew(IdManager.GetId("Poison").Value, ApplierType.Cast); + Enemy.AddApplierModifierNew(IdManager.GetId("Poison").Value, ApplierType.Cast); Unit.AddModifierSelf("PoisonThorns"); Ally.TryCast("Poison", Unit); diff --git a/ModiBuff/ModiBuff.Tests/StatusEffectTests.cs b/ModiBuff/ModiBuff.Tests/StatusEffectTests.cs index 21df88fd..9580c6fc 100644 --- a/ModiBuff/ModiBuff.Tests/StatusEffectTests.cs +++ b/ModiBuff/ModiBuff.Tests/StatusEffectTests.cs @@ -56,14 +56,13 @@ public void Silence_CantCast() .Effect(new StatusEffectEffect(StatusEffectType.Silence, 2), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamage"); - - Unit.AddApplierModifier(generator, ApplierType.Cast); + int id = IdManager.GetId("InitDamage").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); Unit.AddModifierSelf("InitSilence"); Assert.True(Unit.StatusEffectController.HasStatusEffect(StatusEffectType.Silence)); - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(EnemyHealth, Enemy.Health); } @@ -310,7 +309,7 @@ public void DurationLessStatusEffect_DurationOver() Assert.AreEqual(EnemyHealth - UnitDamage, Enemy.Health); } - //[Test] + [Test, Ignore("Needs to sync remove timer with status effect timer")] public void Stun_StackAddTime() { //TODO We need to sync remove timer with status effect timer diff --git a/ModiBuff/ModiBuff.Tests/UnitTagTests.cs b/ModiBuff/ModiBuff.Tests/UnitTagTests.cs index c163b49e..c2f3d6a7 100644 --- a/ModiBuff/ModiBuff.Tests/UnitTagTests.cs +++ b/ModiBuff/ModiBuff.Tests/UnitTagTests.cs @@ -33,12 +33,13 @@ public void NonLifestealableUnit() Setup(); var nonLifeStealableUnit = new Unit(unitTag: UnitTag.None); - Unit.AddApplierModifier(Recipes.GetGenerator("InitDamageLifesteal"), ApplierType.Cast); + int id = IdManager.GetId("InitDamageLifesteal").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast); Unit.TakeDamage(UnitDamage, Unit); Assert.AreEqual(UnitHealth - UnitDamage, Unit.Health); - Unit.TryCast("InitDamageLifesteal", nonLifeStealableUnit); + Unit.TryCast(id, nonLifeStealableUnit); Assert.AreEqual(UnitHealth - UnitDamage, Unit.Health); } diff --git a/ModiBuff/ModiBuff.Tests/UnitTests.cs b/ModiBuff/ModiBuff.Tests/UnitTests.cs index 1d3962f2..f989a6d3 100644 --- a/ModiBuff/ModiBuff.Tests/UnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/UnitTests.cs @@ -23,7 +23,6 @@ public void DamageDamagableUnit() public void UnitDeath_ModifiersPooled() { AddRecipe("InitDamage_ApplyCondition_HealthAbove100") - .ApplyCondition(StatType.Health, 100, ComparisonType.GreaterOrEqual) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); @@ -35,14 +34,18 @@ public void UnitDeath_ModifiersPooled() var unit = new Unit(); unit.AddModifierSelf("InitDamage"); - unit.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Attack); - unit.AddApplierModifier(Recipes.GetGenerator("InitDamage"), ApplierType.Cast); - unit.AddApplierModifier(Recipes.GetGenerator("InitDamage_ApplyCondition_HealthAbove100"), - ApplierType.Attack); + int id = IdManager.GetId("InitDamage").Value; + unit.AddApplierModifierNew(id, ApplierType.Attack); + unit.AddApplierModifierNew(id, ApplierType.Cast); + unit.AddApplierModifierNew(IdManager.GetId("InitDamage_ApplyCondition_HealthAbove100").Value, + ApplierType.Cast, new ICheck[] + { + new StatCheck(StatType.Health, ComparisonType.GreaterOrEqual, 100) + }); unit.TakeDamage(unit.Health, unit); //Unit dies, all modifiers should be returned to pool - Assert.Throws(() => Pool.Allocate(IdManager.GetId("InitDamage").Value, 1)); + Assert.Throws(() => Pool.Allocate(id, 1)); Pool.SetMaxPoolSize(Config.MaxPoolSize); } diff --git a/ModiBuff/ModiBuff.Units/Unit/Unit.cs b/ModiBuff/ModiBuff.Units/Unit/Unit.cs index 4ef34334..0efc92a0 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Unit.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Unit.cs @@ -614,34 +614,36 @@ public void LoadState(SaveData data) IsDead = data.IsDead; ModifierController.LoadState(data.ModifierControllerSaveData, this); ModifierApplierController.LoadState(data.ModifierApplierControllerSaveData); - _modifierAppliers.Clear(); - foreach (var kvp in data.Appliers) - { - var modifierApplier = new List<(int Id, ICheck[]? Checks)>(); - List checks = new List(); - foreach ((int id, var checkStates) in kvp.Value) + if (data.Appliers != null) + foreach (var loadPair in data.Appliers) { - foreach (object state in checkStates) + foreach ((int id, var checkStates) in loadPair.Value) { - IStateCheck? loadedCheck = null; -#if MODIBUFF_SYSTEM_TEXT_JSON - if (state.FromAnonymousJsonObjectToSaveData(loadedCheck)) + if (!_modifierAppliers[loadPair.Key].Exists(c => c.Id == id)) { - checks.Add(loadedCheck); + Logger.LogWarning( + $"Could not find modifier applier with id {id} for applier type {loadPair.Key} when loading unit {Id}"); continue; } + + var loadCheck = _modifierAppliers[loadPair.Key].First(c => c.Id == id); //TODO Nullable + + int i = 0; + foreach (object state in checkStates) + { +#if MODIBUFF_SYSTEM_TEXT_JSON + if (state.FromAnonymousJsonObjectToSaveData((IStateCheck)loadCheck.Checks[i])) + { + i++; + continue; + } #endif - loadedCheck.LoadState((IStateCheck)state); - checks.Add(loadedCheck); + ((IStateCheck)loadCheck.Checks[i]).LoadState(state); + i++; + } } - - modifierApplier.Add((id, checks.Count > 0 ? checks.ToArray() : null)); - checks.Clear(); } - _modifierAppliers[kvp.Key] = modifierApplier; - } - _statusEffectController.LoadState(data.MultiInstanceStatusEffectControllerSaveData); _singleInstanceStatusEffectController.LoadState(data.SingleInstanceStatusEffectControllerSaveData); } @@ -666,7 +668,7 @@ public readonly struct SaveData public readonly ModifierController.SaveData ModifierControllerSaveData; public readonly ModifierApplierController.SaveData ModifierApplierControllerSaveData; - public readonly IReadOnlyDictionary)>> Appliers; + public readonly IReadOnlyDictionary)>>? Appliers; public readonly MultiInstanceStatusEffectController.SaveData MultiInstanceStatusEffectControllerSaveData; public readonly StatusEffectController.SaveData SingleInstanceStatusEffectControllerSaveData; @@ -677,7 +679,7 @@ public SaveData(int id, UnitTag unitTag, float health, float maxHealth, float da float mana, float maxMana, UnitType unitType, bool isDead, ModifierController.SaveData modifierControllerSaveData, ModifierApplierController.SaveData modifierApplierControllerSaveData, - IReadOnlyDictionary)>> appliers, + IReadOnlyDictionary)>>? appliers, MultiInstanceStatusEffectController.SaveData multiInstanceStatusEffectControllerSaveData, StatusEffectController.SaveData singleInstanceStatusEffectControllerSaveData) { From 62f97012285eab235d1f3ca307c3fcfe7c37f365 Mon Sep 17 00:00:00 2001 From: chillu Date: Sat, 30 Aug 2025 17:57:48 +0200 Subject: [PATCH 08/11] feat: wip initial removal of all old applier logic --- .../BenchmarkModifierRecipes.cs | 2 - .../BasicConsole/GameController.cs | 14 +- .../BasicConsole/ModifierRecipes.cs | 4 +- .../ModiBuff.Examples/BasicConsole/Unit.cs | 72 +++++- ModiBuff/ModiBuff.Tests/ApplierTests.cs | 3 +- ModiBuff/ModiBuff.Tests/ConditionTests.cs | 2 - ModiBuff/ModiBuff.Tests/CooldownTests.cs | 1 - ModiBuff/ModiBuff.Tests/CostTests.cs | 1 - .../ModifierApplierUnitTests.cs | 27 +- ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs | 13 - .../Effects/Actions/CastActionEffect.cs | 2 +- .../Recipe/ModifierRecipeExtensions.cs | 68 ----- .../StatusEffectModifierOwnerExtensions.cs | 36 --- ModiBuff/ModiBuff.Units/Unit/Unit.cs | 15 +- ModiBuff/ModiBuff/Core/Config.cs | 18 -- .../Components/Effect/ApplierEffect.cs | 2 - .../Components/Effect/RemoveEffect.cs | 15 +- .../IModifierApplyCheckGenerator.cs | 9 - .../Creation/Generation/ModifierGenerator.cs | 31 +-- .../Creation/Recipe/ModifierRecipe.cs | 33 +-- .../Creation/Recipe/ModifierRecipeData.cs | 15 +- .../Modifier/ModifierApplierController.cs | 238 ------------------ .../Core/Pool/ModifierControllerPool.cs | 42 ---- ModiBuff/ModiBuff/Core/Pool/ModifierPool.cs | 65 ----- .../Core/Unit/IModifierApplierOwner.cs | 4 +- .../Core/Unit/ModifierOwnerExtensions.cs | 51 ---- 26 files changed, 123 insertions(+), 660 deletions(-) delete mode 100644 ModiBuff/ModiBuff/Core/Modifier/Creation/Generation/IModifierApplyCheckGenerator.cs delete mode 100644 ModiBuff/ModiBuff/Core/Modifier/ModifierApplierController.cs diff --git a/ModiBuff/ModiBuff.Benchmarks/BenchmarkModifierRecipes.cs b/ModiBuff/ModiBuff.Benchmarks/BenchmarkModifierRecipes.cs index 69e5555e..1bbe01d4 100644 --- a/ModiBuff/ModiBuff.Benchmarks/BenchmarkModifierRecipes.cs +++ b/ModiBuff/ModiBuff.Benchmarks/BenchmarkModifierRecipes.cs @@ -72,11 +72,9 @@ protected override void SetupRecipes() .Stack(WhenStackEffect.Always); Add("InitDamage_CostMana") - .ApplyCost(CostType.Mana, 5) .Effect(new DamageEffect(5), EffectOn.Init); Add("InitDamage_ApplyCondition_HealthAbove100") - .ApplyCondition(StatType.Health, 100, ComparisonType.GreaterOrEqual) .Effect(new DamageEffect(5), EffectOn.Init); } } diff --git a/ModiBuff/ModiBuff.Examples/BasicConsole/GameController.cs b/ModiBuff/ModiBuff.Examples/BasicConsole/GameController.cs index d0dd882f..6d50dbd3 100644 --- a/ModiBuff/ModiBuff.Examples/BasicConsole/GameController.cs +++ b/ModiBuff/ModiBuff.Examples/BasicConsole/GameController.cs @@ -1,3 +1,4 @@ +using System.Linq; using ModiBuff.Core; namespace ModiBuff.Examples.BasicConsole @@ -47,9 +48,8 @@ public GameController() //But we're adding it as an applier, and not as a normal modifier //This means that instead of it being applier to the player //it will be applied to a unit that the player attacks - _player.ModifierApplierController.TryAddApplier(_idManager.GetId("DoT")!.Value, false, ApplierType.Attack); - _player.ModifierApplierController.TryAddApplier(_idManager.GetId("InitHeal")!.Value, false, - ApplierType.Cast); + _player.AddApplierModifierNew(_idManager.GetId("DoT")!.Value, ApplierType.Attack); + _player.AddApplierModifierNew(_idManager.GetId("InitHeal")!.Value, ApplierType.Cast); //_player.ModifierController.TryAddApplier(_idManager.GetId("DisarmChance"), true, ApplierType.Cast); } @@ -101,12 +101,12 @@ private bool PlayerAction() private bool PlayerCastAction() { //Display all possible modifiers to cast, then when one was chosen, choose the target - var modifierIds = _player.ModifierApplierController.GetApplierCastModifierIds(); + int[] modifierIds = _player.GetApplierCastModifierIds().ToArray(); while (true) { Console.GameMessage("Choose modifier to cast, or c to cancel"); - for (int i = 0; i < modifierIds.Count; i++) + for (int i = 0; i < modifierIds.Length; i++) { var modifierInfo = _recipes.GetModifierInfo(modifierIds[i]); Console.GameMessage($"{i + 1} - {modifierInfo.DisplayName} - {modifierInfo.Description}"); @@ -115,10 +115,10 @@ private bool PlayerCastAction() string castAction = System.Console.ReadLine(); if (int.TryParse(castAction, out int castActionInt)) { - if (castActionInt > 0 && castActionInt <= modifierIds.Count) + if (castActionInt > 0 && castActionInt <= modifierIds.Length) { //TODO: choosing target - _player.TryCast(modifierIds[castActionInt - 1], _player); + _player.TryApply(modifierIds[castActionInt - 1], _player); break; } } diff --git a/ModiBuff/ModiBuff.Examples/BasicConsole/ModifierRecipes.cs b/ModiBuff/ModiBuff.Examples/BasicConsole/ModifierRecipes.cs index e3669b79..c5776135 100644 --- a/ModiBuff/ModiBuff.Examples/BasicConsole/ModifierRecipes.cs +++ b/ModiBuff/ModiBuff.Examples/BasicConsole/ModifierRecipes.cs @@ -47,10 +47,8 @@ protected override void SetupRecipes() .Effect(new DamageEffect(1), EffectOn.Interval); //Here we introduce a new effect, and a chance for the modifier to be applied + //Chance needs to be applied when adding the applier Add("DisarmChance", "Disarm", "Disarms target for 1 second, 20% chance to apply") - //When applying a modifier (through attacking or casting it) - //It will have 20% chance to apply the modifier to the unit - .ApplyChance(0.2f) //Disarms (can't attack) the target unit for 1 second when applied .Effect(new StatusEffectEffect(StatusEffectType.Disarm, 1f), EffectOn.Init) .Remove(1f).Refresh(); diff --git a/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs b/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs index 45189203..969c9f97 100644 --- a/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs +++ b/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs @@ -21,8 +21,6 @@ public sealed class Unit : IModifierOwner, IUpdatable, IDamagable, IAttacker, IH //We simply add modifier ids to it, and it will handle the rest public ModifierController ModifierController { get; } - public ModifierApplierController ModifierApplierController { get; } - //TODO Explain private readonly Dictionary> _modifierAppliers; @@ -50,7 +48,6 @@ public Unit(string name, float health, float damage) //Remember to rent the modifier controllers in the constructor ModifierController = ModifierControllerPool.Instance.Rent(); - ModifierApplierController = ModifierControllerPool.Instance.RentApplier(); _modifierAppliers = new Dictionary> { { ApplierType.Attack, new List<(int, ICheck[])>() }, @@ -68,7 +65,6 @@ public void Update(float deltaTime) //We need to update the modifier controller each frame/tick //To update the modifier timers (interval, duration) ModifierController.Update(deltaTime); - ModifierApplierController.Update(deltaTime); StatusEffectController.Update(deltaTime); } @@ -103,14 +99,71 @@ public float Attack(Unit target) if (!StatusEffectController.HasLegalAction(LegalAction.Act)) return 0; - //This method will try to apply all our applier attack modifiers to the target - this.ApplyAllAttackModifier(target); + foreach ((int id, ICheck[] checks) in _modifierAppliers[ApplierType.Attack]) + { + bool checksPassed = true; + if (checks != null) + foreach (var check in checks) + { + if (!check.Check(this)) + { + checksPassed = false; + break; + } + } + + if (!checksPassed) + continue; + + if (checks != null) + foreach (var check in checks) + check.Use(this); + + target.ModifierController.Add(id, target, this); + } float damageDealt = target.TakeDamage(Damage, this); return damageDealt; } + public bool TryApply(int modifierId, IUnit target) + { + if (!(target is IModifierOwner modifierTarget)) + return false; + if (!StatusEffectController.HasLegalAction(LegalAction.Cast)) + return false; + if (!_modifierAppliers.TryGetValue(ApplierType.Cast, out var appliers)) + return false; + + (int Id, ICheck[] Checks)? applier = null; + for (int i = 0; i < appliers.Count; i++) + { + if (appliers[i].Id == modifierId) + { + applier = appliers[i]; + break; + } + } + + if (applier == null) + return false; + + if (applier.Value.Checks != null) + { + foreach (var check in applier.Value.Checks) + if (!check.Check(this)) + return false; + + for (int i = 0; i < applier.Value.Checks.Length; i++) + applier.Value.Checks[i].Use(this); + } + + modifierTarget.ModifierController.Add(modifierId, modifierTarget, this); + + return true; + } + public float TakeDamage(float damage, IUnit source) { if (IsDead) @@ -167,6 +220,13 @@ public void AddApplierModifierNew(int modifierId, ApplierType applierType, IChec _modifierAppliers[applierType].Add((modifierId, null)); } + public IEnumerable GetApplierCastModifierIds() + { + if (_modifierAppliers.TryGetValue(ApplierType.Cast, out var list)) + foreach ((int id, ICheck[] _) in list) + yield return id; + } + public string GetDebugString() { return $"Unit, health: {Health}/{MaxHealth}, damage: {Damage}"; diff --git a/ModiBuff/ModiBuff.Tests/ApplierTests.cs b/ModiBuff/ModiBuff.Tests/ApplierTests.cs index b5bb5988..3c0f313d 100644 --- a/ModiBuff/ModiBuff.Tests/ApplierTests.cs +++ b/ModiBuff/ModiBuff.Tests/ApplierTests.cs @@ -98,7 +98,6 @@ public void DamageApplier_Interval() public void InitDamageCostMana() { AddRecipe("InitDamage_CostMana") - .ApplyCost(CostType.Mana, 5) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); @@ -238,7 +237,7 @@ public void Cast_AddApplier() { AddRecipe("AddApplier_Effect") .Effect(new ApplierEffect("InitDamage"), EffectOn.Init) - .RemoveApplier(5, ApplierType.Cast, false); + .RemoveApplier(5, ApplierType.Cast); AddRecipe("AddApplier_ApplierEffect") .Effect(new ApplierEffect("AddApplier_Effect", ApplierType.Cast, false), EffectOn.Init); Setup(); diff --git a/ModiBuff/ModiBuff.Tests/ConditionTests.cs b/ModiBuff/ModiBuff.Tests/ConditionTests.cs index 1f117977..7def0a6b 100644 --- a/ModiBuff/ModiBuff.Tests/ConditionTests.cs +++ b/ModiBuff/ModiBuff.Tests/ConditionTests.cs @@ -10,7 +10,6 @@ public sealed class ConditionTests : ModifierTests public void HealthCondition_OnApply_InitDamage() { AddRecipe("InitDamage_ApplyCondition_HealthAbove100") - .ApplyCondition(StatType.Health, 100, ComparisonType.GreaterOrEqual) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); @@ -167,7 +166,6 @@ public void HasStatusEffect_OnApply_InitDamage() AddRecipe("InitDamage_ApplyCondition_FreezeStatusEffect") .Effect(new DamageEffect(5), EffectOn.Init); AddRecipe("InitDamage_ApplyCondition_ActLegalAction") - .ApplyCondition(LegalAction.Act) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); diff --git a/ModiBuff/ModiBuff.Tests/CooldownTests.cs b/ModiBuff/ModiBuff.Tests/CooldownTests.cs index e354dfcc..3d3af26f 100644 --- a/ModiBuff/ModiBuff.Tests/CooldownTests.cs +++ b/ModiBuff/ModiBuff.Tests/CooldownTests.cs @@ -185,7 +185,6 @@ public void InitDamage_ChargesCooldown() public void InitDamage_ChargesCooldownUseWait() { AddRecipe("InitDamage_Cooldown") - .ApplyChargesCooldown(1, 2) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); diff --git a/ModiBuff/ModiBuff.Tests/CostTests.cs b/ModiBuff/ModiBuff.Tests/CostTests.cs index 7f67d858..1202c64f 100644 --- a/ModiBuff/ModiBuff.Tests/CostTests.cs +++ b/ModiBuff/ModiBuff.Tests/CostTests.cs @@ -116,7 +116,6 @@ public void CostHealth_HealSelf() public void CostSixtyPercentHealth_Damage() { AddRecipe("InitDamage_CostSixtyPercentHealth") - .ApplyCostPercent(CostType.Health, 0.6f) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs index 8b3adb30..e6332f30 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs @@ -22,7 +22,6 @@ public sealed class ModifierApplierUnit : IUnit, IModifierApplierOwner, IDamagab public float MaxHealth { get; } public float Damage { get; } - public ModifierApplierController ModifierApplierController { get; } private readonly Dictionary> _modifierAppliers; public ModifierApplierUnit(float health, float damage, UnitType unitType = UnitType.Good) @@ -32,7 +31,6 @@ public ModifierApplierUnit(float health, float damage, UnitType unitType = UnitT MaxHealth = Health = health; Damage = damage; - ModifierApplierController = ModifierControllerPool.Instance.RentApplier(); _modifierAppliers = new Dictionary> { { ApplierType.Attack, new List<(int, ICheck[])>() }, @@ -43,7 +41,30 @@ public ModifierApplierUnit(float health, float damage, UnitType unitType = UnitT public float Attack(IUnit target) { if (target is IModifierOwner modifierOwner) - this.ApplyAllAttackModifier(modifierOwner); + { + foreach ((int id, ICheck[] checks) in _modifierAppliers[ApplierType.Attack]) + { + bool checksPassed = true; + if (checks != null) + foreach (var check in checks) + { + if (!check.Check(this)) + { + checksPassed = false; + break; + } + } + + if (!checksPassed) + continue; + + if (checks != null) + foreach (var check in checks) + check.Use(this); + + modifierOwner.ModifierController.Add(id, target, this); + } + } return ((IDamagable)target).TakeDamage(Damage, this); } diff --git a/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs b/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs index 697558c3..5e3d4420 100644 --- a/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs +++ b/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs @@ -52,14 +52,6 @@ internal static bool ContainsApplier(this IModifierApplierOwner unit, string nam return unit.ModifierApplierController.ContainsApplier(ModifierIdManager.GetIdByName(name).Value); } - internal static bool AddApplierModifier(this IModifierApplierOwner unit, IModifierGenerator generator, - ApplierType applierType) - { - CheckForSetup(unit); - return unit.ModifierApplierController.TryAddApplier(generator.Id, - ((IModifierApplyCheckGenerator)generator).HasApplyChecks, applierType); - } - internal static bool AddEffectApplier(this IModifierApplierOwner unit, string name) { CheckForSetup(unit); @@ -71,11 +63,6 @@ internal static void TryCast(this Unit unit, string name, IModifierOwner target) unit.TryCast(ModifierIdManager.GetIdByName(name).Value, target); } - internal static void TryCast(this IModifierApplierOwner unit, string name, IModifierOwner target) - { - unit.TryCast(ModifierIdManager.GetIdByName(name).Value, target); - } - internal static void TryCastEffect(this IModifierApplierOwner unit, string name, IUnit target) { unit.TryCastEffect(EffectIdManager.GetIdOld(name).Value, target); diff --git a/ModiBuff/ModiBuff.Units/Effects/Actions/CastActionEffect.cs b/ModiBuff/ModiBuff.Units/Effects/Actions/CastActionEffect.cs index ad6ca2b4..7d8661e7 100644 --- a/ModiBuff/ModiBuff.Units/Effects/Actions/CastActionEffect.cs +++ b/ModiBuff/ModiBuff.Units/Effects/Actions/CastActionEffect.cs @@ -41,7 +41,7 @@ public void Effect(IUnit target, IUnit source) return; } - applierSource.TryCast(_modifierId, modifierTarget); + applierSource.TryApply(_modifierId, modifierTarget); } } } \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Units/Recipe/ModifierRecipeExtensions.cs b/ModiBuff/ModiBuff.Units/Recipe/ModifierRecipeExtensions.cs index f39f82db..a8fb2e8f 100644 --- a/ModiBuff/ModiBuff.Units/Recipe/ModifierRecipeExtensions.cs +++ b/ModiBuff/ModiBuff.Units/Recipe/ModifierRecipeExtensions.cs @@ -19,74 +19,6 @@ public static ModifierRecipe CustomStack(this ModifierRecipe recipe, CustomStack return recipe.ModifierAction(ModifierAction.Stack, customStackEffectOn.ToEffectOn()); } - public static ModifierRecipe ApplyCondition(this ModifierRecipe recipe, ConditionType conditionType) - { - return recipe.ApplyCheck(unit => conditionType.CheckConditionType(unit)); - } - - public static ModifierRecipe ApplyCondition(this ModifierRecipe recipe, StatType statType, float statValue, - ComparisonType comparisonType = ComparisonType.GreaterOrEqual) - { - return recipe.ApplyCheck(unit => statType.CheckStatType(unit, comparisonType, statValue)); - } - - public static ModifierRecipe ApplyCondition(this ModifierRecipe recipe, LegalAction legalAction) - { - return recipe.ApplyCheck(unit => legalAction.CheckLegalAction(unit)); - } - - public static ModifierRecipe ApplyCondition(this ModifierRecipe recipe, StatusEffectType statusEffectType) - { - return recipe.ApplyCheck(unit => statusEffectType.CheckStatusEffectType(unit)); - } - - public static ModifierRecipe ApplyCondition(this ModifierRecipe recipe, string modifierName) - { - int? modifierId = recipe.IdManager.GetId(modifierName); - return recipe.ApplyCheck(unit => modifierId.CheckModifierId(unit)); - } - - /// - /// Cooldown set for when we can try to apply the modifier to a target. - /// - public static ModifierRecipe ApplyCooldown(this ModifierRecipe recipe, float cooldown) - { - return recipe.ApplyCheck(new CooldownCheck(cooldown)); - } - - /// - /// Cooldown set for when we can try to apply the modifier to a target, with . - /// - public static ModifierRecipe ApplyChargesCooldown(this ModifierRecipe recipe, float cooldown, int charges) - { - return recipe.ApplyCheck(new ChargesCooldownCheck(cooldown, charges)); - } - - /// - /// When trying to apply a modifier, what should the chance be of it being applied? - /// - public static ModifierRecipe ApplyChance(this ModifierRecipe recipe, float chance) - { - if (chance > 1) - chance /= 100; - if (chance <= 0 || chance > 1) - Logger.LogError("[ModiBuff.Units] Chance must be between 0 and 1"); - return recipe.ApplyCheck(new ChanceCheck(chance)); - } - - /// - /// Cost for when we can try to apply the modifier to a target. - /// - public static ModifierRecipe ApplyCost(this ModifierRecipe recipe, CostType costType, float cost) - { - return recipe.ApplyCheck(new CostCheck(costType, cost)); - } - - public static ModifierRecipe ApplyCostPercent(this ModifierRecipe recipe, CostType costType, float costPercent) - { - return recipe.ApplyCheck(new CostPercentCheck(costType, costPercent)); - } - public static ModifierRecipe EffectCondition(this ModifierRecipe recipe, ConditionType conditionType) { return recipe.EffectCheck(unit => conditionType.CheckConditionType(unit)); diff --git a/ModiBuff/ModiBuff.Units/Unit/Interfaces/StatusEffectModifierOwnerExtensions.cs b/ModiBuff/ModiBuff.Units/Unit/Interfaces/StatusEffectModifierOwnerExtensions.cs index a77d64b0..9d4e6120 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Interfaces/StatusEffectModifierOwnerExtensions.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Interfaces/StatusEffectModifierOwnerExtensions.cs @@ -2,42 +2,6 @@ namespace ModiBuff.Core.Units { public static class StatusEffectModifierOwnerExtensions { - public static bool TryCast(this IStatusEffectModifierOwnerLegalTarget owner, - int modifierId, IModifierOwner target) - { - if (!modifierId.IsLegalTarget((IUnitEntity)target, owner)) - return false; - - if (!owner.StatusEffectController.HasLegalAction(LegalAction.Cast)) - return false; - - if (!owner.CanCastModifier(modifierId)) - return false; - - target.ModifierController.Add(modifierId, target, owner); - return true; - } - - /// - /// Skips the check part for check modifiers, use this ONLY in case you're also using - /// - public static bool TryCastNoChecks( - this IStatusEffectModifierOwnerLegalTarget owner, int modifierId, - IModifierOwner target) - { - if (!modifierId.IsLegalTarget((IUnitEntity)target, owner)) - return false; - - if (!owner.StatusEffectController.HasLegalAction(LegalAction.Cast)) - return false; - - if (!owner.ModifierApplierController.ContainsApplier(modifierId)) - return false; - - target.ModifierController.Add(modifierId, target, owner); - return true; - } - public static bool HasStatusEffectSingle( this ISingleInstanceStatusEffectOwner owner, StatusEffectType statusEffectType) diff --git a/ModiBuff/ModiBuff.Units/Unit/Unit.cs b/ModiBuff/ModiBuff.Units/Unit/Unit.cs index 0efc92a0..bb9ec694 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Unit.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Unit.cs @@ -43,7 +43,6 @@ public partial class Unit : IUpdatable, IModifierOwner, IModifierApplierOwner, I public bool IsDead { get; private set; } public ModifierController ModifierController { get; } - public ModifierApplierController ModifierApplierController { get; } //Note: use one of these, not both public IMultiInstanceStatusEffectController StatusEffectController => @@ -119,7 +118,6 @@ public Unit(float health = 500, float damage = 10, float healValue = 5, float ma _debuffs = new DebuffType[Enum.GetValues(typeof(DebuffType)).Length]; ModifierController = ModifierControllerPool.Instance.Rent(); - ModifierApplierController = ModifierControllerPool.Instance.RentApplier(); _statusEffectController = new MultiInstanceStatusEffectController (this, StatusEffectType.None, _statusEffectAddedEvents, _statusEffectRemovedEvents); _singleInstanceStatusEffectController = new StatusEffectController(); @@ -147,7 +145,6 @@ public void Update(float deltaTime) _statusEffectController.Update(deltaTime); _singleInstanceStatusEffectController.Update(deltaTime); ModifierController.Update(deltaTime); - ModifierApplierController.Update(deltaTime); for (int i = 0; i < _updatableChecks.Count; i++) _updatableChecks[i].Update(deltaTime); @@ -349,6 +346,7 @@ public float Heal(IHealable target) return valueHealed; } + public bool TryApply(int modifierId, IUnit target) => TryCastInternal(modifierId, target); public bool TryCast(int modifierId, IUnit target) => TryCastInternal(modifierId, target); internal bool TryCastNoChecks(int modifierId, IUnit target) => TryCastInternal(modifierId, target, true); @@ -582,7 +580,6 @@ public void ResetState() _singleInstanceStatusEffectController.ResetState(); _durationLessStatusEffectController.ResetState(); ModifierControllerPool.Instance.Return(ModifierController); - ModifierControllerPool.Instance.ReturnApplier(ModifierApplierController); void ClearEvents(params IList[] lists) { @@ -594,9 +591,9 @@ void ClearEvents(params IList[] lists) public SaveData SaveState() { return new SaveData(Id, UnitTag, Health, MaxHealth, Damage, HealValue, Mana, MaxMana, - UnitType, IsDead, ModifierController.SaveState(), ModifierApplierController.SaveState(), - _modifierAppliers.ToDictionary(a => a.Key, a => a.Value.Select(cs => (cs.Id, cs.Checks.Select( - c => (c as IStateCheck)?.SaveState())))), + UnitType, IsDead, ModifierController.SaveState(), + _modifierAppliers.ToDictionary(a => a.Key, + a => a.Value.Select(cs => (cs.Id, cs.Checks.Select(c => (c as IStateCheck)?.SaveState())))), _statusEffectController.SaveState(), _singleInstanceStatusEffectController.SaveState()); } @@ -613,7 +610,6 @@ public void LoadState(SaveData data) UnitType = data.UnitType; IsDead = data.IsDead; ModifierController.LoadState(data.ModifierControllerSaveData, this); - ModifierApplierController.LoadState(data.ModifierApplierControllerSaveData); if (data.Appliers != null) foreach (var loadPair in data.Appliers) { @@ -667,7 +663,6 @@ public readonly struct SaveData public readonly bool IsDead; public readonly ModifierController.SaveData ModifierControllerSaveData; - public readonly ModifierApplierController.SaveData ModifierApplierControllerSaveData; public readonly IReadOnlyDictionary)>>? Appliers; public readonly MultiInstanceStatusEffectController.SaveData MultiInstanceStatusEffectControllerSaveData; public readonly StatusEffectController.SaveData SingleInstanceStatusEffectControllerSaveData; @@ -678,7 +673,6 @@ public readonly struct SaveData public SaveData(int id, UnitTag unitTag, float health, float maxHealth, float damage, float healValue, float mana, float maxMana, UnitType unitType, bool isDead, ModifierController.SaveData modifierControllerSaveData, - ModifierApplierController.SaveData modifierApplierControllerSaveData, IReadOnlyDictionary)>>? appliers, MultiInstanceStatusEffectController.SaveData multiInstanceStatusEffectControllerSaveData, StatusEffectController.SaveData singleInstanceStatusEffectControllerSaveData) @@ -694,7 +688,6 @@ public SaveData(int id, UnitTag unitTag, float health, float maxHealth, float da UnitType = unitType; IsDead = isDead; ModifierControllerSaveData = modifierControllerSaveData; - ModifierApplierControllerSaveData = modifierApplierControllerSaveData; Appliers = appliers; MultiInstanceStatusEffectControllerSaveData = multiInstanceStatusEffectControllerSaveData; SingleInstanceStatusEffectControllerSaveData = singleInstanceStatusEffectControllerSaveData; diff --git a/ModiBuff/ModiBuff/Core/Config.cs b/ModiBuff/ModiBuff/Core/Config.cs index 6ba172be..2e1a4cd0 100644 --- a/ModiBuff/ModiBuff/Core/Config.cs +++ b/ModiBuff/ModiBuff/Core/Config.cs @@ -12,7 +12,6 @@ public static class Config private const int DefaultModifierControllerPoolSize = 256; private const int DefaultMaxModifierControllerPoolSize = 32_768; - private const int DefaultModifierApplierControllerPoolSize = 64; public const int DefaultModifierArraySize = 32; private const int DefaultDispellableSize = 8; @@ -21,11 +20,6 @@ public static class Config private const int DefaultMultiTargetComponentInitialCapacity = 4; - private const int DefaultAttackApplierSize = 4, - DefaultCastApplierSize = 4, - DefaultAttackCheckApplierSize = 4, - DefaultCastCheckApplierSize = 4; - private const int DefaultEffectCastsSize = 4; private const float DefaultDeltaTolerance = 0.001f; @@ -46,7 +40,6 @@ public static class Config public static int ModifierControllerPoolSize = DefaultModifierControllerPoolSize; public static int MaxModifierControllerPoolSize = DefaultMaxModifierControllerPoolSize; - public static int ModifierApplierControllerPoolSize = DefaultModifierApplierControllerPoolSize; public static int ModifierArraySize = DefaultModifierArraySize; public static int DispellableSize = DefaultDispellableSize; @@ -55,11 +48,6 @@ public static class Config public static int MultiTargetComponentInitialCapacity = DefaultMultiTargetComponentInitialCapacity; - public static int AttackApplierSize = DefaultAttackApplierSize; - public static int CastApplierSize = DefaultCastApplierSize; - public static int AttackCheckApplierSize = DefaultAttackCheckApplierSize; - public static int CastCheckApplierSize = DefaultCastCheckApplierSize; - public static int EffectCastsSize = DefaultEffectCastsSize; public static float DeltaTolerance = DefaultDeltaTolerance; @@ -79,7 +67,6 @@ public static void Reset() ModifierControllerPoolSize = DefaultModifierControllerPoolSize; MaxModifierControllerPoolSize = DefaultMaxModifierControllerPoolSize; - ModifierApplierControllerPoolSize = DefaultModifierApplierControllerPoolSize; ModifierArraySize = DefaultModifierArraySize; DispellableSize = DefaultDispellableSize; @@ -88,11 +75,6 @@ public static void Reset() MultiTargetComponentInitialCapacity = DefaultMultiTargetComponentInitialCapacity; - AttackApplierSize = DefaultAttackApplierSize; - CastApplierSize = DefaultCastApplierSize; - AttackCheckApplierSize = DefaultAttackCheckApplierSize; - CastCheckApplierSize = DefaultCastCheckApplierSize; - EffectCastsSize = DefaultEffectCastsSize; DeltaTolerance = DefaultDeltaTolerance; diff --git a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs b/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs index e1190759..ee251583 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs @@ -73,8 +73,6 @@ public void Effect(IUnit target, IUnit source) } modifierApplierOwnerTarget.AddApplierModifierNew(modifierId, _applierType.Value); - modifierApplierOwnerTarget.ModifierApplierController.TryAddApplier(modifierId, _hasApplyChecks, - _applierType.Value); break; default: throw new ArgumentOutOfRangeException(); diff --git a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/RemoveEffect.cs b/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/RemoveEffect.cs index 660a58d1..6014ad76 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/RemoveEffect.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/RemoveEffect.cs @@ -4,7 +4,6 @@ public sealed class RemoveEffect : IModifierGenIdOwner, IEffect, IStackEffect, I IShallowClone { private readonly ApplierType? _applierType; - private readonly bool _hasApplyChecks; private IRevertEffect[]? _revertibleEffects; private int _id; private int? _genId; @@ -15,11 +14,10 @@ public RemoveEffect() internal RemoveEffect(int id) => _id = id; - internal RemoveEffect(int id, ApplierType? applierType = null, bool hasApplyChecks = false) + internal RemoveEffect(int id, ApplierType? applierType = null) { _id = id; _applierType = applierType; - _hasApplyChecks = hasApplyChecks; } /// @@ -27,17 +25,16 @@ internal RemoveEffect(int id, ApplierType? applierType = null, bool hasApplyChec /// public static RemoveEffect Create(int id, int? genId, params IRevertEffect[] revertibleEffects) { - var effect = new RemoveEffect(id, genId, null, false); + var effect = new RemoveEffect(id, genId, null); effect.SetRevertibleEffects(revertibleEffects); return effect; } - private RemoveEffect(int id, int? genId, ApplierType? applierType, bool hasApplyChecks) + private RemoveEffect(int id, int? genId, ApplierType? applierType) { _id = id; _genId = genId; _applierType = applierType; - _hasApplyChecks = hasApplyChecks; } public void SetModifierId(int id) => _id = id; @@ -61,8 +58,8 @@ public void Effect(IUnit target, IUnit source) if (_applierType != null) { - ((IModifierApplierOwner)target).ModifierApplierController.RemoveApplier(_id /*, _genId*/, - _applierType.Value, _hasApplyChecks); + //TODO + //((IModifierApplierOwner)target).RemoveApplier(_id /*, _genId*/, _applierType.Value); //return; } @@ -71,7 +68,7 @@ public void Effect(IUnit target, IUnit source) public void StackEffect(int stacks, IUnit target, IUnit source) => Effect(target, source); - public IEffect ShallowClone() => new RemoveEffect(_id, _genId, _applierType, _hasApplyChecks); + public IEffect ShallowClone() => new RemoveEffect(_id, _genId, _applierType); object IShallowClone.ShallowClone() => ShallowClone(); } } \ No newline at end of file diff --git a/ModiBuff/ModiBuff/Core/Modifier/Creation/Generation/IModifierApplyCheckGenerator.cs b/ModiBuff/ModiBuff/Core/Modifier/Creation/Generation/IModifierApplyCheckGenerator.cs deleted file mode 100644 index 3fe06011..00000000 --- a/ModiBuff/ModiBuff/Core/Modifier/Creation/Generation/IModifierApplyCheckGenerator.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ModiBuff.Core -{ - public interface IModifierApplyCheckGenerator : IModifierGenerator - { - bool HasApplyChecks { get; } - - ModifierCheck CreateApplyCheck(); - } -} \ No newline at end of file diff --git a/ModiBuff/ModiBuff/Core/Modifier/Creation/Generation/ModifierGenerator.cs b/ModiBuff/ModiBuff/Core/Modifier/Creation/Generation/ModifierGenerator.cs index bfe5ad41..fae0d670 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Creation/Generation/ModifierGenerator.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Creation/Generation/ModifierGenerator.cs @@ -3,14 +3,12 @@ namespace ModiBuff.Core { - public sealed class ModifierGenerator : IModifierGenerator, IModifierApplyCheckGenerator + public sealed class ModifierGenerator : IModifierGenerator { public int Id { get; } public int GenId { get; private set; } public string Name { get; } - public bool HasApplyChecks { get; } - private readonly bool _hasEffectChecks; private readonly bool _isAura; @@ -32,17 +30,6 @@ public sealed class ModifierGenerator : IModifierGenerator, IModifierApplyCheckG private readonly ModifierEffectsCreator _modifierEffectsCreator; - private readonly Func[]? _applyFuncChecks; - private readonly List _updatableApplyChecksList; - private readonly List _noUnitApplyChecksList; - private readonly List _unitApplyChecksList; - private readonly List _usableApplyChecksList; - private readonly IUpdatableCheck[] _updatableApplyChecks; - private readonly INoUnitCheck[] _noUnitApplyChecks; - private readonly IUnitCheck[] _unitApplyChecks; - private readonly IUsableCheck[] _usableApplyChecks; - private readonly IStateCheck[] _stateApplyChecks; - private readonly Func[]? _effectFuncChecks; private readonly List _updatableEffectChecksList; private readonly List _noUnitEffectChecksList; @@ -59,7 +46,6 @@ public ModifierGenerator(in ModifierRecipeData data) Id = data.Id; Name = data.Name; - HasApplyChecks = data.HasApplyChecks; _hasEffectChecks = data.HasEffectChecks; _isAura = data.IsAura; @@ -83,14 +69,6 @@ public ModifierGenerator(in ModifierRecipeData data) data.DispelRegisterWrapper, data.CallbackUnitRegisterWrappers, data.CallbackEffectRegisterWrappers, data.CallbackEffectUnitsRegisterWrappers); - if (HasApplyChecks) - { - _applyFuncChecks = data.ApplyFuncCheckList?.ToArray(); - SetupChecks(data.ApplyCheckList, out _updatableApplyChecksList, out _noUnitApplyChecksList, - out _unitApplyChecksList, out _usableApplyChecksList, out _updatableApplyChecks, - out _noUnitApplyChecks, out _unitApplyChecks, out _usableApplyChecks, out _stateApplyChecks); - } - if (_hasEffectChecks) { _effectFuncChecks = data.EffectFuncCheckList?.ToArray(); @@ -184,13 +162,6 @@ Modifier IModifierGenerator.Create() effectCheck, targetComponent, effects.SetDataEffects, effects.EffectStateInfo, effects.EffectSaveState); } - ModifierCheck IModifierApplyCheckGenerator.CreateApplyCheck() - { - return CreateCheck(_stateApplyChecks, _applyFuncChecks, _updatableApplyChecks, - _noUnitApplyChecks, _unitApplyChecks, _usableApplyChecks, _updatableApplyChecksList, - _noUnitApplyChecksList, _unitApplyChecksList, _usableApplyChecksList); - } - private ModifierCheck CreateCheck(IStateCheck[] stateChecks, Func[] funcChecks, IUpdatableCheck[] updatableChecks, INoUnitCheck[] noUnitChecks, IUnitCheck[] unitChecks, IUsableCheck[] usableChecks, List updatableChecksList, List noUnitChecksList, diff --git a/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipe.cs b/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipe.cs index 1e7568fc..38644eeb 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipe.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipe.cs @@ -44,10 +44,6 @@ public sealed partial class ModifierRecipe : IModifierRecipe, IEquatable? _applyCheckList; - private List>? _applyFuncCheckList; - private bool _hasEffectChecks; private List? _effectCheckList; private List>? _effectFuncCheckList; @@ -138,24 +134,6 @@ public ModifierRecipe RemoveTag(TagType tag) return this; } - //---ApplyChecks--- - - public ModifierRecipe ApplyCheck(Func check) - { - _applyFuncCheckList ??= new List>(); - _applyFuncCheckList.Add(check); - _hasApplyChecks = true; - return this; - } - - public ModifierRecipe ApplyCheck(ICheck check) - { - _applyCheckList ??= new List(); - _applyCheckList.Add(check); - _hasApplyChecks = true; - return this; - } - //---EffectChecks--- public ModifierRecipe EffectCheck(Func check) @@ -213,11 +191,10 @@ public ModifierRecipe Remove(float duration) /// How many seconds should pass before the modifier gets removed. /// /// OVERWRITES all previous remove effects. - public ModifierRecipe RemoveApplier(float duration, ApplierType applierType, bool hasApplyChecks) + public ModifierRecipe RemoveApplier(float duration, ApplierType applierType) { Duration(duration); - _removeEffectWrapper = - new RemoveEffectWrapper(new RemoveEffect(Id, applierType, hasApplyChecks), EffectOn.Duration); + _removeEffectWrapper = new RemoveEffectWrapper(new RemoveEffect(Id, applierType), EffectOn.Duration); return this; } @@ -559,9 +536,9 @@ public IModifierGenerator CreateModifierGenerator() var data = new ModifierRecipeData(Id, Name, _effectWrappers, finalRemoveEffectWrapper, _dispelRegisterWrapper, _callbackUnitRegisterWrappers.ToArray(), _callbackEffectRegisterWrappers.ToArray(), _callbackEffectUnitsRegisterWrappers.ToArray(), - _hasApplyChecks, _applyCheckList, _hasEffectChecks, _effectCheckList, _applyFuncCheckList, - _effectFuncCheckList, _isAura, _tag, _interval, _duration, _refreshDuration, _refreshInterval, - _whenStackEffect, _maxStacks, _everyXStacks, _singleStackTime, _independentStackTime); + _hasEffectChecks, _effectCheckList, _effectFuncCheckList, _isAura, _tag, _interval, _duration, + _refreshDuration, _refreshInterval, _whenStackEffect, _maxStacks, _everyXStacks, _singleStackTime, + _independentStackTime); return new ModifierGenerator(in data); } diff --git a/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipeData.cs b/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipeData.cs index 66996ce3..d61141a9 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipeData.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipeData.cs @@ -13,11 +13,8 @@ public readonly struct ModifierRecipeData public readonly EffectWrapper[] CallbackUnitRegisterWrappers; public readonly EffectWrapper[] CallbackEffectRegisterWrappers; public readonly EffectWrapper[] CallbackEffectUnitsRegisterWrappers; - public readonly bool HasApplyChecks; - public readonly List? ApplyCheckList; public readonly bool HasEffectChecks; public readonly List? EffectCheckList; - public readonly List>? ApplyFuncCheckList; public readonly List>? EffectFuncCheckList; public readonly bool IsAura; public readonly TagType Tag; @@ -34,11 +31,10 @@ public readonly struct ModifierRecipeData public ModifierRecipeData(int id, string name, List effectWrappers, EffectWrapper? removeEffectWrapper, EffectWrapper? dispelRegisterWrapper, EffectWrapper[] callbackUnitRegisterWrappers, EffectWrapper[] callbackEffectRegisterWrappers, - EffectWrapper[] callbackEffectUnitsRegisterWrappers, bool hasApplyChecks, List? applyCheckList, - bool hasEffectChecks, List? effectCheckList, List>? applyFuncCheckList, - List>? effectFuncCheckList, bool isAura, TagType tag, float interval, - float duration, bool refreshDuration, bool refreshInterval, WhenStackEffect? whenStackEffect, - int? maxStacks, int? everyXStacks, float? singleStackTime, float? independentStackTime) + EffectWrapper[] callbackEffectUnitsRegisterWrappers, bool hasEffectChecks, List? effectCheckList, + List>? effectFuncCheckList, bool isAura, TagType tag, float interval, float duration, + bool refreshDuration, bool refreshInterval, WhenStackEffect? whenStackEffect, int? maxStacks, + int? everyXStacks, float? singleStackTime, float? independentStackTime) { Id = id; Name = name; @@ -48,11 +44,8 @@ public ModifierRecipeData(int id, string name, List effectWrapper CallbackUnitRegisterWrappers = callbackUnitRegisterWrappers; CallbackEffectRegisterWrappers = callbackEffectRegisterWrappers; CallbackEffectUnitsRegisterWrappers = callbackEffectUnitsRegisterWrappers; - HasApplyChecks = hasApplyChecks; - ApplyCheckList = applyCheckList; HasEffectChecks = hasEffectChecks; EffectCheckList = effectCheckList; - ApplyFuncCheckList = applyFuncCheckList; EffectFuncCheckList = effectFuncCheckList; IsAura = isAura; Tag = tag; diff --git a/ModiBuff/ModiBuff/Core/Modifier/ModifierApplierController.cs b/ModiBuff/ModiBuff/Core/Modifier/ModifierApplierController.cs deleted file mode 100644 index 18d9c0f3..00000000 --- a/ModiBuff/ModiBuff/Core/Modifier/ModifierApplierController.cs +++ /dev/null @@ -1,238 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace ModiBuff.Core -{ - public sealed class ModifierApplierController - { - private readonly List _modifierAttackAppliers; - - //TODO Will there be cast modifier without any appliers? - private readonly List _modifierCastAppliers; - - private readonly Dictionary _modifierCastChecksAppliers; - private readonly Dictionary _modifierAttackChecksAppliers; - - private readonly List _effectCasts; - - public ModifierApplierController() - { - _modifierAttackAppliers = new List(Config.AttackApplierSize); - _modifierCastAppliers = new List(Config.CastApplierSize); - _modifierCastChecksAppliers = new Dictionary(Config.CastCheckApplierSize); - _modifierAttackChecksAppliers = new Dictionary(Config.AttackCheckApplierSize); - - _effectCasts = new List(Config.EffectCastsSize); - } - - public void Update(float delta) - { - foreach (var check in _modifierCastChecksAppliers.Values) - check.Update(delta); - - foreach (var check in _modifierAttackChecksAppliers.Values) - check.Update(delta); - } - - public ICollection GetApplierCastCheckModifiers() => _modifierCastChecksAppliers.Values; - public ICollection GetApplierAttackCheckModifiers() => _modifierAttackChecksAppliers.Values; - - public IReadOnlyList GetApplierAttackModifierIds() => _modifierAttackAppliers; - public IReadOnlyList GetApplierCastModifierIds() => _modifierCastAppliers; - - /// - /// Only triggers the check, does not trigger the modifiers effect. Used when modifiers - /// - internal bool TryCastCheck(int id, IModifierApplierOwner owner) - { - return _modifierCastChecksAppliers.TryGetValue(id, out var check) && check.CheckUse(owner); - } - - /// - /// Checks if we can cast the modifier, triggers the check if it exists - /// - internal bool CanCastModifier(int id, IModifierApplierOwner owner) - { - if (_modifierCastAppliers.Contains(id)) - return true; - - return _modifierCastChecksAppliers.TryGetValue(id, out var check) && check.CheckUse(owner); - } - - public bool CanCastEffect(int id) => _effectCasts.Contains(id); - - internal bool CanUseAttackModifier(int id, IModifierApplierOwner owner) - { - if (_modifierAttackAppliers.Contains(id)) - return true; - - return _modifierAttackChecksAppliers.TryGetValue(id, out var check) && check.CheckUse(owner); - } - - public bool TryAddApplier(int id, bool hasApplyChecks, ApplierType applierType) - { - switch (applierType) - { - case ApplierType.Cast when hasApplyChecks: - { - if (_modifierCastChecksAppliers.ContainsKey(id)) - { - Logger.LogWarning("[ModiBuff] Tried to add a duplicate cast check applier, id: " + id); - return false; - } - - _modifierCastChecksAppliers.Add(id, ModifierPool.Instance!.RentModifierCheck(id)); - return true; - } - case ApplierType.Cast: - { - if (_modifierCastAppliers.Contains(id)) - { - Logger.LogWarning("[ModiBuff] Tried to add a duplicate cast applier, id: " + id); - return false; - } - - _modifierCastAppliers.Add(id); - return true; - } - case ApplierType.Attack when hasApplyChecks: - { - if (_modifierAttackChecksAppliers.ContainsKey(id)) - { - Logger.LogWarning("[ModiBuff] Tried to add a duplicate attack check applier, id: " + id); - return false; - } - - _modifierAttackChecksAppliers.Add(id, ModifierPool.Instance!.RentModifierCheck(id)); - return true; - } - case ApplierType.Attack: - { - if (_modifierAttackAppliers.Contains(id)) - { - Logger.LogWarning("[ModiBuff] Tried to add a duplicate attack applier, id: " + id); - return false; - } - - _modifierAttackAppliers.Add(id); - return true; - } - default: -#if DEBUG && !MODIBUFF_PROFILE - Logger.LogError("[ModiBuff] Unknown applier type: " + applierType); -#endif - return false; - } - } - - public bool TryAddEffectApplier(int id) - { - if (_effectCasts.Contains(id)) - { - Logger.LogWarning("[ModiBuff] Tried to add a duplicate effect applier, id: " + id); - return false; - } - - _effectCasts.Add(id); - return true; - } - - public bool ContainsApplier(int id) => - _modifierCastAppliers.Contains(id) || _modifierCastChecksAppliers.ContainsKey(id); - - public void RemoveApplier(int id, ApplierType applierType, bool hasApplyChecks) - { - switch (applierType) - { - case ApplierType.Cast when hasApplyChecks: - _modifierCastChecksAppliers.Remove(id); - return; - case ApplierType.Cast: - _modifierCastAppliers.Remove(id); - return; - case ApplierType.Attack when hasApplyChecks: - _modifierAttackChecksAppliers.Remove(id); - return; - case ApplierType.Attack: - _modifierAttackAppliers.Remove(id); - return; - } - } - - /// - /// Returns all modifiers back to the pool - /// - public void Clear() - { - foreach (var check in _modifierCastChecksAppliers.Values) - ModifierPool.Instance!.ReturnCheck(check); - - foreach (var check in _modifierAttackChecksAppliers.Values) - ModifierPool.Instance!.ReturnCheck(check); - - _modifierAttackAppliers.Clear(); - _modifierCastAppliers.Clear(); - _modifierCastChecksAppliers.Clear(); - _modifierAttackChecksAppliers.Clear(); - _effectCasts.Clear(); - } - - public SaveData SaveState() - { - return new SaveData(_modifierAttackAppliers.ToArray(), _modifierCastAppliers.ToArray(), - _modifierCastChecksAppliers.ToDictionary(pair => pair.Key, pair => pair.Value.SaveState()), - _modifierAttackChecksAppliers.ToDictionary(pair => pair.Key, pair => pair.Value.SaveState()), - _effectCasts.ToArray()); - } - - public void LoadState(SaveData saveData) - { - for (int i = 0; i < saveData.ModifierAttackAppliers.Count; i++) - _modifierAttackAppliers.Add(ModifierIdManager.GetNewId(saveData.ModifierAttackAppliers[i])!.Value); - for (int i = 0; i < saveData.ModifierCastAppliers.Count; i++) - _modifierCastAppliers.Add(ModifierIdManager.GetNewId(saveData.ModifierCastAppliers[i])!.Value); - foreach (var kvp in saveData.ModifierCastChecksAppliers) - { - int newId = ModifierIdManager.GetNewId(kvp.Key)!.Value; - var check = ModifierPool.Instance!.RentModifierCheck(newId); - check.LoadState(kvp.Value); - _modifierCastChecksAppliers.Add(newId, check); - } - - foreach (var kvp in saveData.ModifierAttackChecksAppliers) - { - int newId = ModifierIdManager.GetNewId(kvp.Key)!.Value; - var check = ModifierPool.Instance!.RentModifierCheck(newId); - check.LoadState(kvp.Value); - _modifierAttackChecksAppliers.Add(newId, check); - } - - for (int i = 0; i < saveData.EffectCasts.Count; i++) - _effectCasts.Add(EffectIdManager.GetNewId(saveData.EffectCasts[i])!.Value); - } - - public readonly struct SaveData - { - public readonly IReadOnlyList ModifierAttackAppliers; - public readonly IReadOnlyList ModifierCastAppliers; - public readonly IReadOnlyDictionary ModifierCastChecksAppliers; - public readonly IReadOnlyDictionary ModifierAttackChecksAppliers; - public readonly IReadOnlyList EffectCasts; - -#if MODIBUFF_SYSTEM_TEXT_JSON - [System.Text.Json.Serialization.JsonConstructor] -#endif - public SaveData(IReadOnlyList modifierAttackAppliers, IReadOnlyList modifierCastAppliers, - IReadOnlyDictionary modifierCastChecksAppliers, - IReadOnlyDictionary modifierAttackChecksAppliers, - IReadOnlyList effectCasts) - { - ModifierAttackAppliers = modifierAttackAppliers; - ModifierCastAppliers = modifierCastAppliers; - ModifierCastChecksAppliers = modifierCastChecksAppliers; - ModifierAttackChecksAppliers = modifierAttackChecksAppliers; - EffectCasts = effectCasts; - } - } - } -} \ No newline at end of file diff --git a/ModiBuff/ModiBuff/Core/Pool/ModifierControllerPool.cs b/ModiBuff/ModiBuff/Core/Pool/ModifierControllerPool.cs index 916182e3..2e149ab1 100644 --- a/ModiBuff/ModiBuff/Core/Pool/ModifierControllerPool.cs +++ b/ModiBuff/ModiBuff/Core/Pool/ModifierControllerPool.cs @@ -11,9 +11,6 @@ public sealed class ModifierControllerPool private ModifierController[] _pool; private int _poolTop; - private ModifierApplierController[] _applierPool; - private int _applierPoolTop; - public ModifierControllerPool() { if (Instance != null) @@ -26,12 +23,6 @@ public ModifierControllerPool() for (int i = 0; i < initialSize; i++) _pool[i] = new ModifierController(); _poolTop = initialSize; - - int applierInitialSize = Math.Max(Config.ModifierApplierControllerPoolSize, 1); - _applierPool = new ModifierApplierController[applierInitialSize]; - for (int i = 0; i < applierInitialSize; i++) - _applierPool[i] = new ModifierApplierController(); - _applierPoolTop = applierInitialSize; } public ModifierController Rent() @@ -42,14 +33,6 @@ public ModifierController Rent() return _pool[--_poolTop]; } - public ModifierApplierController RentApplier() - { - if (_applierPoolTop == 0) - AllocateApplierDouble(); - - return _applierPool[--_applierPoolTop]; - } - public void Return(ModifierController modifierController) { modifierController.Clear(); @@ -60,16 +43,6 @@ public void Return(ModifierController modifierController) _pool[_poolTop++] = modifierController; } - public void ReturnApplier(ModifierApplierController modifierApplierController) - { - modifierApplierController.Clear(); - - if (_applierPoolTop == _applierPool.Length) - Array.Resize(ref _applierPool, _applierPool.Length << 1); - - _applierPool[_applierPoolTop++] = modifierApplierController; - } - private void AllocateDouble() { if (_poolTop == _pool.Length) @@ -83,25 +56,10 @@ private void AllocateDouble() throw new Exception($"ModifierControllerPool reached max size of {MaxPoolSize}"); } - private void AllocateApplierDouble() - { - if (_applierPoolTop == _applierPool.Length) - Array.Resize(ref _applierPool, _applierPool.Length << 1); - - for (int i = _applierPoolTop; i < _applierPool.Length; i++) - _applierPool[i] = new ModifierApplierController(); - _applierPoolTop = _applierPool.Length; - - if (_applierPoolTop > MaxPoolSize) - throw new Exception($"ModifierApplierControllerPool reached max size of {MaxPoolSize}"); - } - internal void Clear() { Array.Clear(_pool, 0, _pool.Length); _poolTop = 0; - Array.Clear(_applierPool, 0, _applierPool.Length); - _applierPoolTop = 0; } public void Reset() diff --git a/ModiBuff/ModiBuff/Core/Pool/ModifierPool.cs b/ModiBuff/ModiBuff/Core/Pool/ModifierPool.cs index 4931c070..5de1e360 100644 --- a/ModiBuff/ModiBuff/Core/Pool/ModifierPool.cs +++ b/ModiBuff/ModiBuff/Core/Pool/ModifierPool.cs @@ -10,10 +10,7 @@ public sealed class ModifierPool private readonly Modifier[][] _pools; private readonly int[] _poolTops; - private readonly ModifierCheck[][] _checkPools; - private readonly int[] _checkPoolTops; private readonly IModifierGenerator[] _generators; - private readonly IModifierApplyCheckGenerator[] _applyCheckRecipes; #if DEBUG && !MODIBUFF_PROFILE private readonly int[] _maxModifiersCreated; @@ -34,10 +31,7 @@ public ModifierPool(IModifierGenerator[] generators) _pools = new Modifier[generators.Length][]; _poolTops = new int[generators.Length]; - _checkPools = new ModifierCheck[generators.Length][]; - _checkPoolTops = new int[generators.Length]; _generators = new IModifierGenerator[generators.Length]; - _applyCheckRecipes = new IModifierApplyCheckGenerator[generators.Length]; #if DEBUG && !MODIBUFF_PROFILE _maxModifiersCreated = new int[generators.Length]; @@ -55,17 +49,6 @@ public ModifierPool(IModifierGenerator[] generators) _pools[generator.Id] = new Modifier[initialSize]; _generators[generator.Id] = generator; - if (generator is IModifierApplyCheckGenerator applyCheckRecipe) - { - if (Config.ModifierAllocationsCount.TryGetValue(applyCheckRecipe.Name, out int applyCount)) - _checkPools[generator.Id] = new ModifierCheck[applyCount]; - else - _checkPools[generator.Id] = new ModifierCheck[initialSize]; - _applyCheckRecipes[generator.Id] = applyCheckRecipe; - - AllocateDoubleChecks(generator.Id); - } - AllocateDouble(generator.Id); } @@ -104,14 +87,6 @@ internal void Resize(int id, int size) _pools[id] = pool; } - internal void ResizeChecks(int id, int size) - { - var pool = _checkPools[id]; - - Array.Resize(ref pool, size); - _checkPools[id] = pool; - } - internal void Allocate(int id, int count) { var generator = _generators[id]; @@ -160,23 +135,6 @@ internal void AllocateDouble(int id) #endif } - internal void AllocateDoubleChecks(int id) - { - var recipe = _applyCheckRecipes[id]; - int poolLength = _checkPools[id].Length; //Don't cache pool array, it can be resized. - - if (_checkPoolTops[id] == poolLength) - ResizeChecks(id, poolLength << 1); - - if (recipe.HasApplyChecks) - for (int i = 0; i < poolLength; i++) - _checkPools[id][_checkPoolTops[id]++] = recipe.CreateApplyCheck(); - - if (_checkPoolTops[id] > MaxPoolSize) - throw new Exception( - $"Modifier check pool for {recipe.Name} is over the max pool size of {MaxPoolSize}."); - } - public Modifier Rent(int id) { if (_poolTops[id] == 0) @@ -185,14 +143,6 @@ public Modifier Rent(int id) return _pools[id][--_poolTops[id]]; } - public ModifierCheck RentModifierCheck(int id) - { - if (_checkPoolTops[id] == 0) - AllocateDoubleChecks(id); - - return _checkPools[id][--_checkPoolTops[id]]; - } - public void Return(Modifier modifier) { modifier.ResetState(); @@ -205,16 +155,6 @@ public void Return(Modifier modifier) _pools[id][_poolTops[id]++] = modifier; } - public void ReturnCheck(ModifierCheck check) - { - check.ResetState(); - - if (_checkPoolTops[check.Id] == _checkPools[check.Id].Length) - ResizeChecks(check.Id, _checkPools[check.Id].Length << 1); - - _checkPools[check.Id][_checkPoolTops[check.Id]++] = check; - } - #if DEBUG && !MODIBUFF_PROFILE public void PrintMaxModifiersCreated() { @@ -233,11 +173,6 @@ internal void Clear() { Array.Clear(_pools[i], 0, _pools[i].Length); _poolTops[i] = 0; - if (_checkPools[i] != null) - { - Array.Clear(_checkPools[i], 0, _checkPools[i].Length); - _checkPoolTops[i] = 0; - } } } diff --git a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs index 2766773b..7514c1a6 100644 --- a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs +++ b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs @@ -2,7 +2,9 @@ namespace ModiBuff.Core { public interface IModifierApplierOwner : IUnit { - ModifierApplierController ModifierApplierController { get; } + bool TryApply(int modifierId, IUnit target); + void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[]? checks = null); + //void RemoveApplier(int id, ApplierType applierType); } } \ No newline at end of file diff --git a/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs b/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs index ac482858..f7449270 100644 --- a/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs +++ b/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs @@ -12,17 +12,6 @@ public static void Dispel(this IModifierOwner owner, DispelType dispelType, IUni owner.ModifierController.Dispel(dispelType, owner, source); } - //TODO Remove - public static void TryCast(this IModifierApplierOwner owner, int modifierId, IModifierOwner target) - { - if (owner.CanCastModifier(modifierId)) - target.ModifierController.Add(modifierId, target, owner); -#if DEBUG - else - Logger.Log($"[ModiBuff] Can't cast modifier id {modifierId} from {owner} to {target}"); -#endif - } - //TODO Remove? public static void TryCastEffect(this IModifierApplierOwner owner, int effectId, IUnit target) { @@ -33,45 +22,5 @@ public static void TryCastEffect(this IModifierApplierOwner owner, int effectId, Logger.Log($"[ModiBuff] Can't cast effect id {effectId} from {owner} to {target}"); #endif } - - public static void ApplyAllAttackModifier(this IModifierApplierOwner owner, IModifierOwner target) - { - owner.ApplyAttackNonCheckModifiers(target); - owner.TryApplyAttackCheckModifiers(target); - } - - public static void ApplyAttackNonCheckModifiers(this IModifierApplierOwner owner, IModifierOwner target) - { - foreach (int id in owner.ModifierApplierController.GetApplierAttackModifierIds()) - target.ModifierController.Add(id, target, owner); - } - - public static void TryApplyAttackCheckModifiers(this IModifierApplierOwner owner, IModifierOwner target) - { - foreach (var check in owner.ModifierApplierController.GetApplierAttackCheckModifiers()) - if (check.CheckUse(owner)) - target.ModifierController.Add(check.Id, target, owner); - } - - /// - /// Only triggers the check, does not trigger the modifiers effect. Used when modifiers - /// - public static bool TryCastCheck(this IModifierApplierOwner owner, int id) - { - return owner.ModifierApplierController.TryCastCheck(id, owner); - } - - /// - /// Checks if we can cast the modifier, triggers the check if it exists - /// - public static bool CanCastModifier(this IModifierApplierOwner owner, int id) - { - return owner.ModifierApplierController.CanCastModifier(id, owner); - } - - public static bool CanUseAttackModifier(this IModifierApplierOwner owner, int id) - { - return owner.ModifierApplierController.CanUseAttackModifier(id, owner); - } } } \ No newline at end of file From f2f5c59acbe5195a1897333be61d556c884bca6f Mon Sep 17 00:00:00 2001 From: chillu Date: Sun, 31 Aug 2025 21:34:08 +0200 Subject: [PATCH 09/11] feat: all tests ported --- .../BasicConsole/UIExtensions.cs | 14 +++--- .../ModiBuff.Examples/BasicConsole/Unit.cs | 5 +++ ModiBuff/ModiBuff.Tests/ApplierTests.cs | 2 +- ModiBuff/ModiBuff.Tests/CastTests.cs | 4 +- .../CentralizedCustomLogicTests.cs | 14 +++--- ModiBuff/ModiBuff.Tests/ModifierTests.cs | 1 - .../PartialUnitTests/AttackUnitTests.cs | 3 -- .../PartialUnitTests/DamagableUnitTests.cs | 10 +++-- .../ModifierApplierUnitTests.cs | 43 +++++++++++++++++++ .../PartialUnitTests/NoModifierUnitTests.cs | 12 ------ ModiBuff/ModiBuff.Tests/SaveLoadTests.cs | 25 ----------- ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs | 14 +++--- ModiBuff/ModiBuff.Units/Unit/Unit.cs | 5 +++ .../Core/Unit/IModifierApplierOwner.cs | 2 + .../Core/Unit/ModifierOwnerExtensions.cs | 11 ----- 15 files changed, 84 insertions(+), 81 deletions(-) diff --git a/ModiBuff/ModiBuff.Examples/BasicConsole/UIExtensions.cs b/ModiBuff/ModiBuff.Examples/BasicConsole/UIExtensions.cs index 2b92cbee..6c2523ac 100644 --- a/ModiBuff/ModiBuff.Examples/BasicConsole/UIExtensions.cs +++ b/ModiBuff/ModiBuff.Examples/BasicConsole/UIExtensions.cs @@ -1,3 +1,4 @@ +using System.Linq; using ModiBuff.Core; using ModiBuff.Core.Units; using ModiBuff.Core.Units.Interfaces.NonGeneric; @@ -10,7 +11,6 @@ public static class UIExtensions public static void PrintStateAndModifiers(this IModifierApplierOwner owner, IModifierRecipes modifierRecipes) { var modifierController = ((IModifierOwner)owner).ModifierController; - var modifierApplierController = owner.ModifierApplierController; //Stats, ApplyModifiers, Normal modifiers. var damagable = (IDamagable)owner; var attacker = (IAttacker)owner; @@ -18,22 +18,22 @@ public static void PrintStateAndModifiers(this IModifierApplierOwner owner, IMod $"{attacker.Damage} Damage"); //Appliers //Name, description, checks, (states, like cooldown) - var applierAttackIds = modifierApplierController.GetApplierAttackModifierIds(); - if (applierAttackIds != null && applierAttackIds.Count > 0) + var applierAttackIds = ((Unit)owner).GetApplierCastModifierIds().ToArray(); + if (applierAttackIds.Length > 0) { Console.GameMessage("Player attack appliers:"); - for (int i = 0; i < applierAttackIds.Count; i++) + for (int i = 0; i < applierAttackIds.Length; i++) { var modifierInfo = modifierRecipes.GetModifierInfo(applierAttackIds[i]); Console.GameMessage($"{i + 1} - {modifierInfo.DisplayName} - {modifierInfo.Description}"); } } - var applierCastIds = modifierApplierController.GetApplierCastModifierIds(); - if (applierCastIds != null && applierCastIds.Count > 0) + var applierCastIds = ((Unit)owner).GetApplierCastModifierIds().ToArray(); + if (applierCastIds.Length > 0) { Console.GameMessage("Player cast appliers:"); - for (int i = 0; i < applierCastIds.Count; i++) + for (int i = 0; i < applierCastIds.Length; i++) { var modifierInfo = modifierRecipes.GetModifierInfo(applierCastIds[i]); Console.GameMessage($"{i + 1} - {modifierInfo.DisplayName} - {modifierInfo.Description}"); diff --git a/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs b/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs index 969c9f97..881f8cbf 100644 --- a/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs +++ b/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs @@ -202,6 +202,11 @@ public float Heal(float heal, IUnit source) return Health - originalHealth; } + public bool ContainsApplier(int modifierId, ApplierType applierType) + { + return _modifierAppliers.TryGetValue(applierType, out var list) && list.Exists(c => c.Id == modifierId); + } + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) { if (checks?.Length > 0) diff --git a/ModiBuff/ModiBuff.Tests/ApplierTests.cs b/ModiBuff/ModiBuff.Tests/ApplierTests.cs index 3c0f313d..464612e7 100644 --- a/ModiBuff/ModiBuff.Tests/ApplierTests.cs +++ b/ModiBuff/ModiBuff.Tests/ApplierTests.cs @@ -250,7 +250,7 @@ public void Cast_AddApplier() Assert.AreEqual(EnemyHealth - 5, Enemy.Health); Unit.Update(5); - Assert.False(Unit.ContainsApplier("AddApplier_Effect")); + Assert.False(Unit.ContainsApplier("AddApplier_Effect", ApplierType.Cast)); Assert.False(Unit.ContainsModifier("AddApplier_Effect")); } diff --git a/ModiBuff/ModiBuff.Tests/CastTests.cs b/ModiBuff/ModiBuff.Tests/CastTests.cs index 52608ef9..8f13289a 100644 --- a/ModiBuff/ModiBuff.Tests/CastTests.cs +++ b/ModiBuff/ModiBuff.Tests/CastTests.cs @@ -160,14 +160,14 @@ public void SelfApplyIfNotCast() Assert.AreEqual(UnitHealth, Unit.Health); //TODO Enemy has SelfCast (shouldn't), Unit doesn't get his appliers removed Assert.False(Unit.ContainsModifier("DurationDamageSelfCast")); - Assert.False(Unit.ContainsApplier("DurationDamageSelfCast")); + Assert.False(Unit.ContainsApplier("DurationDamageSelfCast", ApplierType.Cast)); //Unit.TryCastEffect("DurationDamageCast", Unit); //Adds modifier, starts duration Unit.TryCast("DurationDamageCast", Unit); Unit.Update(1); Assert.AreEqual(UnitHealth - 5, Unit.Health); Assert.False(Unit.ContainsModifier("DurationDamageSelfCast")); - Assert.False(Unit.ContainsApplier("DurationDamageSelfCast")); + Assert.False(Unit.ContainsApplier("DurationDamageSelfCast", ApplierType.Cast)); } } } \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Tests/CentralizedCustomLogicTests.cs b/ModiBuff/ModiBuff.Tests/CentralizedCustomLogicTests.cs index a98f10b9..9cc4e94d 100644 --- a/ModiBuff/ModiBuff.Tests/CentralizedCustomLogicTests.cs +++ b/ModiBuff/ModiBuff.Tests/CentralizedCustomLogicTests.cs @@ -77,23 +77,23 @@ public void HealBasedOnPoisonStacksEvent(RecipeAddFunc recipe) public void HealBasedOnPoisonStacks() { AddRecipe(PoisonRecipe); - AddRecipe("PoisonHealHeal") + AddRecipe("PoisonHeal") .Stack(WhenStackEffect.Always) .Effect(new HealEffect(0, HealEffect.EffectState.None, StackEffectType.Effect | StackEffectType.SetStacksBased, 1) .SetMetaEffects(new AddValueBasedOnPoisonStacksMetaEffect(1f)), EffectOn.Stack); - AddEffect("PoisonHeal", - new ApplierEffect("Poison"), - new ApplierEffect("PoisonHealHeal", targeting: Targeting.SourceTarget)); + AddRecipe("PosionHealApplier") + .Effect(new ApplierEffect("Poison"), EffectOn.Init) + .Effect(new ApplierEffect("PoisonHeal", targeting: Targeting.SourceTarget), EffectOn.Init); Setup(); Unit.TakeDamage(UnitHealth / 2f, Unit); - Unit.AddEffectApplier("PoisonHeal"); + Unit.AddApplierModifierNew("PosionHealApplier", ApplierType.Cast); - Unit.TryCastEffect("PoisonHeal", Enemy); + Unit.TryCast("PosionHealApplier", Enemy); Assert.AreEqual(UnitHealth / 2f + 1, Unit.Health); - Unit.TryCastEffect("PoisonHeal", Enemy); + Unit.TryCast("PosionHealApplier", Enemy); Assert.AreEqual(UnitHealth / 2f + 1 + 1 * 2, Unit.Health); } diff --git a/ModiBuff/ModiBuff.Tests/ModifierTests.cs b/ModiBuff/ModiBuff.Tests/ModifierTests.cs index 100191d7..ca22beb8 100644 --- a/ModiBuff/ModiBuff.Tests/ModifierTests.cs +++ b/ModiBuff/ModiBuff.Tests/ModifierTests.cs @@ -42,7 +42,6 @@ public virtual void OneTimeSetup() Config.DefaultTag = (ulong)Core.Units.TagType.Default; Config.PoolSize = 1; Config.ModifierControllerPoolSize = 3; - Config.ModifierApplierControllerPoolSize = 3; EffectTypeIdManager = new EffectTypeIdManager(); EffectTypeIdManager.RegisterAllEffectTypesInAssemblies(); diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs index 89d5b4a2..8417bd7c 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs @@ -18,7 +18,6 @@ public sealed class AttackUnit : IUnit, IModifierOwner, IAttacker, IUpdatable, I public float Damage { get; } public ModifierController ModifierController { get; } - public ModifierApplierController ModifierApplierController { get; } public AttackUnit(float damage, UnitType unitType = UnitType.Good) { @@ -27,13 +26,11 @@ public AttackUnit(float damage, UnitType unitType = UnitType.Good) UnitTag = UnitTag.Default; ModifierController = ModifierControllerPool.Instance.Rent(); - ModifierApplierController = ModifierControllerPool.Instance.RentApplier(); } public void Update(float delta) { ModifierController.Update(delta); - ModifierApplierController.Update(delta); } public float Attack(IUnit target) diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs index a0994cd0..f3d94bd2 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs @@ -23,7 +23,6 @@ public sealed class DamagableUnit : IUnit, IModifierOwner, IDamagable, IUpdatabl public bool IsDead { get; private set; } public ModifierController ModifierController { get; } - public ModifierApplierController ModifierApplierController { get; } private readonly Dictionary> _modifierAppliers; @@ -34,7 +33,6 @@ public DamagableUnit(float health, UnitType unitType = UnitType.Good) MaxHealth = Health = health; ModifierController = ModifierControllerPool.Instance.Rent(); - ModifierApplierController = ModifierControllerPool.Instance.RentApplier(); _modifierAppliers = new Dictionary> { { ApplierType.Attack, new List<(int, ICheck[])>() }, @@ -45,7 +43,6 @@ public DamagableUnit(float health, UnitType unitType = UnitType.Good) public void Update(float delta) { ModifierController.Update(delta); - ModifierApplierController.Update(delta); } public float TakeDamage(float damage, IUnit source) @@ -69,6 +66,13 @@ public void UseHealth(float value) Health -= value; } + public bool ContainsApplier(int modifierId, ApplierType applierType) + { + return _modifierAppliers.TryGetValue(applierType, out var list) && list.Exists(c => c.Id == modifierId); + } + + public bool TryApply(int modifierId, IUnit target) => TryCast(modifierId, target); + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) { if (checks?.Length > 0) diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs index e6332f30..8abe1cb2 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs @@ -79,6 +79,49 @@ public float TakeDamage(float damage, IUnit source) return dealtDamage; } + public bool ContainsApplier(int modifierId, ApplierType applierType) + { + return _modifierAppliers.TryGetValue(applierType, out var list) && list.Exists(c => c.Id == modifierId); + } + + public bool TryApply(int modifierId, IUnit target) + { + if (!(target is IModifierOwner modifierTarget)) + return false; + if (!modifierId.IsLegalTarget((IUnitEntity)target, this)) + return false; + if (!_modifierAppliers.TryGetValue(ApplierType.Cast, out var appliers)) + return false; + + (int Id, ICheck[] Checks)? applier = null; + for (int i = 0; i < appliers.Count; i++) + { + if (appliers[i].Id == modifierId) + { + applier = appliers[i]; + break; + } + } + + if (applier == null) + return false; + + if (applier.Value.Checks != null) + { + foreach (var check in applier.Value.Checks) + if (!check.Check(this)) + return false; + + for (int i = 0; i < applier.Value.Checks.Length; i++) + applier.Value.Checks[i].Use(this); + } + + modifierTarget.ModifierController.Add(modifierId, modifierTarget, this); + + + return true; + } + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) { if (checks?.Length > 0) diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs index 77c37d89..d50dd675 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs @@ -58,18 +58,6 @@ public void TryApplyDamageAppliers_NoModifiersUnit() Assert.AreEqual(UnitHealth - EnemyDamage, Unit.Health); } - [Test] - public void ApplyDamageEffect_NoModifiersUnit() - { - AddEffect("InitDamage", new DamageEffect(5)); - Setup(); - - Enemy.AddEffectApplier("InitDamage"); - - Enemy.TryCastEffect("InitDamage", Unit); - Assert.AreEqual(UnitHealth - 5, Unit.Health); - } - [Test] public void TryApplyApplierEffect_NoModifiersUnit() { diff --git a/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs b/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs index 14881522..f95710c3 100644 --- a/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs +++ b/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs @@ -296,31 +296,6 @@ public void SaveNewModifierApplierIdLoad() Assert.AreEqual(UnitHealth - 10 - 5 - 10 - 10 - 10, loadedUnit.Health); } - [Test] -#if !MODIBUFF_SYSTEM_TEXT_JSON - [Ignore("MODIBUFF_SYSTEM_TEXT_JSON not set. Skipping test")] -#endif - public void SaveNewEffectIdLoad() - { - AddEffect("InitDamage", new DamageEffect(5)); - AddEffect("InitBigDamage", new DamageEffect(10)); - Setup(); - - const string gameStateFile = "effectIdGameStateTest.json"; - - //TODO save will not have modifier id redirection - if (!File.Exists(_saveController.Path + "/" + gameStateFile)) - { - Unit.AddEffectApplier("InitBigDamage"); - SaveGameState(gameStateFile, Unit); - } - - LoadGameState(gameStateFile, out Unit loadedUnit); - - loadedUnit.TryCastEffect("InitBigDamage", loadedUnit); - Assert.AreEqual(UnitHealth - 10, loadedUnit.Health); - } - [Test] #if !MODIBUFF_SYSTEM_TEXT_JSON [Ignore("MODIBUFF_SYSTEM_TEXT_JSON not set. Skipping test")] diff --git a/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs b/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs index 5e3d4420..ef10045d 100644 --- a/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs +++ b/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs @@ -47,15 +47,16 @@ internal static bool ContainsModifier(this IModifierOwner unit, string name) return unit.ModifierController.Contains(ModifierIdManager.GetIdByName(name).Value); } - internal static bool ContainsApplier(this IModifierApplierOwner unit, string name) + internal static bool ContainsApplier(this IModifierApplierOwner unit, string name, ApplierType applierType) { - return unit.ModifierApplierController.ContainsApplier(ModifierIdManager.GetIdByName(name).Value); + return unit.ContainsApplier(ModifierIdManager.GetIdByName(name).Value, applierType); } - internal static bool AddEffectApplier(this IModifierApplierOwner unit, string name) + internal static void AddApplierModifierNew(this IModifierApplierOwner unit, string name, + ApplierType applierType, params ICheck[] checks) { CheckForSetup(unit); - return unit.ModifierApplierController.TryAddEffectApplier(EffectIdManager.GetIdOld(name).Value); + unit.AddApplierModifierNew(ModifierIdManager.GetIdByName(name).Value, applierType, checks); } internal static void TryCast(this Unit unit, string name, IModifierOwner target) @@ -63,11 +64,6 @@ internal static void TryCast(this Unit unit, string name, IModifierOwner target) unit.TryCast(ModifierIdManager.GetIdByName(name).Value, target); } - internal static void TryCastEffect(this IModifierApplierOwner unit, string name, IUnit target) - { - unit.TryCastEffect(EffectIdManager.GetIdOld(name).Value, target); - } - internal static void ChangeStatusEffect(this IStatusEffectOwner owner, StatusEffectType statusEffect, float duration, IUnit source) { diff --git a/ModiBuff/ModiBuff.Units/Unit/Unit.cs b/ModiBuff/ModiBuff.Units/Unit/Unit.cs index bb9ec694..829734bf 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Unit.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Unit.cs @@ -483,6 +483,11 @@ public void StrongDispel(IUnit source) //---Appliers--- + public bool ContainsApplier(int modifierId, ApplierType applierType) + { + return _modifierAppliers.TryGetValue(applierType, out var list) && list.Exists(c => c.Id == modifierId); + } + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[]? checks = null) { if (checks is { Length: > 0 }) diff --git a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs index 7514c1a6..2c2dfae5 100644 --- a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs +++ b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs @@ -2,6 +2,8 @@ namespace ModiBuff.Core { public interface IModifierApplierOwner : IUnit { + bool ContainsApplier(int modifierId, ApplierType applierType); + bool TryApply(int modifierId, IUnit target); void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[]? checks = null); diff --git a/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs b/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs index f7449270..b6d379c3 100644 --- a/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs +++ b/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs @@ -11,16 +11,5 @@ public static void Dispel(this IModifierOwner owner, DispelType dispelType, IUni { owner.ModifierController.Dispel(dispelType, owner, source); } - - //TODO Remove? - public static void TryCastEffect(this IModifierApplierOwner owner, int effectId, IUnit target) - { - if (owner.ModifierApplierController.CanCastEffect(effectId)) - target.ApplyEffect(effectId, owner); -#if DEBUG - else - Logger.Log($"[ModiBuff] Can't cast effect id {effectId} from {owner} to {target}"); -#endif - } } } \ No newline at end of file From 6dc4f184d296e40a18c2f41f39a3182b0fb28b9e Mon Sep 17 00:00:00 2001 From: chillu Date: Mon, 1 Sep 2025 18:50:23 +0200 Subject: [PATCH 10/11] feat: remove applier --- .../ModiBuff.Examples/BasicConsole/Unit.cs | 13 +++++++++++++ .../PartialUnitTests/DamagableUnitTests.cs | 13 +++++++++++++ .../ModifierApplierUnitTests.cs | 13 +++++++++++++ ModiBuff/ModiBuff.Units/Unit/Unit.cs | 18 ++++++++++++++++++ .../Modifier/Components/Effect/RemoveEffect.cs | 3 +-- .../Core/Unit/IModifierApplierOwner.cs | 2 +- 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs b/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs index 881f8cbf..2387ffab 100644 --- a/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs +++ b/ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs @@ -207,6 +207,19 @@ public bool ContainsApplier(int modifierId, ApplierType applierType) return _modifierAppliers.TryGetValue(applierType, out var list) && list.Exists(c => c.Id == modifierId); } + public bool RemoveApplier(int id, ApplierType applierType) + { + if (!_modifierAppliers.TryGetValue(applierType, out var list)) + return false; + + int index = list.FindIndex(c => c.Id == id); + if (index == -1) + return false; + + list.RemoveAt(index); + return true; + } + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) { if (checks?.Length > 0) diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs index f3d94bd2..191bea8b 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs @@ -73,6 +73,19 @@ public bool ContainsApplier(int modifierId, ApplierType applierType) public bool TryApply(int modifierId, IUnit target) => TryCast(modifierId, target); + public bool RemoveApplier(int id, ApplierType applierType) + { + if (!_modifierAppliers.TryGetValue(applierType, out var list)) + return false; + + int index = list.FindIndex(c => c.Id == id); + if (index == -1) + return false; + + list.RemoveAt(index); + return true; + } + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null) { if (checks?.Length > 0) diff --git a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs index 8abe1cb2..ac821a51 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs @@ -84,6 +84,19 @@ public bool ContainsApplier(int modifierId, ApplierType applierType) return _modifierAppliers.TryGetValue(applierType, out var list) && list.Exists(c => c.Id == modifierId); } + public bool RemoveApplier(int id, ApplierType applierType) + { + if (!_modifierAppliers.TryGetValue(applierType, out var list)) + return false; + + int index = list.FindIndex(c => c.Id == id); + if (index == -1) + return false; + + list.RemoveAt(index); + return true; + } + public bool TryApply(int modifierId, IUnit target) { if (!(target is IModifierOwner modifierTarget)) diff --git a/ModiBuff/ModiBuff.Units/Unit/Unit.cs b/ModiBuff/ModiBuff.Units/Unit/Unit.cs index 829734bf..8cbc2556 100644 --- a/ModiBuff/ModiBuff.Units/Unit/Unit.cs +++ b/ModiBuff/ModiBuff.Units/Unit/Unit.cs @@ -488,6 +488,24 @@ public bool ContainsApplier(int modifierId, ApplierType applierType) return _modifierAppliers.TryGetValue(applierType, out var list) && list.Exists(c => c.Id == modifierId); } + public bool RemoveApplier(int id, ApplierType applierType) + { + if (!_modifierAppliers.TryGetValue(applierType, out var list)) + return false; + + int index = list.FindIndex(c => c.Id == id); + if (index < 0) + return false; + + var checks = list[index].Checks; + if (checks != null) + foreach (var check in checks) + if (check is IUpdatableCheck updatableCheck) + _updatableChecks.Remove(updatableCheck); + list.RemoveAt(index); + return true; + } + public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[]? checks = null) { if (checks is { Length: > 0 }) diff --git a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/RemoveEffect.cs b/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/RemoveEffect.cs index 6014ad76..dc125f98 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/RemoveEffect.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/RemoveEffect.cs @@ -58,8 +58,7 @@ public void Effect(IUnit target, IUnit source) if (_applierType != null) { - //TODO - //((IModifierApplierOwner)target).RemoveApplier(_id /*, _genId*/, _applierType.Value); + ((IModifierApplierOwner)target).RemoveApplier(_id /*, _genId*/, _applierType.Value); //return; } diff --git a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs index 2c2dfae5..e3b03ee1 100644 --- a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs +++ b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs @@ -7,6 +7,6 @@ public interface IModifierApplierOwner : IUnit bool TryApply(int modifierId, IUnit target); void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[]? checks = null); - //void RemoveApplier(int id, ApplierType applierType); + bool RemoveApplier(int id, ApplierType applierType); } } \ No newline at end of file From bff5f3e4a945da54a20a017e866b00e847514961 Mon Sep 17 00:00:00 2001 From: chillu Date: Wed, 3 Sep 2025 17:08:28 +0200 Subject: [PATCH 11/11] feat: continued applier refactor --- ModiBuff/ModiBuff.Tests/ApplierTests.cs | 28 ++++++++++- ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs | 4 +- .../Effects}/ApplierEffect.cs | 18 +++---- .../Effects/RemoveApplierEffect.cs | 47 +++++++++++++++++++ .../Recipe/ModifierRecipeExtensions.cs | 5 ++ .../Creation/Recipe/ModifierRecipe.cs | 11 +---- 6 files changed, 87 insertions(+), 26 deletions(-) rename ModiBuff/{ModiBuff/Core/Modifier/Components/Effect => ModiBuff.Units/Effects}/ApplierEffect.cs (80%) create mode 100644 ModiBuff/ModiBuff.Units/Effects/RemoveApplierEffect.cs diff --git a/ModiBuff/ModiBuff.Tests/ApplierTests.cs b/ModiBuff/ModiBuff.Tests/ApplierTests.cs index 464612e7..03a43e03 100644 --- a/ModiBuff/ModiBuff.Tests/ApplierTests.cs +++ b/ModiBuff/ModiBuff.Tests/ApplierTests.cs @@ -237,9 +237,9 @@ public void Cast_AddApplier() { AddRecipe("AddApplier_Effect") .Effect(new ApplierEffect("InitDamage"), EffectOn.Init) - .RemoveApplier(5, ApplierType.Cast); + .RemoveApplier(ApplierType.Cast, 5); AddRecipe("AddApplier_ApplierEffect") - .Effect(new ApplierEffect("AddApplier_Effect", ApplierType.Cast, false), EffectOn.Init); + .Effect(new ApplierEffect("AddApplier_Effect", ApplierType.Cast), EffectOn.Init); Setup(); Unit.TryCast("AddApplier_Effect", Enemy); @@ -280,5 +280,29 @@ public void ConditionalApplierBasedOnUnitType() Unit.TryCast("ConditionalApplierBasedOnUnitType", Ally); Assert.AreEqual(AllyHealth - 5 + 5, Ally.Health); } + + //[Test + public void AddApplier_DurationRemove() + { + AddRecipe("AddApplier_Effect") + .Effect(new ApplierEffect("InitDamage"), EffectOn.Init) + .RemoveApplier(ApplierType.Cast, 5); + //TODO Issue that modifier is not being added, so the duration doesn't work + //We probably need to have two modifiers for applier removal, one that is used as the applier by the unit + //Second as the duration remover that removes self and the applier in unit + Setup(); + + Unit.AddApplierModifierNew("AddApplier_Effect", ApplierType.Cast); + Assert.False(Unit.ContainsModifier("AddApplier_Effect")); + + Unit.TryCast("AddApplier_Effect", Enemy); + Unit.Update(1); + Assert.AreEqual(EnemyHealth - 5, Enemy.Health); + + Unit.Update(4); + Assert.False(Unit.ContainsApplier("AddApplier_Effect", ApplierType.Cast)); + Assert.False(Unit.ContainsModifier("AddApplier_Effect")); + Assert.False(Unit.TryCast("AddApplier_Effect", Enemy)); + } } } \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs b/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs index ef10045d..f81c5f6c 100644 --- a/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs +++ b/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs @@ -59,9 +59,9 @@ internal static void AddApplierModifierNew(this IModifierApplierOwner unit, stri unit.AddApplierModifierNew(ModifierIdManager.GetIdByName(name).Value, applierType, checks); } - internal static void TryCast(this Unit unit, string name, IModifierOwner target) + internal static bool TryCast(this Unit unit, string name, IModifierOwner target) { - unit.TryCast(ModifierIdManager.GetIdByName(name).Value, target); + return unit.TryCast(ModifierIdManager.GetIdByName(name).Value, target); } internal static void ChangeStatusEffect(this IStatusEffectOwner owner, diff --git a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs b/ModiBuff/ModiBuff.Units/Effects/ApplierEffect.cs similarity index 80% rename from ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs rename to ModiBuff/ModiBuff.Units/Effects/ApplierEffect.cs index ee251583..3f5c22d9 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs +++ b/ModiBuff/ModiBuff.Units/Effects/ApplierEffect.cs @@ -1,31 +1,26 @@ using System; -using System.Collections.Generic; -namespace ModiBuff.Core +namespace ModiBuff.Core.Units { public sealed class ApplierEffect : IStackEffect, IEffect, IMetaEffectOwner { - public bool HasApplierType => _applierType != null; - private readonly int _modifierId; private readonly ApplierType? _applierType; - private readonly bool _hasApplyChecks; private readonly Targeting _targeting; private IMetaEffect[]? _metaEffects; public ApplierEffect(string modifierName, ApplierType? applierType = null, - bool hasApplyChecks = false, Targeting targeting = Targeting.TargetSource) + Targeting targeting = Targeting.TargetSource) { //Could ask the user to instead supply the id, but that isn't ideal int? id = ModifierIdManager.GetIdByName(modifierName); if (id == null) - Logger.LogError("[ModiBuff] Can't find modifier with name " + modifierName + + Logger.LogError("[ModiBuff.Units] Can't find modifier with name " + modifierName + ". Either wrong order of effect initialization or wrong modifier name."); _modifierId = id ?? -1; _applierType = applierType; - _hasApplyChecks = hasApplyChecks; _targeting = targeting; } @@ -33,14 +28,13 @@ public ApplierEffect(string modifierName, ApplierType? applierType = null, /// Manual modifier generation constructor /// public static ApplierEffect Create(int modifierId, ApplierType? applierType = null, - bool hasApplyChecks = false, Targeting targeting = Targeting.TargetSource) => - new ApplierEffect(modifierId, applierType, hasApplyChecks, targeting); + Targeting targeting = Targeting.TargetSource) => + new ApplierEffect(modifierId, applierType, targeting); - private ApplierEffect(int modifierId, ApplierType? applierType, bool hasApplyChecks, Targeting targeting) + private ApplierEffect(int modifierId, ApplierType? applierType, Targeting targeting) { _modifierId = modifierId; _applierType = applierType; - _hasApplyChecks = hasApplyChecks; _targeting = targeting; } diff --git a/ModiBuff/ModiBuff.Units/Effects/RemoveApplierEffect.cs b/ModiBuff/ModiBuff.Units/Effects/RemoveApplierEffect.cs new file mode 100644 index 00000000..c5f07b88 --- /dev/null +++ b/ModiBuff/ModiBuff.Units/Effects/RemoveApplierEffect.cs @@ -0,0 +1,47 @@ +namespace ModiBuff.Core.Units +{ + public sealed class RemoveApplierEffect : IModifierGenIdOwner, IEffect, IStackEffect, IModifierIdOwner, + IShallowClone + { + private readonly ApplierType _applierType; + private int _id; + private int? _genId; + + public RemoveApplierEffect(ApplierType applierType) => _applierType = applierType; + + /// + /// Manual modifier generation constructor + /// + public static RemoveApplierEffect Create(int id, int? genId, ApplierType applierType) + { + var effect = new RemoveApplierEffect(id, genId, applierType); + return effect; + } + + private RemoveApplierEffect(int id, int? genId, ApplierType applierType) + { + _id = id; + _genId = genId; + _applierType = applierType; + } + + public void SetModifierId(int id) => _id = id; + + public void SetGenId(int genId) => _genId = genId; + + public void Effect(IUnit target, IUnit source) + { +#if DEBUG && !MODIBUFF_PROFILE + if (_genId == null) //This probably wont matter for not instance stackable modifiers + Logger.LogWarning("[ModiBuff] RemoveEffect.Effect: genId wasn't set"); +#endif + + ((IModifierApplierOwner)target).RemoveApplier(_id /*, _genId*/, _applierType); + } + + public void StackEffect(int stacks, IUnit target, IUnit source) => Effect(target, source); + + public IEffect ShallowClone() => new RemoveApplierEffect(_id, _genId, _applierType); + object IShallowClone.ShallowClone() => ShallowClone(); + } +} \ No newline at end of file diff --git a/ModiBuff/ModiBuff.Units/Recipe/ModifierRecipeExtensions.cs b/ModiBuff/ModiBuff.Units/Recipe/ModifierRecipeExtensions.cs index a8fb2e8f..c13dff2f 100644 --- a/ModiBuff/ModiBuff.Units/Recipe/ModifierRecipeExtensions.cs +++ b/ModiBuff/ModiBuff.Units/Recipe/ModifierRecipeExtensions.cs @@ -7,6 +7,11 @@ public static ModifierRecipe Tag(this ModifierRecipe recipe, TagType tag) return recipe.Tag(tag.ToInternalTag()); } + public static ModifierRecipe RemoveApplier(this ModifierRecipe recipe, ApplierType applierType, float duration) + { + return recipe.Effect(new RemoveApplierEffect(applierType), EffectOn.Duration).Duration(duration); + } + public static ModifierRecipe LegalTarget(this ModifierRecipe recipe, LegalTarget target) { recipe.RemoveTag((Core.TagType)TagType.LegalTargetAll); diff --git a/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipe.cs b/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipe.cs index 38644eeb..e468dcaa 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipe.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipe.cs @@ -191,7 +191,7 @@ public ModifierRecipe Remove(float duration) /// How many seconds should pass before the modifier gets removed. /// /// OVERWRITES all previous remove effects. - public ModifierRecipe RemoveApplier(float duration, ApplierType applierType) + public ModifierRecipe RemoveApplierOld(float duration, ApplierType applierType) { Duration(duration); _removeEffectWrapper = new RemoveEffectWrapper(new RemoveEffect(Id, applierType), EffectOn.Duration); @@ -624,15 +624,6 @@ private void Validate() ValidateCallbacks(EffectOnCallbackEffectData.AllCallbackEffectUnitsData, _callbackEffectUnitsRegisterWrappers); - if (_effectWrappers.Exists(w => - w.GetEffect() is ApplierEffect applierEffect && applierEffect.HasApplierType)) - { - Logger.LogWarning( - "[ModiBuff] ApplierEffect ApplierType set in a modifier, adding this modifier will add " + - "the applier effect to the owner because of how modifiers work, use effect (modifier-less-effects) " + - "if not desired in modifier: " + Name + " id: " + Id); - } - if (_tag.HasTag(TagType.CustomStack) && !_modifierActions.HasFlag(Core.ModifierAction.Stack)) { validRecipe = false;