diff --git a/Assets/Battle/BattleController.cs b/Assets/Battle/BattleController.cs index dc325d4..8c6521e 100644 --- a/Assets/Battle/BattleController.cs +++ b/Assets/Battle/BattleController.cs @@ -4,7 +4,7 @@ using System.Linq; using UnityEngine; using UnityEngine.SceneManagement; -public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffectResolver +public class BattleController : MonoBehaviour, IBattleEffectApplier { private bool STABLE_HAND_STYLE = true; @@ -20,6 +20,7 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe private HandPlayability heroHandPlayability; private HandPlayability monsterHandPlayability; private TurnIntentions monsterIntentions; + private IBattleEffectResolver effectResolver; private delegate void BattleStateChangedAction(); private event BattleStateChangedAction OnBattleStateChanged; @@ -52,6 +53,8 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe this.state.HeroDeck, this.state.MonsterDeck, this.state.PlayArea, this.state.InsightLevel, this.heroHandPlayability, this.monsterHandPlayability, this.monsterIntentions, this.uiCanvas.transform.localScale.x); + + this.effectResolver = new EffectResolver(this.state); } // Start is called before the first frame update @@ -317,184 +320,10 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe } } - private BattleParticipant[] GetTeam(TeamChoice team) { - return (team == TeamChoice.Heroes - ? this.state.Heroes.Cast().ToArray() - : this.state.Monsters.Cast().ToArray()); - } - public BattleState State {get => this.state;} // IBattleEffectApplier public void Apply(IBattleEffect effect) { - effect.Apply(this); - } - - // IBattleEffectResolver - public void DropEmotion(DropEmotionEffect effect) { - if (!this.state.CanPlayEmotion(effect.Team)) { - throw new System.InvalidOperationException("Cannot play emotion"); - } - - this.state.NotifyPlayedEmotion(effect.Team); - EnergyPool pool = (effect.Team == TeamChoice.Heroes ? this.state.HeroEnergy : this.state.MonsterEnergy); - pool.MaxEnergy += effect.Amount; - pool.Energy += effect.Amount; - } - - public void IncreaseHeroMaxEnergy(IncreaseMaxEnergyEffect effect) { - this.state.HeroEnergy.MaxEnergy += effect.Amount; - if (effect.Immediate) { - this.state.HeroEnergy.Energy += effect.Amount; - } - } - - public void IncreaseMaxHP(IncreaseMaxHPEffect effect) { - if (effect.Target == null) return; - effect.Target.IncreaseMaxHP(effect.Amount); - } - - public void ModifyInsight(ModifyInsightEffect effect) { - this.state.InsightLevel.Modify(effect.Amount); - } - - public void DrawCards(DrawCardsEffect effect) { - if (effect.Team == TeamChoice.Heroes) { - for (int i = 0; i < effect.Amount; i++) { - this.state.HeroDeck.DrawCard(); - } - } else { - for (int i = 0; i < effect.Amount; i++) { - this.state.MonsterDeck.DrawCard(); - } - } - } - - public void AcquireCards(AcquireCardsEffect effect) { - if (effect.Participant == null) return; - - if (effect.Participant.Team == TeamChoice.Heroes) { - this.AcquireCardsTyped(effect, this.state.HeroDeck, new HeroCardDatabase()); - } else { - this.AcquireCardsTyped(effect, this.state.MonsterDeck, new MonsterCardDatabase()); - } - } - - private void AcquireCardsTyped( - AcquireCardsEffect effect, - BattleDeck deck, - CardDatabase cardDatabase) - where BaseCardT : BaseCard { - foreach (int cardId in effect.CardIds) { - BaseCardT acquiredCard = cardDatabase.CreateCard(cardId, effect.Participant); - switch (effect.Zone) { - case BattleZone.DrawPile: - deck.PutCardOnTopOfDrawPile(acquiredCard); - break; - case BattleZone.DiscardPile: - deck.MoveCardToDiscard(acquiredCard); - break; - default: - throw new System.NotImplementedException(); - } - } - - if (effect.Zone == BattleZone.DrawPile) { - deck.ShuffleDrawPile(); - } - } - - - public int DealDamage(DealDamageEffect effect) { - if (effect.Target == null) return 0; - - int amount = effect.Amount; - if (effect.Source != null) { - amount += this.state.BuffManager.GetTotalBuffAmountOfType(effect.Source, BuffType.Power); - } - int damageDealt = effect.Target.DealDamage(amount); - this.state.TriggerManager.NotifyResolvedDamageEffect(effect); - - return damageDealt; - } - - public int DealMassDamage(MassDamageEffect effect) { - int damageDealt = 0; - BattleParticipant[] affectedTeam = GetTeam(effect.Team); - foreach (BattleParticipant bp in affectedTeam) { - damageDealt += bp.DealDamage(effect.Amount); - } - this.state.TriggerManager.NotifyResolvedMassDamageEffect(effect); - - return damageDealt; - } - - public int Heal(HealEffect effect) { - if (effect.Target == null) return 0; - - int healedAmount = effect.Target.Heal(effect.Amount); - return healedAmount; - } - - public void AddBlock(BlockEffect effect) { - if (effect.Target == null) return; - effect.Target.AddBlock(effect.Amount); - } - - public void AddMassBlock(MassBlockEffect effect) { - BattleParticipant[] affectedTeam = GetTeam(effect.Team); - foreach (BattleParticipant bp in affectedTeam) { - bp.AddBlock(effect.Amount); - } - } - - public void AddStatus(StatusEffect effect) { - if (effect.Target == null) return; - effect.Target.AddStatus(effect.Status, effect.Amount); - } - - public void BuffParticipant(BuffParticipantEffect effect) { - this.state.BuffManager.AddBuff(effect, this.state.Clock.Now); - } - - public void Rotate(RotateEffect effect) { - if (effect.Positions == 0) return; - - BattleParticipant[] currentPositions = GetTeam(effect.Team); - - int start = int.MaxValue; - int end = int.MinValue; - for (int i = 0; i < currentPositions.Length; i++) { - BattleParticipant bp = currentPositions[i]; - if (bp != null) { - start = System.Math.Min(start, i); - end = System.Math.Max(end, i); - } - } - - int[] newPositions = new int[currentPositions.Length]; - for (int i = start; i <= end; i++) { - if (i < start || i > end) { - newPositions[i] = i; - } else { - int newI = start + MathUtil.TrueMod( - i - start - effect.Positions, - end - start + 1); - newPositions[newI] = i; - } - } - - this.state.MoveTeamToNewPositions(effect.Team, newPositions); - } - - public void SetupDefault(DefaultEffect effect) { - DefaultHeroCard previousDefault = this.state.PlayArea.SetupDefault(effect); - if (previousDefault != null) { - this.state.HeroDeck.MoveCardToDiscard(previousDefault); - } - } - - public void ArmDamageTrigger(DamageTrigger damageTrigger) { - this.state.TriggerManager.ArmDamageTrigger(damageTrigger); + effect.Apply(this.effectResolver); } } diff --git a/Assets/Battle/BattleState.cs b/Assets/Battle/BattleState.cs index bb79c6e..fd5652c 100644 --- a/Assets/Battle/BattleState.cs +++ b/Assets/Battle/BattleState.cs @@ -129,6 +129,12 @@ public class BattleState: MonsterViewpoint if (OnMonsterPositionsSet != null) OnMonsterPositionsSet(); } + public BattleParticipant[] GetTeam(TeamChoice team) { + return (team == TeamChoice.Heroes + ? this.heroes.Cast().ToArray() + : this.monsters.Cast().ToArray()); + } + public BattleHero[] Heroes {get => this.heroes;} public BattleMonster[] Monsters {get => this.monsters;} public BattleClock Clock {get => this.clock;} diff --git a/Assets/Battle/EffectResolver.cs b/Assets/Battle/EffectResolver.cs new file mode 100644 index 0000000..71931d7 --- /dev/null +++ b/Assets/Battle/EffectResolver.cs @@ -0,0 +1,182 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.SceneManagement; + +public class EffectResolver : IBattleEffectResolver +{ + private BattleState state; + + public EffectResolver(BattleState state) { + this.state = state; + } + + // IBattleEffectResolver + public void DropEmotion(DropEmotionEffect effect) { + if (!this.state.CanPlayEmotion(effect.Team)) { + throw new System.InvalidOperationException("Cannot play emotion"); + } + + this.state.NotifyPlayedEmotion(effect.Team); + EnergyPool pool = (effect.Team == TeamChoice.Heroes ? this.state.HeroEnergy : this.state.MonsterEnergy); + pool.MaxEnergy += effect.Amount; + pool.Energy += effect.Amount; + } + + public void IncreaseHeroMaxEnergy(IncreaseMaxEnergyEffect effect) { + this.state.HeroEnergy.MaxEnergy += effect.Amount; + if (effect.Immediate) { + this.state.HeroEnergy.Energy += effect.Amount; + } + } + + public void IncreaseMaxHP(IncreaseMaxHPEffect effect) { + if (effect.Target == null) return; + effect.Target.IncreaseMaxHP(effect.Amount); + } + + public void ModifyInsight(ModifyInsightEffect effect) { + this.state.InsightLevel.Modify(effect.Amount); + } + + public void DrawCards(DrawCardsEffect effect) { + if (effect.Team == TeamChoice.Heroes) { + for (int i = 0; i < effect.Amount; i++) { + this.state.HeroDeck.DrawCard(); + } + } else { + for (int i = 0; i < effect.Amount; i++) { + this.state.MonsterDeck.DrawCard(); + } + } + } + + public void AcquireCards(AcquireCardsEffect effect) { + if (effect.Participant == null) return; + + if (effect.Participant.Team == TeamChoice.Heroes) { + this.AcquireCardsTyped(effect, this.state.HeroDeck, new HeroCardDatabase()); + } else { + this.AcquireCardsTyped(effect, this.state.MonsterDeck, new MonsterCardDatabase()); + } + } + + private void AcquireCardsTyped( + AcquireCardsEffect effect, + BattleDeck deck, + CardDatabase cardDatabase) + where BaseCardT : BaseCard { + foreach (int cardId in effect.CardIds) { + BaseCardT acquiredCard = cardDatabase.CreateCard(cardId, effect.Participant); + switch (effect.Zone) { + case BattleZone.DrawPile: + deck.PutCardOnTopOfDrawPile(acquiredCard); + break; + case BattleZone.DiscardPile: + deck.MoveCardToDiscard(acquiredCard); + break; + default: + throw new System.NotImplementedException(); + } + } + + if (effect.Zone == BattleZone.DrawPile) { + deck.ShuffleDrawPile(); + } + } + + + public int DealDamage(DealDamageEffect effect) { + if (effect.Target == null) return 0; + + int amount = effect.Amount; + if (effect.Source != null) { + amount += this.state.BuffManager.GetTotalBuffAmountOfType(effect.Source, BuffType.Power); + } + int damageDealt = effect.Target.DealDamage(amount); + this.state.TriggerManager.NotifyResolvedDamageEffect(effect); + + return damageDealt; + } + + public int DealMassDamage(MassDamageEffect effect) { + int damageDealt = 0; + BattleParticipant[] affectedTeam = this.state.GetTeam(effect.Team); + foreach (BattleParticipant bp in affectedTeam) { + damageDealt += bp.DealDamage(effect.Amount); + } + this.state.TriggerManager.NotifyResolvedMassDamageEffect(effect); + + return damageDealt; + } + + public int Heal(HealEffect effect) { + if (effect.Target == null) return 0; + + int healedAmount = effect.Target.Heal(effect.Amount); + return healedAmount; + } + + public void AddBlock(BlockEffect effect) { + if (effect.Target == null) return; + effect.Target.AddBlock(effect.Amount); + } + + public void AddMassBlock(MassBlockEffect effect) { + BattleParticipant[] affectedTeam = this.state.GetTeam(effect.Team); + foreach (BattleParticipant bp in affectedTeam) { + bp.AddBlock(effect.Amount); + } + } + + public void AddStatus(StatusEffect effect) { + if (effect.Target == null) return; + effect.Target.AddStatus(effect.Status, effect.Amount); + } + + public void BuffParticipant(BuffParticipantEffect effect) { + this.state.BuffManager.AddBuff(effect, this.state.Clock.Now); + } + + public void Rotate(RotateEffect effect) { + if (effect.Positions == 0) return; + + BattleParticipant[] currentPositions = this.state.GetTeam(effect.Team); + + int start = int.MaxValue; + int end = int.MinValue; + for (int i = 0; i < currentPositions.Length; i++) { + BattleParticipant bp = currentPositions[i]; + if (bp != null) { + start = System.Math.Min(start, i); + end = System.Math.Max(end, i); + } + } + + int[] newPositions = new int[currentPositions.Length]; + for (int i = start; i <= end; i++) { + if (i < start || i > end) { + newPositions[i] = i; + } else { + int newI = start + MathUtil.TrueMod( + i - start - effect.Positions, + end - start + 1); + newPositions[newI] = i; + } + } + + this.state.MoveTeamToNewPositions(effect.Team, newPositions); + } + + public void SetupDefault(DefaultEffect effect) { + DefaultHeroCard previousDefault = this.state.PlayArea.SetupDefault(effect); + if (previousDefault != null) { + this.state.HeroDeck.MoveCardToDiscard(previousDefault); + } + } + + public void ArmDamageTrigger(DamageTrigger damageTrigger) { + this.state.TriggerManager.ArmDamageTrigger(damageTrigger); + } +} diff --git a/Assets/Battle/EffectResolver.cs.meta b/Assets/Battle/EffectResolver.cs.meta new file mode 100644 index 0000000..fb15623 --- /dev/null +++ b/Assets/Battle/EffectResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dce6dd03330d4794faadaef3b88a8720 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TODO.txt b/TODO.txt index 5d95afb..a9e3a3a 100644 --- a/TODO.txt +++ b/TODO.txt @@ -4,7 +4,6 @@ Battle - Show on who enemies will use the cards - Highlight which card is targeting - Allow cancelling targeting -- Extend BattleState object to contain everything for effect resolver to work - Implement a stack/queue to control effects - Make battle work with numbers different than 3 vs 3 - Merge HeroCard and MonsterCard