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/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 42e1c9b0..2387ffab 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; @@ -21,7 +22,7 @@ public sealed class Unit : IModifierOwner, IUpdatable, IDamagable, IAttacker, IH public ModifierController ModifierController { get; } //TODO Explain - public ModifierApplierController ModifierApplierController { get; } + 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. @@ -47,7 +48,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(); } @@ -60,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); } @@ -95,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) @@ -141,6 +202,49 @@ 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 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) + { + 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 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 9dc68d08..03a43e03 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); } @@ -100,15 +98,13 @@ public void DamageApplier_Interval() public void InitDamageCostMana() { AddRecipe("InitDamage_CostMana") - .ApplyCost(CostType.Mana, 5) .Effect(new DamageEffect(5), EffectOn.Init); Setup(); - var generator = Recipes.GetGenerator("InitDamage_CostMana"); + int id = IdManager.GetId("InitDamage_CostMana").Value; + Unit.AddApplierModifierNew(id, ApplierType.Cast, new ICheck[] { new CostCheck(CostType.Mana, 5) }); - Unit.AddApplierModifier(generator, ApplierType.Cast); - - Unit.TryCast(generator.Id, Enemy); + Unit.TryCast(id, Enemy); Assert.AreEqual(UnitMana - 5, Unit.Mana); Assert.AreEqual(EnemyHealth - 5, Enemy.Health); @@ -241,19 +237,20 @@ 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)); + .RemoveApplier(ApplierType.Cast, 5); + AddRecipe("AddApplier_ApplierEffect") + .Effect(new ApplierEffect("AddApplier_Effect", ApplierType.Cast), 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); Unit.Update(5); - Assert.False(Unit.ContainsApplier("AddApplier_Effect")); + Assert.False(Unit.ContainsApplier("AddApplier_Effect", ApplierType.Cast)); Assert.False(Unit.ContainsModifier("AddApplier_Effect")); } @@ -273,7 +270,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); @@ -283,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/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/CastTests.cs b/ModiBuff/ModiBuff.Tests/CastTests.cs index a2d574a1..8f13289a 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,11 +57,11 @@ public void AttackInitDamageNoChecks_OnEnemy() public void AttackInitDamageChecks_OnEnemy() { AddRecipe("InitDamageFullHealth") - .ApplyCondition(ConditionType.HealthIsFull) .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); @@ -76,15 +78,15 @@ 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)); @@ -100,14 +102,15 @@ 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); } - //[Test] + [Test, Ignore("Advanced applier logic needed")] public void SelfApplyIfNotCast() { //Trigger duration timer, if duration timer ends, damages self @@ -148,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 @@ -157,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 8b9f6ece..9cc4e94d 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); } @@ -75,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); } @@ -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/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/ConditionTests.cs b/ModiBuff/ModiBuff.Tests/ConditionTests.cs index b868122d..7def0a6b 100644 --- a/ModiBuff/ModiBuff.Tests/ConditionTests.cs +++ b/ModiBuff/ModiBuff.Tests/ConditionTests.cs @@ -10,16 +10,18 @@ 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(); - 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 +29,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 +118,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 +164,20 @@ 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 +208,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 +250,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..3d3af26f 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); } @@ -182,25 +185,25 @@ public void InitDamage_ChargesCooldown() public void InitDamage_ChargesCooldownUseWait() { 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); 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..1202c64f 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); @@ -25,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 @@ -41,11 +45,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); @@ -56,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); @@ -87,16 +95,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); @@ -106,17 +116,20 @@ public void CostHealth_HealSelf() public void CostSixtyPercentHealth_Damage() { AddRecipe("InitDamage_CostSixtyPercentHealth") - .ApplyCostPercent(CostType.Health, 0.6f) .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.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..5cd42079 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); } @@ -120,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/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 1941e0c0..8417bd7c 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/AttackUnitTests.cs @@ -11,15 +11,13 @@ 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; } public float Damage { get; } public ModifierController ModifierController { get; } - public ModifierApplierController ModifierApplierController { get; } public AttackUnit(float damage, UnitType unitType = UnitType.Good) { @@ -28,18 +26,16 @@ 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) { - 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..191bea8b 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/DamagableUnitTests.cs @@ -23,7 +23,8 @@ 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; public DamagableUnit(float health, UnitType unitType = UnitType.Good) { @@ -32,13 +33,16 @@ 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[])>() }, + { ApplierType.Cast, new List<(int, ICheck[])>() } + }; } public void Update(float delta) { ModifierController.Update(delta); - ModifierApplierController.Update(delta); } public float TakeDamage(float damage, IUnit source) @@ -61,6 +65,86 @@ 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 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) + { + 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 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] @@ -118,41 +202,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/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.Tests/PartialUnitTests/ModifierApplierUnitTests.cs b/ModiBuff/ModiBuff.Tests/PartialUnitTests/ModifierApplierUnitTests.cs index b2056d54..ac821a51 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; @@ -21,7 +22,7 @@ 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) { @@ -30,13 +31,40 @@ 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[])>() }, + { ApplierType.Cast, new List<(int, ICheck[])>() } + }; } 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); } @@ -50,24 +78,103 @@ 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 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)) + 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) + { + 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] 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..d50dd675 100644 --- a/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs +++ b/ModiBuff/ModiBuff.Tests/PartialUnitTests/NoModifierUnitTests.cs @@ -45,29 +45,19 @@ 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); } - [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/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..f95710c3 100644 --- a/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs +++ b/ModiBuff/ModiBuff.Tests/SaveLoadTests.cs @@ -173,29 +173,33 @@ 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 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), + 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); } @@ -255,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 @@ -265,7 +269,6 @@ 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(); @@ -275,8 +278,11 @@ public void SaveNewModifierApplierIdLoad() //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(IdManager.GetId("DoT").Value, ApplierType.Cast); + Unit.AddApplierModifierNew(IdManager.GetId("DoTHealthCost").Value, ApplierType.Cast, new ICheck[] + { + new CostCheck(CostType.Health, 5) + }); SaveGameState(gameStateFile, Unit); } @@ -290,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")] @@ -347,7 +328,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") @@ -433,8 +414,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 d95e8cab..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); } @@ -276,7 +275,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)); @@ -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/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..c2f3d6a7 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); } @@ -32,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); } @@ -52,12 +54,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.Tests/UnitTestExtensions.cs b/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs index 697558c3..f81c5f6c 100644 --- a/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs +++ b/ModiBuff/ModiBuff.Tests/UnitTestExtensions.cs @@ -47,38 +47,21 @@ 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 AddApplierModifier(this IModifierApplierOwner unit, IModifierGenerator generator, - ApplierType applierType) + internal static void AddApplierModifierNew(this IModifierApplierOwner unit, string name, + ApplierType applierType, params ICheck[] checks) { CheckForSetup(unit); - return unit.ModifierApplierController.TryAddApplier(generator.Id, - ((IModifierApplyCheckGenerator)generator).HasApplyChecks, applierType); + unit.AddApplierModifierNew(ModifierIdManager.GetIdByName(name).Value, applierType, checks); } - internal static bool AddEffectApplier(this IModifierApplierOwner unit, string name) + internal static bool TryCast(this Unit unit, string name, IModifierOwner target) { - CheckForSetup(unit); - return unit.ModifierApplierController.TryAddEffectApplier(EffectIdManager.GetIdOld(name).Value); - } - - 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); + return unit.TryCast(ModifierIdManager.GetIdByName(name).Value, target); } internal static void ChangeStatusEffect(this IStatusEffectOwner owner, 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/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.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/Core/Modifier/Components/Effect/ApplierEffect.cs b/ModiBuff/ModiBuff.Units/Effects/ApplierEffect.cs similarity index 76% rename from ModiBuff/ModiBuff/Core/Modifier/Components/Effect/ApplierEffect.cs rename to ModiBuff/ModiBuff.Units/Effects/ApplierEffect.cs index 540f37b1..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; } @@ -72,8 +66,7 @@ public void Effect(IUnit target, IUnit source) return; } - modifierApplierOwnerTarget.ModifierApplierController.TryAddApplier(modifierId, _hasApplyChecks, - _applierType.Value); + modifierApplierOwnerTarget.AddApplierModifierNew(modifierId, _applierType.Value); break; default: throw new ArgumentOutOfRangeException(); 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 f39f82db..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); @@ -19,74 +24,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/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 d96fe34f..8cbc2556 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; @@ -42,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 => @@ -64,6 +64,9 @@ public partial class Unit : IUpdatable, IModifierOwner, IModifierApplierOwner, I private readonly StatusEffectController _singleInstanceStatusEffectController; private readonly DurationLessStatusEffectController _durationLessStatusEffectController; + private readonly Dictionary> _modifierAppliers; + private readonly List _updatableChecks; + private readonly Dictionary _modifierLevels; private static int _idCounter; @@ -115,21 +118,19 @@ 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(); _durationLessStatusEffectController = new DurationLessStatusEffectController(); - _modifierLevels = new Dictionary(); - } + _modifierAppliers = new Dictionary>() + { + { ApplierType.Attack, new List<(int Id, ICheck[] Checks)>() }, + { ApplierType.Cast, new List<(int Id, ICheck[] Checks)>() }, + }; + _updatableChecks = new List(); - 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); + _modifierLevels = new Dictionary(); } public static Unit LoadUnit(int oldId) @@ -144,7 +145,8 @@ 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); _callbackTimer += deltaTime; if (_callbackTimer >= CallbackTimerCooldown) @@ -206,7 +208,10 @@ public float Attack(IUnit target) bool wasDead = killableTarget != null && killableTarget.IsDead; if (target is IModifierOwner modifierOwner) - this.ApplyAllAttackModifier(modifierOwner); + { + //this.ApplyAllAttackModifier(modifierOwner); + DoChecks(modifierOwner, ApplierType.Attack); + } if (++_onAttackCounter <= MaxEventCount) { @@ -341,16 +346,46 @@ public float Heal(IHealable target) return valueHealed; } - public void TryCast(int modifierId, IUnit target) + 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); + + private bool TryCastInternal(int modifierId, IUnit target, bool skipChecks = false) { if (!(target is IModifierOwner modifierTarget)) - return; + return false; if (!modifierId.IsLegalTarget((IUnitEntity)target, this)) - return; + return false; if (!StatusEffectController.HasLegalAction(LegalAction.Cast)) - return; - if (!this.CanCastModifier(modifierId)) - return; + 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; + //if (!this.CanCastModifier(modifierId)) + // return; + + for (int i = 0; i < applier.Value.Checks.Length; i++) + applier.Value.Checks[i].Use(this); + } if (++_onCastCounter <= MaxEventCount) { @@ -367,6 +402,8 @@ public void TryCast(int modifierId, IUnit target) ResetEventCounters(); (target as ICallbackCounter)?.ResetEventCounters(); } + + return true; } public void AddDamage(float damage) @@ -444,6 +481,78 @@ public void StrongDispel(IUnit source) ResetEventCounters(); } + //---Appliers--- + + 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 }) + { + 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; + } + + _modifierAppliers[applierType].Add((modifierId, null)); + } + + 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--- public void AddAuraTargets(int id, params Unit[] targets) => _auraTargets[id].AddRange(targets); @@ -494,7 +603,6 @@ public void ResetState() _singleInstanceStatusEffectController.ResetState(); _durationLessStatusEffectController.ResetState(); ModifierControllerPool.Instance.Return(ModifierController); - ModifierControllerPool.Instance.ReturnApplier(ModifierApplierController); void ClearEvents(params IList[] lists) { @@ -506,8 +614,11 @@ 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(), - _statusEffectController.SaveState(), _singleInstanceStatusEffectController.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()); } public void LoadState(SaveData data) @@ -522,7 +633,36 @@ 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) + { + foreach ((int id, var checkStates) in loadPair.Value) + { + if (!_modifierAppliers[loadPair.Key].Exists(c => c.Id == id)) + { + 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 + ((IStateCheck)loadCheck.Checks[i]).LoadState(state); + i++; + } + } + } + _statusEffectController.LoadState(data.MultiInstanceStatusEffectControllerSaveData); _singleInstanceStatusEffectController.LoadState(data.SingleInstanceStatusEffectControllerSaveData); } @@ -546,8 +686,7 @@ 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; @@ -557,7 +696,7 @@ 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) { @@ -572,7 +711,7 @@ 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/Check/ICheck.cs b/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs index bd3ba81f..24ede481 100644 --- a/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs +++ b/ModiBuff/ModiBuff/Core/Modifier/Components/Check/ICheck.cs @@ -1,6 +1,43 @@ +using System; +using System.Runtime.CompilerServices; + namespace ModiBuff.Core { public interface ICheck { } + + public static class CheckExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Use(this ICheck check, IUnit source) + { + 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/RemoveEffect.cs b/ModiBuff/ModiBuff/Core/Modifier/Components/Effect/RemoveEffect.cs index 660a58d1..dc125f98 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,7 @@ public void Effect(IUnit target, IUnit source) if (_applierType != null) { - ((IModifierApplierOwner)target).ModifierApplierController.RemoveApplier(_id /*, _genId*/, - _applierType.Value, _hasApplyChecks); + ((IModifierApplierOwner)target).RemoveApplier(_id /*, _genId*/, _applierType.Value); //return; } @@ -71,7 +67,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..e468dcaa 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 RemoveApplierOld(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); } @@ -647,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; 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/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/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/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 diff --git a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs index c9428d8f..e3b03ee1 100644 --- a/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs +++ b/ModiBuff/ModiBuff/Core/Unit/IModifierApplierOwner.cs @@ -2,6 +2,11 @@ namespace ModiBuff.Core { public interface IModifierApplierOwner : IUnit { - ModifierApplierController ModifierApplierController { get; } + bool ContainsApplier(int modifierId, ApplierType applierType); + + bool TryApply(int modifierId, IUnit target); + + void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[]? checks = null); + bool 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 10c2bfd2..b6d379c3 100644 --- a/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs +++ b/ModiBuff/ModiBuff/Core/Unit/ModifierOwnerExtensions.cs @@ -11,91 +11,5 @@ 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) - { - 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) - { - 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 - } - - 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