using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using UnityEngine; /// <summary> /// Handles Consumable usage situtations via the Items button /// </summary> public class ConsumableManagement : MonoBehaviour { private BattleHandler bhReference; // Reference to the battle handler that is feeding the information to the manager private bool inBattle; // Reference to if the consumable management system needs to act as if in battle private Player playerRetainer; // Information storage for the player object private Enemy[] enemyRetainers; // Information storage of all of the enemies within the current battle private Ally[] allyRetainers; // Information storage of all of the current allies in the party private Consumable currentConsumable; // The current consumable that is being used, information storage private Target[] enemyTargets; // Target components for enemies for indicator instantiation private Target[] allyTargets; // Target components for allies for indicator instantiation private Target playerTarget; // Target component for the player when trying to self activate private Task chosenTarget; // Task system to awawit for the chosen target for player selection private Entity consumableUser; // The user of the consumable private Entity consumableTarget; // The target of the consumable private bool UsedConsumable; private bool consumableTaskCancel; private bool[] signals; private static bool consumableSignaledToNotUse; private const int MaxChance = 100; public static void IndicateNoConsume() => consumableSignaledToNotUse = true; public bool GetUsedConsumableState() => UsedConsumable; public bool GetConsumableTaskState() => consumableTaskCancel; public void StopConsumableTasks() => consumableTaskCancel = true; /// <summary> /// Passes the target of the spell as an entity and indicates what child type the passed parameter it is /// </summary> /// <param name="target">Parent Entity class for the Enemies and Player classes</param> /// <exception cref="NullReferenceException">When target is null or an unexpected Entity type</exception> public void ChooseTarget(Entity target) { if (target is Player) consumableTarget = target as Player; else if (target is Enemy) consumableTarget = target as Enemy; else if (target is Ally) consumableTarget = target as Ally; else throw new NullReferenceException(); chosenTarget = Task.CompletedTask; } public void BeginConsumableProcess(Entity user, Consumable consumable, Player player, Enemy[] enemyComps, Ally[] allyComps, BattleHandler bh) { UsedConsumable = false; consumableTaskCancel = false; consumableSignaledToNotUse = false; bhReference = bh; currentConsumable = consumable; consumableUser = user; if (player != null) { playerRetainer = player; playerTarget = player.gameObject.GetComponent<Target>(); playerTarget.InjectManager(this); } else { playerRetainer = null; playerTarget = null; } if (allyComps != null) { allyRetainers = allyComps; allyTargets = new Target[allyComps.Length]; for (int i = 0; i < allyRetainers.Length; i++) { allyTargets[i] = allyRetainers[i].gameObject.GetComponent<Target>(); allyTargets[i].InjectManager(this); } } else { allyRetainers = null; allyTargets = null; } enemyRetainers = enemyComps; enemyTargets = new Target[enemyComps.Length]; for (int i = 0; i < enemyRetainers.Length; i++) { enemyTargets[i] = enemyRetainers[i].gameObject.GetComponent<Target>(); enemyTargets[i].InjectManager(this); } if (currentConsumable.Effects.Count > 1) BeginAdvancedConsumableProcess(); else BeginNormalConsumableProcess(); } /// <summary> /// Normal Consumable Process when there is only one effect in the list /// </summary> private void BeginNormalConsumableProcess() { switch (currentConsumable.Effects.FirstOrDefault()) { case ConsumableSO.Effect.Damage: signals = new bool[6] { true, false, false, false, false, false }; ActivateDamageCon(); break; case ConsumableSO.Effect.Heal: signals = new bool[6] { false, true, false, false, false, false }; ActivateHealCon(); break; case ConsumableSO.Effect.Refill: signals = new bool[6] { false, false, true, false, false, false }; ActivateRefillCon(); break; case ConsumableSO.Effect.Buff: signals = new bool[6] { false, false, false, true, false, false }; ActivateBuffCon(); break; case ConsumableSO.Effect.Debuff: signals = new bool[6] { false, false, false, false, true, false }; ActivateDebuffCon(); break; } } /// <summary> /// More Advanced Consumable Process when there is more than one effect in the consumable list /// </summary> private void BeginAdvancedConsumableProcess() { for (int i = 0; i < currentConsumable.Effects.Count; i++) { bool endOfEffects = i == currentConsumable.Effects.Count - 1; switch (currentConsumable.Effects[i]) { case ConsumableSO.Effect.Heal: signals = new bool[6] { true, false, false, false, false, false }; ActivateHealCon(endOfEffects); break; case ConsumableSO.Effect.Refill: signals = new bool[6] { false, true, false, false, false, false }; ActivateRefillCon(endOfEffects); break; case ConsumableSO.Effect.Buff: signals = new bool[6] { false, false, true, false, false, false }; ActivateBuffCon(endOfEffects); break; case ConsumableSO.Effect.Debuff: signals = new bool[6] { false, false, false, true, false, false }; ActivateDebuffCon(endOfEffects); break; case ConsumableSO.Effect.Damage: signals = new bool[6] { false, false, false, false, true, false }; ActivateDamageCon(endOfEffects); break; default: throw new DataMisalignedException($"Invalid Type detected in AdvancedConsumableProcess. " + $"CurrentConsumable.Effects[i] -> ({currentConsumable.Effects[i]})"); } } } /// <summary> /// Damage Consumable Handler /// </summary> private async void ActivateDamageCon(bool isEndOfConsumable = true) { int v = UtilityHandler.RollValueWithBase(currentConsumable.BaseValue, currentConsumable.DamageChance.ToArray()); if (currentConsumable.EffectAll) { if (!consumableSignaledToNotUse) UsedConsumable = true; await bhReference.AttackWithItem(v, currentConsumable, consumableUser, null, true, true); } if (consumableUser is Player || consumableUser is Ally) { // When the user is the player or ally they select either side for damage if (currentConsumable.EffectAllType) { SwitchAllIndicatorTargets(true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchAllIndicatorTargets(false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); if (!consumableSignaledToNotUse) UsedConsumable = true; await bhReference.AttackWithItem(v, currentConsumable, consumableUser, consumableTarget, (consumableTarget is Ally || consumableTarget is Player), consumableTarget is Enemy); } // When the user is the player or ally they can select one enemy to receive the damage else { SwitchIndicatorsOfSide(false, true, true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchIndicatorsOfSide(false, true, false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); if (!consumableSignaledToNotUse) UsedConsumable = true; await bhReference.AttackWithItem(v, currentConsumable, consumableUser, consumableTarget); } } else { // Enemy will use a damaging item on only the companion side if it affects all if (currentConsumable.EffectAllType) { if (!consumableSignaledToNotUse) UsedConsumable = true; await bhReference.AttackWithItem(v, currentConsumable, consumableUser, null, true, false); } // Enemy will target a random companion and attack with the consumable else { if (!consumableSignaledToNotUse) UsedConsumable = true; await bhReference.AttackWithItem(v, currentConsumable, consumableUser, ChooseRandomTargetForEnemy()); } } if (isEndOfConsumable) GarbageCleanUp(); } /// <summary> /// Heals either a single entity, all of a side, or all entities on screen /// </summary> private async void ActivateHealCon(bool isEndOfConsumable = true) { string consumeName = currentConsumable.ItemName; if (consumeName.Equals("Replenishment Concoction") || consumeName.Equals("Replenishment Potion")) { SwitchIndicatorsOfSide(true, false, true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchIndicatorsOfSide(true, false, false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); int healValue = 1; if (consumeName.Equals("Replenishment Concoction")) healValue = (int)(consumableTarget.RetrieveMaxHealth() * .25f); else if (consumeName.Equals("Replenishment Potion")) healValue = (int)(consumableTarget.RetrieveMaxHealth() * .5f); if (consumableTarget.HasDied) consumableTarget.Revive(false, healValue); else consumableTarget.IncreaseHealth(healValue); consumableTarget.StatusChanged(); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, healValue); bhReference.DisablePlayerTurn(); return; } int healAmount = UtilityHandler.RollValueWithBase(currentConsumable.BaseValue, currentConsumable.HealChance.ToArray()); // Heals all entities on screen currently if (currentConsumable.EffectAll) { IncreaseHealthOfEntities(true, true, healAmount); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), null, currentConsumable, Target.Targetted.All, healAmount); bhReference.DisablePlayerTurn(); } // Player Healing Consumable Usage with companions if (consumableUser is Player || consumableUser is Ally) { // Heals all of a single side if (currentConsumable.EffectAllType) { SwitchAllIndicatorTargets(true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchAllIndicatorTargets(false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); if (consumableTarget is Enemy) // Heals Right (Enemies) IncreaseHealthOfEntities(false, true, healAmount); else // Heals Left (Companions) IncreaseHealthOfEntities(true, false, healAmount); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.AllOfType, healAmount); bhReference.DisablePlayerTurn(); } // Heals single target else { SwitchIndicatorsOfSide(true, false, true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchIndicatorsOfSide(true, false, false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); consumableTarget.IncreaseHealth(AbilityBrain.ConsumableChecks(consumableUser, consumableTarget, healAmount, signals)); consumableTarget.StatusChanged(); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, healAmount); bhReference.DisablePlayerTurn(); } } // Enemy Healing Consumable Usage else { if (currentConsumable.EffectAllType) { IncreaseHealthOfEntities(false, true, healAmount); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.AllOfType, healAmount); } else { consumableTarget = PickMostDamagedEnemy(); consumableTarget.IncreaseHealth(healAmount); consumableTarget.StatusChanged(); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, healAmount); } } if (isEndOfConsumable) GarbageCleanUp(); } /// <summary> /// Picks the most damaged enemy from the containers available, if all are healthy then randomly selects one /// </summary> /// <returns>The most damaged enemy or a random enemy</returns> private Enemy PickMostDamagedEnemy() { Enemy output = null; Enemy[] damagedEnemies = enemyRetainers .Where(e => e.RetrieveHealth() < e.RetrieveMaxHealth()) .ToArray(); if (damagedEnemies.Length is 0) output = enemyRetainers[UnityEngine.Random.Range(0, enemyRetainers.Length)]; // Cycles through all of the damaged enemies for the most damaged // If two enemies have the same health than a coin flip for the place // holder of being held is essentially held foreach (Enemy enemy in damagedEnemies) { if (output == null) { output = enemy; continue; } // Percentages are taken since there is variability between health if (output.GetHealthPercentage() > enemy.GetHealthPercentage()) output = enemy; else if (output.GetHealthPercentage() == enemy.GetHealthPercentage()) { int randomChoice = UnityEngine.Random.Range(0 , MaxChance + 1); if (randomChoice > MaxChance / 2) output = enemy; } } return output; } /// <summary> /// Function to refill mana of the individuals indicated via the consumable item and target functionalities /// </summary> private async void ActivateRefillCon(bool isEndOfConsumable = true) { int refillAmount = UtilityHandler.RollValueWithBase(currentConsumable.BaseValue, currentConsumable.RefillChance.ToArray()); // Refills mana of all entites on screen currently if (currentConsumable.EffectAll) { IncreaseManaOfEntities(true, true, refillAmount); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), null, currentConsumable, Target.Targetted.All, refillAmount); bhReference.DisablePlayerTurn(); } // Mana refill with companions if (consumableUser is Player || consumableUser is Ally) { if (currentConsumable.EffectAllType) { SwitchAllIndicatorTargets(true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchAllIndicatorTargets(false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); if (consumableTarget is Enemy) IncreaseManaOfEntities(false, true, refillAmount); else IncreaseManaOfEntities(true, false, refillAmount); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.AllOfType, refillAmount); bhReference.DisablePlayerTurn(); } else { SwitchIndicatorsOfSide(true, false, true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchIndicatorsOfSide(true, false, false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); consumableTarget.IncreaseMana(refillAmount); consumableTarget.StatusChanged(); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, refillAmount); bhReference.DisablePlayerTurn(); } } else { if (currentConsumable.EffectAllType) { IncreaseManaOfEntities(false, true, refillAmount); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.AllOfType, refillAmount); } else { consumableTarget = PickMostExhaustedEnemy(); consumableTarget.IncreaseMana(refillAmount); consumableTarget.StatusChanged(); if (!consumableSignaledToNotUse) UsedConsumable = true; bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, refillAmount); } } GarbageCleanUp(); } /// <summary> /// Pick the enemy with the least mana percentage wise /// </summary> /// <returns>Most exhausted enemy</returns> private Enemy PickMostExhaustedEnemy() { Enemy output = null; // Chooses enemies that have less than their max mana, also specifies that the enemies should have mana to begin with Enemy[] exhaustedEnemies = enemyRetainers .Where(e => e.RetrieveMana() < e.RetrieveMaxMana() && e.RetrieveMaxMana() is not 0) .ToArray(); if (exhaustedEnemies.Length is 0) output = enemyRetainers[UnityEngine.Random.Range(0, enemyRetainers.Length)]; // Cycles through all of the enemies with lower mana than the max mana // of the enemy to retrieve the most exhausted enemy for the mana item foreach (Enemy enemy in exhaustedEnemies) { if (output == null) { output = enemy; continue; } if (output.GetManaPercentage() > enemy.GetManaPercentage()) output = enemy; else if (output.GetManaPercentage() == enemy.GetManaPercentage()) { int randomChoice = UnityEngine.Random.Range(0 , MaxChance + 1); if (randomChoice > MaxChance / 2) output = enemy; } } return output; } /// <summary> /// Buff Modifier addition logic /// </summary> private async void ActivateBuffCon(bool isEndOfConsumable = true) { if (currentConsumable.EffectAll) { if (!consumableSignaledToNotUse) UsedConsumable = true; ModifierCall(true, true); } if (consumableUser is Ally || consumableUser is Player) { // Activates buffs on the selected side by the player/allies if (currentConsumable.EffectAllType) { SwitchAllIndicatorTargets(true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchAllIndicatorTargets(false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); if (!consumableSignaledToNotUse) UsedConsumable = true; ModifierCall(consumableTarget is Ally || consumableTarget is Player, consumableTarget is Enemy); } // Activates singular buff on the selected target else { SwitchIndicatorsOfSide(true, false, true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchIndicatorsOfSide(true, false, false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); if (!consumableSignaledToNotUse) UsedConsumable = true; ModifierCall(); } } else { // Always buffs the enemies side when an enemy casts a buff item if (currentConsumable.EffectAllType) { if (!consumableSignaledToNotUse) UsedConsumable = true; ModifierCall(false, true); } // Enemy chooses a random enemy target to buff else { consumableTarget = enemyRetainers[UnityEngine.Random.Range(0, enemyRetainers.Length)]; if (!consumableSignaledToNotUse) UsedConsumable = true; ModifierCall(); } } if (isEndOfConsumable) GarbageCleanUp(); } /// <summary> /// Debuff modifier addition logic /// </summary> private async void ActivateDebuffCon(bool isEndOfConsumable = true) { if (currentConsumable.EffectAll) { if (!consumableSignaledToNotUse) UsedConsumable = true; ModifierCall(true, true); } if (consumableUser is Ally || consumableUser is Player) { // Activates buffs on the selected side by the player/allies if (currentConsumable.EffectAllType) { SwitchAllIndicatorTargets(true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchAllIndicatorTargets(false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); if (!consumableSignaledToNotUse) UsedConsumable = true; ModifierCall(consumableTarget is Ally || consumableTarget is Player, consumableTarget is Enemy); } // Activates singular buff on the selected target else { SwitchIndicatorsOfSide(true, false, true); bhReference.AwaitConsumableChoice(consumableUser); bool trigger = await Awaiter(); SwitchIndicatorsOfSide(true, false, false); if (!trigger) { GarbageCleanUp(); return; } bhReference.GetUIHandler().ResetUI(); UsedConsumable = true; ModifierCall(); } } else { // Always buffs the enemies side when an enemy casts a buff item if (currentConsumable.EffectAllType) { if (!consumableSignaledToNotUse) UsedConsumable = true; ModifierCall(true, false); } // Enemy chooses a random enemy target to buff else { consumableTarget = ChooseRandomTargetForEnemy(); if (!consumableSignaledToNotUse) UsedConsumable = true; ModifierCall(); } } if (isEndOfConsumable) GarbageCleanUp(); } /// <summary> /// Simpler Modifier Call that adds on the modifier taken from the current consumable to the consumable /// target if it is not within the mod list of the entity /// </summary> private void ModifierCall() { bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable); Modifier m = Globals.TurnModifierFromObject(currentConsumable.AcquireModifier()); // Checks that the target doesn't already have the modification within their list if (!consumableTarget.GatherModList().Contains(m)) consumableTarget.AddModToList(m); if (consumableUser is Player || consumableUser is Ally) bhReference.DisablePlayerTurn(); } /// <summary> /// Collective side calls for modifier add-ons /// </summary> /// <param name="left">Condition of the left side indicator if companions are wholly effected</param> /// <param name="right">Condition of the right side indicator if enemies are wholly effected</param> /// <exception cref="DataMisalignedException">Exception is thrown when both left and right show false</exception> private void ModifierCall(bool left, bool right) { Modifier m = Globals.TurnModifierFromObject(currentConsumable.AcquireModifier()); if (!left && !right) throw new DataMisalignedException($"Modifier Call has thrown an exception due to misaligned side information - Modifier --> {m.Name}" + $" - Left Ind {left} - Right Ind {right}"); bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, (left && right) ? Target.Targetted.All : (left || right) ? Target.Targetted.AllOfType : default); if (left) // Adds condition to all companions if not already present { if (playerRetainer != null) { if (!playerRetainer.GatherModList().Contains(m)) playerRetainer.AddModToList(m); } if (allyRetainers != null) { foreach (Ally a in allyRetainers) { if (!a.GatherModList().Contains(m)) a.AddModToList(m); } } } if (right) // Adds condition to all enmemies if not already present { foreach (Enemy e in enemyRetainers) { if (!e.GatherModList().Contains(m)) e.AddModToList(m); } } if (consumableUser is Player || consumableUser is Ally) bhReference.DisablePlayerTurn(); } #pragma warning disable UNT0008 /// <summary> /// Cleans up the unnecessary information from the consumable manager now that the process is complete /// </summary> private void GarbageCleanUp() { currentConsumable = null; consumableUser = null; consumableTarget = null; allyRetainers = null; playerRetainer = null; enemyRetainers = null; if (enemyTargets is not null) { foreach (Target t in enemyTargets) { if (t != null) t.SwitchConsumableIndicationMode(false); } } if (allyTargets is not null) { foreach (Target t in allyTargets) { if (t != null) t.SwitchConsumableIndicationMode(false); } } playerTarget?.SwitchConsumableIndicationMode(false); enemyTargets = null; allyTargets = null; playerTarget = null; chosenTarget = null; } #pragma warning restore UNT0008 /// <summary> /// Public reset call for button in consumable selection fields and stops all consumable tasks /// </summary> public void Cancel() { StopConsumableTasks(); GarbageCleanUp(); } /// <summary> /// Consumable Awaiter for item selection for players and allies that has a cancelling component /// </summary> /// <returns>Completed Task once a target has been chosen</returns> private async Task<bool> Awaiter() { while (chosenTarget == null) { // Cancel call if the task cancel is switched to true while trying to select a target if (consumableTaskCancel) return false; await Task.Yield(); } return true; } /// <summary> /// Switches all of the targets to a designated status for the arrow indicators to disappear and appear /// </summary> /// <param name="status">The condition of the indicator status</param> private void SwitchAllIndicatorTargets(bool status) { playerTarget?.SwitchConsumableIndicationMode(status); foreach (Target target in enemyTargets) target.SwitchConsumableIndicationMode(status); if (allyTargets != null) { foreach (Target target in allyTargets) target.SwitchConsumableIndicationMode(status); } } /// <summary> /// Switches a designated sides indicators when necessary /// </summary> /// <param name="left">The companion side indicators</param> /// <param name="right">The enemy side indicators</param> /// <param name="status">The condition of the targets indicators</param> private void SwitchIndicatorsOfSide(bool left, bool right, bool status) { if (left) // Companion side { playerTarget?.SwitchConsumableIndicationMode(status); if (allyTargets != null) { foreach (Target t in allyTargets) t.SwitchConsumableIndicationMode(status); } } else if (right) // Enemy side { foreach (Target t in enemyTargets) t.SwitchConsumableIndicationMode(status); } } /// <summary> /// Handles collective side healing effects, works for type and all targetting /// </summary> /// <param name="left">The companion side targetting indication</param> /// <param name="right">The enemy side targetting indication</param> /// <param name="healAmount">The value that is healing the targets</param> private void IncreaseHealthOfEntities(bool left, bool right, int healAmount) { // The companions side if (left) { playerRetainer?.IncreaseHealth(AbilityBrain.ConsumableChecks(consumableUser, playerRetainer, healAmount, signals)); playerRetainer?.StatusChanged(); if (allyRetainers != null) { foreach (Ally ally in allyRetainers) { ally.IncreaseHealth(AbilityBrain.ConsumableChecks(consumableUser, ally, healAmount, signals)); ally.StatusChanged(); } } } // The enemy side if (right) { foreach (Enemy enemy in enemyRetainers) { enemy.IncreaseHealth(AbilityBrain.ConsumableChecks(consumableUser, enemy, healAmount, signals)); enemy.StatusChanged(); } } } /// <summary> /// Increases mana of all of one side or both sides /// </summary> /// <param name="left">Companion Side</param> /// <param name="right">Enemy Side</param> /// <param name="refillAmount">The amount to refill</param> private void IncreaseManaOfEntities(bool left, bool right, int refillAmount) { // The companions side if (left) { playerRetainer?.IncreaseMana(AbilityBrain.ConsumableChecks(consumableUser, playerRetainer, refillAmount, signals)); playerRetainer?.StatusChanged(); if (allyRetainers != null) { foreach (Ally ally in allyRetainers) { ally.IncreaseMana(AbilityBrain.ConsumableChecks(consumableUser, ally, refillAmount, signals)); ally.StatusChanged(); } } } // The enemy side if (right) { foreach (Enemy enemy in enemyRetainers) { enemy.IncreaseMana(AbilityBrain.ConsumableChecks(consumableUser, enemy, refillAmount, signals)); enemy.StatusChanged(); } } } /// <summary> /// Cycles for an entity that the enemy can target /// </summary> /// <returns>The entity that the enemy wants to target</returns> private Entity ChooseRandomTargetForEnemy() { Entity output = null; const int CutoffMax = 100; if (allyRetainers == null && playerRetainer != null) output = playerRetainer; else if (allyRetainers != null && playerRetainer != null) { int count = allyRetainers.Length; int quo = CutoffMax / (allyRetainers.Length + 1); int v = UnityEngine.Random.Range(1, CutoffMax + 1); switch (count) { case 1: if (v >= quo) output = playerRetainer; else output = allyRetainers[0]; break; case 2: if (v >= quo * count) output = playerRetainer; else if (v >= quo) output = allyRetainers[1]; else output = allyRetainers[0]; break; case 3: if (v >= quo * count) output = playerRetainer; else if (v >= quo * (count - 1)) output = allyRetainers[2]; else if (v >= quo) output = allyRetainers[1]; else output = allyRetainers[0]; break; } } else if (allyRetainers != null && playerRetainer == null) { int count = allyRetainers.Length; int quo = CutoffMax / allyRetainers.Length; int v = UnityEngine.Random.Range(1, CutoffMax + 1); switch (count) { case 1: output = allyRetainers[0]; break; case 2: if (v >= quo) output = allyRetainers[1]; else output = allyRetainers[0]; break; case 3: if (v >= quo * (count - 1)) output = allyRetainers[2]; else if (v >= quo) output = allyRetainers[1]; else output = allyRetainers[0]; break; } } return output; } }