protected void PrintStatusAddedMessage(IFighter fighter, AutoEvadeStatus status) { string andCounterString = status.ShouldCounterAttack ? " and counter" : ""; string output = $"{fighter.DisplayName} will evade{andCounterString} all attacks for {GetDurationString(status)}!"; _output.WriteLine(output); }
public void AutoEvadeStatus_CorrectlyPrintsMessage_WhenAdded([Values(1, 4)] int statusDuration, [Values(true, false)] bool shouldCounter) { AutoEvadeStatus evadeStatus = new AutoEvadeStatus(statusDuration, shouldCounter); StatusMove statusMove = new StatusMove("foo", TargetType.Self, evadeStatus); _humanFighter.SetMove(statusMove, 1); //status move hits _chanceService.PushEventOccurs(true); _humanFighter.SetMove(_runawayMove); _enemy.SetMove(_doNothing); BattleManagerBattleConfiguration config = new BattleManagerBattleConfiguration { ShowIntroAndOutroMessages = false }; _battleManager.Battle(_humanTeam, _enemyTeam, config: config); MockOutputMessage[] outputs = _output.GetOutputs(); Assert.AreEqual(1, outputs.Length); string turnOrTurns = statusDuration == 1 ? "turn" : "turns"; string andCounterString = shouldCounter ? " and counter" : ""; string expectedOutput = $"{_humanFighter.DisplayName} will evade{andCounterString} all attacks for {statusDuration} {turnOrTurns}!\n"; Assert.AreEqual(expectedOutput, outputs[0].Message); }
public override bool AreEqual(Status status) { AutoEvadeStatus evadeStatus = status as AutoEvadeStatus; bool areEqual = evadeStatus != null && evadeStatus.ShouldCounterAttack == ShouldCounterAttack; return(areEqual); }
protected void PrintStatusAddedMessage(object sender, StatusAddedEventArgs e) { Status status = e.Status; IFighter senderAsFighter = sender as IFighter; if (senderAsFighter == null) { throw new InvalidOperationException("BattleManager.PrintStatusAddedMessage() should only subscribe to instances of IFighter"); } CriticalChanceMultiplierStatus criticalChanceStatus = status as CriticalChanceMultiplierStatus; StatMultiplierStatus statMultiplierStatus = status as StatMultiplierStatus; MagicMultiplierStatus magicMultiplierStatus = status as MagicMultiplierStatus; MagicResistanceMultiplierStatus resistanceMultiplierStatus = status as MagicResistanceMultiplierStatus; ReflectStatus reflectStatus = status as ReflectStatus; SpellCostMultiplierStatus spellCostMultiplierStatus = status as SpellCostMultiplierStatus; AutoEvadeStatus autoEvadeStatus = status as AutoEvadeStatus; CounterAttackStatus counterAttackStatus = status as CounterAttackStatus; BlindStatus blindStatus = status as BlindStatus; if (criticalChanceStatus != null) { PrintStatusAddedMessage(senderAsFighter, criticalChanceStatus); } if (statMultiplierStatus != null) { PrintStatusAddedMessage(senderAsFighter, statMultiplierStatus); } if (magicMultiplierStatus != null) { PrintStatusAddedMessage(senderAsFighter, magicMultiplierStatus); } if (resistanceMultiplierStatus != null) { PrintStatusAddedMessage(senderAsFighter, resistanceMultiplierStatus); } if (reflectStatus != null) { PrintStatusAddedMessage(senderAsFighter, reflectStatus); } if (spellCostMultiplierStatus != null) { PrintStatusAddedMessage(senderAsFighter, spellCostMultiplierStatus); } if (autoEvadeStatus != null) { PrintStatusAddedMessage(senderAsFighter, autoEvadeStatus); } if (counterAttackStatus != null) { PrintStatusAddedMessage(senderAsFighter, counterAttackStatus); } if (blindStatus != null) { PrintStatusAddedMessage(senderAsFighter, blindStatus); } }
public void MoveWithNeverMissEffect_CanStillBeEvaded() { _human.SetMove(_attackWithNeverMissEffect, 1); _human.SetMoveTarget(_enemy); _chanceService.PushEventsOccur(false); //just check the crit _human.SetMove(_runawayMove); AutoEvadeStatus autoEvadeStatus = new AutoEvadeStatus(1, false); _enemy.AddStatus(autoEvadeStatus); _enemy.SetMove(_doNothingMove); _battleManager.Battle(_humanTeam, _enemyTeam); Assert.AreEqual(_enemy.MaxHealth, _enemy.CurrentHealth, "Enemy should have evaded the never-miss attack and escaped at full health!"); }
public void MoveWithCannotBeEvadedEffect_HitsOpponentThatEvaded() { CannotBeEvadedBattleMoveEffect cannotBeEvadedEffect = new CannotBeEvadedBattleMoveEffect(); AttackBattleMove noEvadeAttack = new AttackBattleMove("foo", TargetType.SingleEnemy, 100, 10, effects: cannotBeEvadedEffect); _human.SetMove(noEvadeAttack, 1); _human.SetMove(_runawayMove); _human.SetMoveTarget(_enemy); _chanceService.PushAttackHitsNotCrit(); //attack hits, not a crit AutoEvadeStatus autoEvadeStatus = new AutoEvadeStatus(1, false); _enemy.AddStatus(autoEvadeStatus); _enemy.SetMove(_doNothingMove); _enemy.SetHealth(_human.Strength + 1); _battleManager.Battle(_humanTeam, _enemyTeam); Assert.AreEqual(1, _enemy.CurrentHealth, "attack should have hit even though enemy had an AutoEvade status!"); }
public void Setup() { _logger = new EventLogger(); _input = new MockInput(); _output = new MockOutput(); _menuManager = new TestMenuManager(_input, _output); _chanceService = new MockChanceService(); _battleManager = new TestBattleManager(_chanceService, _input, _output); _evadeButDoNotCounterStatus = new AutoEvadeStatus(1, false); _evadeAndCounterStatus = new AutoEvadeStatus(1, true); _humanFighter = new TestHumanFighter("foo", 1); _humanTeam = new TestTeam(_humanFighter); _enemy = (TestEnemyFighter)TestFighterFactory.GetFighter(TestFighterType.TestEnemy, 1); _enemyTeam = new Team(_menuManager, _enemy); _doNothing = new DoNothingMove(); }
private void GetLevel3MoveIndices(out int attackIndex, out int evadeIndex, out int evadeAndCounterIndex, out int attackBoostIndex) { List <BattleMove> availableMoves = _level3Warrior.AvailableMoves; attackIndex = availableMoves.FindIndex(bm => bm.MoveType == BattleMoveType.Attack); evadeIndex = availableMoves.FindIndex(bm => { if (bm.MoveType != BattleMoveType.Status) { return(false); } StatusMove statusMove = bm as StatusMove; AutoEvadeStatus status = statusMove?.Status as AutoEvadeStatus; if (status == null || status.ShouldCounterAttack) { return(false); } return(true); }); evadeAndCounterIndex = availableMoves.FindIndex(bm => { if (bm.MoveType != BattleMoveType.Status) { return(false); } StatusMove statusMove = bm as StatusMove; AutoEvadeStatus status = statusMove?.Status as AutoEvadeStatus; if (status == null || !status.ShouldCounterAttack) { return(false); } return(true); }); attackBoostIndex = availableMoves.FindIndex(bm => bm.MoveType == BattleMoveType.Status && (bm as StatusMove)?.Status is StatMultiplierStatus); }
public void ConditionalEffect_AppropriatelySuppressed_WhenNotEvadedConditionNotMet([Values(10, 20)] int percentage) { AttackBattleMove conditionalHealMove = GetNotEvadeRestoreHealthAttack(percentage); _team1Fighter.SetHealth(100, 10); _team1Fighter.SetMove(conditionalHealMove, 1); _team1Fighter.SetMoveTarget(_team2Fighter); _team1Fighter.SetMove(_runawayMove); _chanceService.PushAttackHitsNotCrit(); AutoEvadeStatus autoEvadeStatus = new AutoEvadeStatus(1, false); _team2Fighter.AddStatus(autoEvadeStatus); _team2Fighter.SetHealth(100); _team2Fighter.SetMove(_doNothingMove); _battleManager.Battle(_team1, _team2); int expectedRemainingHealth = 10; Assert.AreEqual(expectedRemainingHealth, _team1Fighter.CurrentHealth, "The enemy had evade status, so the user should not have regained any HP"); }
public static BattleMove Get(BattleMoveType type, string description = null) { BattleMove ret; var notFoundException = new ArgumentException($"No move exists with type {type} and description '{description}'!"); switch (type) { case BattleMoveType.Attack: switch (description) { case null: case "attack": ret = Attack; break; case "goblin punch": ret = new AttackBattleMove(description, TargetType.SingleEnemy, 100, 75, executionText: $"throws a goblin punch at {Globals.TargetReplaceText}"); break; case "feint": NotEvadedBattleCondition notEvadedCondition = new NotEvadedBattleCondition(); AttackBoostBattleMoveEffect attackBoostEffect = new AttackBoostBattleMoveEffect(0.25, notEvadedCondition); CannotBeEvadedBattleMoveEffect cannotBeEvadedEffect = new CannotBeEvadedBattleMoveEffect(); BattleMoveEffect[] effects = { attackBoostEffect, cannotBeEvadedEffect, UnconditionalNeverMissEffect }; ret = new AttackBattleMove(description, TargetType.SingleEnemy, 100, 0, executionText: "attacks [target] with a feint", effects: effects); break; default: throw notFoundException; } break; case BattleMoveType.ConditionalPowerAttack: ret = new ConditionalPowerAttackBattleMove("malevolence attack", TargetType.SingleEnemy, 100, 10, executionText: "unleashes their dark power!"); break; case BattleMoveType.Runaway: ret = Runaway; break; case BattleMoveType.DoNothing: switch (description) { case null: ret = DoNothing; break; case "goblin punch charge": ret = new DoNothingMove("prepares to unleash its fury"); break; default: throw notFoundException; } break; case BattleMoveType.Special: switch (description) { case "dark energy gather": ret = new SpecialMove(description, BattleMoveType.Special, TargetType.Self, "gathers dark energy"); break; default: throw notFoundException; } break; case BattleMoveType.MultiTurn: if (description == "goblin punch") { ret = new MultiTurnBattleMove(description, TargetType.SingleEnemy, Get(BattleMoveType.DoNothing, "goblin punch charge"), Get(BattleMoveType.Attack, description)); } else { throw notFoundException; } break; case BattleMoveType.Dance: switch (description) { default: throw notFoundException; case "fire dance": ret = new DanceMove(description, TargetType.OwnTeam, 2, DanceEffectType.Fire, new List <FieldEffect> { new MagicMultiplierFieldEffect(TargetType.OwnTeam, "fire dance", MagicType.Fire, (4.0 / 3.0)) }, new DoNothingMove("performs the fire dance"), new DoNothingMove("continues to perform the fire dance")); break; case "water dance": ret = new DanceMove(description, TargetType.OwnTeam, 2, DanceEffectType.Water, new List <FieldEffect> { new MagicMultiplierFieldEffect(TargetType.OwnTeam, "water dance", MagicType.Water, (4.0 / 3.0)) }, new DoNothingMove("performs the water dance"), new DoNothingMove("continues to perform the water dance")); break; case "wind dance": ret = new DanceMove(description, TargetType.OwnTeam, 2, DanceEffectType.Wind, new List <FieldEffect> { new MagicMultiplierFieldEffect(TargetType.OwnTeam, "wind dance", MagicType.Wind, (4.0 / 3.0)) }, new DoNothingMove("performs the wind dance"), new DoNothingMove("continues to perform the wind dance")); break; case "earth dance": ret = new DanceMove(description, TargetType.OwnTeam, 2, DanceEffectType.Earth, new List <FieldEffect> { new MagicMultiplierFieldEffect(TargetType.OwnTeam, "earth dance", MagicType.Earth, (4.0 / 3.0)) }, new DoNothingMove("performs the earth dance"), new DoNothingMove("continues to perform the earth dance")); break; case "heart dance": ret = new DanceMove(description, TargetType.OwnTeam, 2, DanceEffectType.Heart, new List <FieldEffect> { new StatMultiplierFieldEffect(TargetType.OwnTeam, "heart dance", StatType.Defense, (5 / 100.0)) }, new DoNothingMove("performs the heart dance"), new DoNothingMove("continues to perform the heart dance")); break; case "soul dance": ret = new DanceMove(description, TargetType.OwnTeam, 2, DanceEffectType.Soul, new List <FieldEffect> { new MagicMultiplierFieldEffect(TargetType.OwnTeam, "soul dance", MagicType.All, (5 / 100.0)) }, new DoNothingMove("performs the soul dance"), new DoNothingMove("continues to perform the soul dance")); break; case "mind dance": ret = new DanceMove(description, TargetType.OwnTeam, 2, DanceEffectType.Mind, new List <FieldEffect> { new StatMultiplierFieldEffect(TargetType.OwnTeam, "mind dance", StatType.Evade, (5.0 / 100.0), 1) }, new DoNothingMove("performs the mind dance"), new DoNothingMove("continues to perform the mind dance")); break; case "danger dance": ret = new DanceMove(description, TargetType.OwnTeam, 2, DanceEffectType.Danger, new List <FieldEffect> { new StatMultiplierFieldEffect(TargetType.OwnTeam, "danger dance", StatType.Strength, (5.0 / 100.0), 1) }, new DoNothingMove("performs the danger dance"), new DoNothingMove("continues to perform the danger dance")); break; } break; case BattleMoveType.Status: Status status; switch (description) { default: throw notFoundException; case "warrior's cry": status = new StatMultiplierStatus(4, StatType.Strength, 2); ret = new StatusMove(description, TargetType.Self, status, "unleashes their warrior cry!"); break; case "evade": status = new AutoEvadeStatus(1, false); ret = new StatusMove(description, TargetType.Self, status, "takes a ready stance", 1); break; case "evadeAndCounter": status = new AutoEvadeStatus(1, true); ret = new StatusMove(description, TargetType.Self, status, "prepares to counter", 1); break; case "dark fog": status = new BlindStatus(2); ret = new StatusMove(description, TargetType.SingleEnemy, status, $"draws a dark fog about {Globals.TargetReplaceText}", accuracy: 60); break; } break; case BattleMoveType.Shield: switch (description) { case "iron shield": IBattleShield shield = new IronBattleShield(5, 2, 0); ret = new ShieldMove(description, TargetType.SingleAllyOrSelf, "created an iron shield", shield); break; default: throw notFoundException; } break; case BattleMoveType.ShieldFortifier: switch (description) { case "heal shield": ret = new ShieldFortifyingMove(description, TargetType.SingleAllyOrSelf, $"healed {Globals.TargetReplaceText}'s shield", ShieldFortifyingType.Health, 5); break; case "strengthen shield": ret = new ShieldFortifyingMove(description, TargetType.SingleAllyOrSelf, $"strengthened {Globals.TargetReplaceText}'s shield", ShieldFortifyingType.Defense, 5); break; default: ret = null; break; } break; case BattleMoveType.ShieldBuster: if (string.IsNullOrEmpty(description)) { description = "Shield buster"; } switch (description) { case "Shield buster": ret = new ShieldBusterMove(description, TargetType.SingleEnemy, "uses the shield buster on [target]"); break; case "Super shield buster": ret = new ShieldBusterMove(description, TargetType.SingleEnemy, "uses the super shield buster on [target]", 1); break; default: throw notFoundException; } break; case BattleMoveType.BellMove: switch (description) { case "seal shade": default: ret = Get(BellMoveType.SealMove); break; case "control shade": ret = Get(BellMoveType.ControlMove); break; } break; case BattleMoveType.AbsorbShade: ret = new ShadeAbsorbingMove("absorb shade", $"has given into malice, targetting {Globals.TargetReplaceText}!"); break; default: throw notFoundException; } return(ret); }