public void CloneAura2() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.MAGE, Player1Deck = new List <Card> { Cards.FromName("Sorcerer's Apprentice"), Cards.FromName("Counterspell") }, Player2HeroClass = CardClass.MAGE, Player2Deck = new List <Card> { Cards.FromName("Sorcerer's Apprentice"), Cards.FromName("Counterspell"), Cards.FromName("Vaporize") }, Shuffle = false, FillDecks = false, History = false, }); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.StartGame(); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Sorcerer's Apprentice")); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Sorcerer's Apprentice")); game.Process(EndTurnTask.Any(game.CurrentPlayer)); Assert.Equal(2, game.Auras.Count); Assert.Equal(2, game.CurrentPlayer.HandZone[0].Cost); Assert.Equal(2, game.CurrentOpponent.HandZone[0].Cost); Assert.Equal(2, game.CurrentOpponent.HandZone[1].Cost); Game clone = game.Clone(); Assert.Equal(2, clone.Auras.Count); Assert.Equal(2, clone.CurrentPlayer.HandZone[0].Cost); Assert.Equal(2, clone.CurrentOpponent.HandZone[0].Cost); Assert.Equal(2, clone.CurrentOpponent.HandZone[1].Cost); clone.Process(MinionAttackTask.Any(clone.CurrentPlayer, clone.CurrentPlayer.BoardZone[0], clone.CurrentOpponent.BoardZone[0])); Assert.Empty(clone.Auras); Assert.Equal(3, clone.CurrentPlayer.HandZone[0].Cost); Assert.Equal(3, clone.CurrentOpponent.HandZone[0].Cost); Assert.Equal(3, clone.CurrentOpponent.HandZone[1].Cost); }
/// <summary> /// Plays a card that matches the provided name. Returns the created <see cref="IPlayable"/> object from the card. /// If you play a minion, the minion's position will be the rightmost position on the board. /// </summary> /// <returns>The created entity object from the card.</returns> public static IPlayable ProcessCard(this Game game, string cardName, IPlayable target = null, bool asZeroCost = false, int chooseOne = 0) { IPlayable entity = Generic.DrawCard(game.CurrentPlayer, Cards.FromName(cardName)); if (asZeroCost) { entity.Cost = 0; } game.DeathProcessingAndAuraUpdate(); game.Process(PlayCardTask.Any(game.CurrentPlayer, entity, target, chooseOne: chooseOne)); return(entity); }
public static void ChangeEntityCostEnchantment() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.ROGUE, Player2HeroClass = CardClass.MAGE, FillDecks = true }); game.StartGame(); game.Player1.BaseMana = 10; Assert.Equal(4, game.CurrentPlayer.HandZone.Count); game.ProcessCard("Swashburglar"); game.ProcessCard("Swashburglar"); game.ProcessCard("Swashburglar"); game.ProcessCard("Swashburglar"); game.ProcessCard("Swashburglar"); int[] costs = game.CurrentPlayer.HandZone.Skip(4).Select(p => p.Cost).ToArray(); game.ProcessCard("Ethereal Peddler", asZeroCost: true); for (int i = 0; i < costs.Length; i++) { if (costs[i] > 2) { costs[i] -= 2; } else { costs[i] = 0; } } // Cost -2 enchantments are applied to all the opponent-class cards in the hand. Assert.Equal(costs, game.CurrentPlayer.HandZone.Skip(4).Select(p => p.Cost)); // Play Golden Kobold to ChangeEntity the whole hand. //game.ProcessCard("Golden Kobold", asZeroCost: true); var kobold = Generic.DrawCard(game.CurrentPlayer, Cards.FromId("LOOT_998k")); kobold.Cost = 0; game.Process(PlayCardTask.Any(game.CurrentPlayer, kobold)); Assert.True(game.CurrentPlayer.HandZone.ToList() .TrueForAll(p => p.Card.Rarity == Rarity.LEGENDARY && p.Card.Type == CardType.MINION)); // Test if the cost enchantment remains as it is. Assert.True(game.CurrentPlayer.HandZone.Skip(4).ToList() .TrueForAll(p => p.Cost == (p.Card.Cost - 2 > 0 ? p.Card.Cost - 2 : 0))); }
public static void AuraTimingTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.PALADIN, Player2HeroClass = CardClass.HUNTER, Player1Deck = new List <Card> { Cards.FromName("Stormwind Champion") }, Player2Deck = new List <Card> { Cards.FromName("Fiery Bat") }, FillDecks = false, Shuffle = false }); game.Player1.BaseMana = 10; game.StartGame(); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Stormwind Champion")); game.CurrentPlayer.BoardZone[0].Damage = 4; game.Process(HeroPowerTask.Any(game.CurrentPlayer)); Assert.Equal(2, game.CurrentPlayer.BoardZone[1].Health); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Fiery Bat")); game.CurrentPlayer.BoardZone[0].IsExhausted = false; while (true) { Game clone = game.Clone(); Assert.Equal(2, clone.CurrentOpponent.BoardZone[1].Health); clone.Process(MinionAttackTask.Any(clone.CurrentPlayer, clone.CurrentPlayer.BoardZone[0], clone.CurrentOpponent.BoardZone[0])); if (clone.CurrentOpponent.Hero.Damage == 7) { continue; } Assert.Equal(1, clone.CurrentOpponent.BoardZone.Count); Assert.Equal(1, clone.CurrentOpponent.BoardZone[0].AttackDamage); Assert.Equal(1, clone.CurrentOpponent.BoardZone[0].Health); break; } }
public void CloneSameState() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.SHAMAN, Player2HeroClass = CardClass.SHAMAN, FillDecks = true, History = false, Logging = false }); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.StartGame(); Game clone = game.Clone(); Assert.Equal(game.Hash(), clone.Hash()); SabberStoneCore.Model.Entities.IPlayable spell1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Lightning Bolt")); SabberStoneCore.Model.Entities.IPlayable minion1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Stonetusk Boar")); SabberStoneCore.Model.Entities.IPlayable spell2 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Lightning Bolt")); SabberStoneCore.Model.Entities.IPlayable cSpell1 = Generic.DrawCard(clone.CurrentPlayer, Cards.FromName("Lightning Bolt")); SabberStoneCore.Model.Entities.IPlayable cSpell2 = Generic.DrawCard(clone.CurrentPlayer, Cards.FromName("Lightning Bolt")); SabberStoneCore.Model.Entities.IPlayable cMinion1 = Generic.DrawCard(clone.CurrentPlayer, Cards.FromName("Stonetusk Boar")); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, spell1, game.CurrentOpponent.Hero)); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, spell2, game.CurrentOpponent.Hero)); game.Process(PlayCardTask.Any(game.CurrentPlayer, minion1)); clone.Process(PlayCardTask.Any(clone.CurrentPlayer, cMinion1)); clone.Process(PlayCardTask.SpellTarget(clone.CurrentPlayer, cSpell2, clone.CurrentOpponent.Hero)); clone.Process(PlayCardTask.SpellTarget(clone.CurrentPlayer, cSpell1, clone.CurrentOpponent.Hero)); GameTag[] ignored = new GameTag[] { GameTag.LAST_CARD_PLAYED, GameTag.ENTITY_ID }; string gameHash = game.Hash(ignored); string cloneHash = clone.Hash(ignored); Assert.Equal(gameHash, cloneHash); }
/// <summary> /// Plays a card that matches the provided name. Returns the created entity as the given type. /// If you play a minion, the minion's position will be the rightmost position on the board. /// </summary> /// <returns>The created entity object from the card.</returns> public static T ProcessCard <T>(this Game game, string cardName, IPlayable target = null, bool asZeroCost = false, int chooseOne = 0) where T : IPlayable { IPlayable entity = Generic.DrawCard(game.CurrentPlayer, Cards.FromName(cardName)); if (!(entity is T t)) { throw new ArgumentException($"The given card is not {typeof(T)}"); } if (asZeroCost) { entity.Cost = 0; } game.DeathProcessingAndAuraUpdate(); game.Process(PlayCardTask.Any(game.CurrentPlayer, t, target, chooseOne: chooseOne)); return(t); }
public static void EnchantAuraTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.ROGUE, Player1Deck = new List <Card> { Cards.FromName("Preparation"), Cards.FromName("Preparation"), Cards.FromName("SI:7 Agent"), Cards.FromName("Sorcerer's Apprentice"), Cards.FromName("Sorcerer's Apprentice"), Cards.FromName("Backstab") }, FillDecks = false, Shuffle = false }); game.Player1.BaseMana = 10; game.StartGame(); Generic.Draw(game.CurrentPlayer); Generic.Draw(game.CurrentPlayer); IPlayable eviscerate1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Eviscerate")); IPlayable eviscerate2 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Eviscerate")); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Sorcerer's Apprentice")); Assert.Equal(1, eviscerate1.Cost); Assert.Equal(1, eviscerate2.Cost); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Preparation")); Assert.Equal(0, eviscerate1.Cost); Assert.Equal(0, eviscerate2.Cost); game.Process(PlayCardTask.Any(game.CurrentPlayer, eviscerate1, game.CurrentPlayer.BoardZone[0])); Assert.Equal(2, eviscerate2.Cost); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Sorcerer's Apprentice")); Assert.Equal(1, eviscerate2.Cost); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Preparation")); Assert.Equal(0, eviscerate2.Cost); game.Process(PlayCardTask.Any(game.CurrentPlayer, "SI:7 Agent", game.CurrentPlayer.BoardZone[0])); Assert.Equal(0, eviscerate2.Cost); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Backstab", game.CurrentPlayer.BoardZone[0])); Assert.Equal(2, eviscerate2.Cost); }
/// <summary> /// Plays the provided entity as current player of the game. /// If you play a minion, the minion's position will be the rightmost position on the board. /// </summary> public static IPlayable ProcessCard(this Game game, IPlayable entity, IPlayable target = null, bool asZeroCost = false, int chooseOne = 0, int zonePosition = -1) { if (target != null && !(target is ICharacter)) { throw new ArgumentException($"Can't target non-charater entity {target}"); } if (asZeroCost) { entity.Cost = 0; } game.DeathProcessingAndAuraUpdate(); var option = PlayCardTask.Any(game.CurrentPlayer, entity, (ICharacter)target, zonePosition, chooseOne); if (!game.Process(option)) { throw new Exception($"{option} is not a valid task."); } return(entity); }
public static void CardsTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.WARLOCK, Player1Deck = new List <Card>() { Cards.FromName("Bloodreaver Gul'dan") }, Player2HeroClass = CardClass.MAGE, Shuffle = false, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer, game.CurrentOpponent.Hero)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer, game.CurrentOpponent.Hero)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Bloodreaver Gul'dan")); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer, game.CurrentOpponent.Hero)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); ShowLog(game, LogLevel.VERBOSE); //Console.WriteLine(game.CurrentPlayer.BoardZone.FullPrint()); //Console.WriteLine(game.CurrentPlayer.HandZone.FullPrint()); //Console.WriteLine(game.CurrentPlayer.DeckZone.FullPrint()); }
public void AfterCastTriggerTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.PRIEST, Player1Deck = new List <Card> { Cards.FromName("Violet Teacher"), Cards.FromName("Wisp"), Cards.FromName("Wisp"), Cards.FromName("Mindgames"), }, Player2HeroClass = CardClass.PALADIN, Player2Deck = new List <Card> { Cards.FromName("Wisp"), Cards.FromName("Wisp"), Cards.FromName("Wisp"), Cards.FromName("Wisp"), Cards.FromName("Wild Pyromancer") }, Shuffle = false, FillDecks = false, }); game.StartGame(); game.Player1.BaseMana = 10; Assert.Equal(1, game.CurrentOpponent.DeckZone.Count); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Violet Teacher")); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Wisp")); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Wisp")); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Mindgames")); Assert.Equal(5, game.CurrentPlayer.BoardZone.Count); Assert.Equal(game.CurrentPlayer.BoardZone[0].Card.Health, game.CurrentPlayer.BoardZone[0].Health); }
public void CloneSameState() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.SHAMAN, Player2HeroClass = CardClass.SHAMAN, FillDecks = true }); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.StartGame(); var clone = game.Clone(); Assert.AreEqual(game.Hash(), clone.Hash()); var spell1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Lightning Bolt")); var minion1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Stonetusk Boar")); var spell2 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Lightning Bolt")); var cSpell1 = Generic.DrawCard(clone.CurrentPlayer, Cards.FromName("Lightning Bolt")); var cSpell2 = Generic.DrawCard(clone.CurrentPlayer, Cards.FromName("Lightning Bolt")); var cMinion1 = Generic.DrawCard(clone.CurrentPlayer, Cards.FromName("Stonetusk Boar")); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, spell1, game.CurrentOpponent.Hero)); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, spell2, game.CurrentOpponent.Hero)); game.Process(PlayCardTask.Any(game.CurrentPlayer, minion1)); clone.Process(PlayCardTask.Any(clone.CurrentPlayer, cMinion1)); clone.Process(PlayCardTask.SpellTarget(clone.CurrentPlayer, cSpell2, clone.CurrentOpponent.Hero)); clone.Process(PlayCardTask.SpellTarget(clone.CurrentPlayer, cSpell1, clone.CurrentOpponent.Hero)); var ignored = new GameTag[] { GameTag.LAST_CARD_PLAYED, GameTag.ENTITY_ID }; Assert.AreEqual(game.Hash(ignored), clone.Hash(ignored)); }
public static void CardsTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.PRIEST, Player1Deck = new List <Card>() { Cards.FromName("Silence"), Cards.FromName("Power Word: Shield"), Cards.FromName("Murloc Tinyfin"), Cards.FromName("Power Word: Shield") }, Player2HeroClass = CardClass.PRIEST, Shuffle = false, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.Process(PlayCardTask.Any(game.CurrentPlayer, "Murloc Tinyfin")); Console.WriteLine(((Minion)game.CurrentPlayer.BoardZone[0]).Health); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, "Power Word: Shield", game.CurrentPlayer.BoardZone[0])); Console.WriteLine(((Minion)game.CurrentPlayer.BoardZone[0]).Health); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, "Silence", game.CurrentPlayer.BoardZone[0])); Console.WriteLine(((Minion)game.CurrentPlayer.BoardZone[0]).Health); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, "Power Word: Shield", game.CurrentPlayer.BoardZone[0])); Console.WriteLine(((Minion)game.CurrentPlayer.BoardZone[0]).Health); ShowLog(game, LogLevel.VERBOSE); Console.WriteLine(game.CurrentOpponent.BoardZone.FullPrint()); //Console.WriteLine(game.CurrentPlayer.HandZone.FullPrint()); //Console.WriteLine(game.CurrentPlayer.DeckZone.FullPrint()); }
public static PlayerTask GetPlayerTask(Option option, Game g) { const bool SkipPrePhase = true; Controller c = g.CurrentPlayer; switch (option.Type) { case Choose: return(ChooseTask.Pick(c, option.Choice)); case Concede: return(ConcedeTask.Any(c)); case EndTurn: return(EndTurnTask.Any(c)); case HeroAttack: return(HeroAttackTask.Any(c, GetOpponentTarget(option.TargetPosition), SkipPrePhase)); case Option.Types.PlayerTaskType.HeroPower: return(HeroPowerTask.Any(c, GetTarget(option.TargetPosition), option.SubOption, SkipPrePhase)); case MinionAttack: return(MinionAttackTask.Any(c, c.BoardZone[option.SourcePosition - 1], GetOpponentTarget(option.TargetPosition), SkipPrePhase)); case PlayCard: IPlayable source = c.HandZone[option.SourcePosition]; if (source.Card.Type == CardType.MINION) { return(PlayCardTask.Any(c, source, null, option.TargetPosition - 1, option.SubOption, SkipPrePhase)); } else { return(PlayCardTask.Any(c, source, GetTarget(option.TargetPosition), 0, option.SubOption, SkipPrePhase)); } default: throw new ArgumentOutOfRangeException(); } ICharacter GetOpponentTarget(int position) { if (position == Option.OP_HERO_POSITION) { return(c.Opponent.Hero); } return(c.Opponent.BoardZone[position - 9]); } ICharacter GetTarget(int position) { if (position == -1) { return(null); } if (position >= Option.OP_HERO_POSITION) { return(GetOpponentTarget(position)); } if (position == Option.HERO_POSITION) { return(c.Hero); } return(c.BoardZone[position - 1]); } }
public PlayerTask ProcessPowerOptionsData(int sendOptionId, int sendOptionMainOption, int sendOptionTarget, int sendOptionPosition, int sendOptionSubOption) { var allOptions = _game.AllOptionsMap[sendOptionId]; var tasks = allOptions.PlayerTaskList; var powerOption = allOptions.PowerOptionList[sendOptionMainOption]; var optionType = powerOption.OptionType; PlayerTask task = null; switch (optionType) { case OptionType.END_TURN: task = EndTurnTask.Any(_game.CurrentPlayer); break; case OptionType.POWER: var mainOption = powerOption.MainOption; var source = _game.IdEntityDic[mainOption.EntityId]; var target = sendOptionTarget > 0 ? (ICharacter)_game.IdEntityDic[sendOptionTarget] : null; var subObtions = powerOption.SubOptions; if (source.Zone?.Type == Zone.PLAY) { task = MinionAttackTask.Any(_game.CurrentPlayer, source, target); } else { switch (source.Card.Type) { case CardType.HERO: if (target != null) { task = HeroAttackTask.Any(_game.CurrentPlayer, target); } else { task = PlayCardTask.Any(_game.CurrentPlayer, source); } break; case CardType.HERO_POWER: task = HeroPowerTask.Any(_game.CurrentPlayer, target); break; default: task = PlayCardTask.Any(_game.CurrentPlayer, source, target, sendOptionPosition, sendOptionSubOption); break; } } break; case OptionType.PASS: break; default: throw new NotImplementedException(); } return(task); }
public static PlayerTask KettleOptionToPlayerTask(Game Game, int sendOptionId, int sendOptionMainOption, int sendOptionTarget, int sendOptionPosition, int sendOptionSubOption) { SabberStoneCore.Kettle.PowerAllOptions allOptions = Game.AllOptionsMap[sendOptionId]; Console.WriteLine(allOptions.Print()); List <PlayerTask> tasks = allOptions.PlayerTaskList; SabberStoneCore.Kettle.PowerOption powerOption = allOptions.PowerOptionList[sendOptionMainOption]; OptionType optionType = powerOption.OptionType; PlayerTask task = null; switch (optionType) { case OptionType.END_TURN: task = EndTurnTask.Any(Game.CurrentPlayer); break; case OptionType.POWER: SabberStoneCore.Kettle.PowerSubOption mainOption = powerOption.MainOption; IPlayable source = Game.IdEntityDic[mainOption.EntityId]; IPlayable target = sendOptionTarget > 0 ? Game.IdEntityDic[sendOptionTarget] : null; List <SabberStoneCore.Kettle.PowerSubOption> subObtions = powerOption.SubOptions; if (source.Zone?.Type == Zone.PLAY) { task = MinionAttackTask.Any(Game.CurrentPlayer, source, target); } else { switch (source.Card.Type) { case CardType.HERO: if (target != null) { task = HeroAttackTask.Any(Game.CurrentPlayer, target); } else { task = PlayCardTask.Any(Game.CurrentPlayer, source); } break; case CardType.HERO_POWER: task = HeroPowerTask.Any(Game.CurrentPlayer, target); break; default: task = PlayCardTask.Any(Game.CurrentPlayer, source, target, sendOptionPosition, sendOptionSubOption); break; } } break; case OptionType.PASS: break; default: throw new NotImplementedException(); } return(task); }
/// <summary> /// Returns a set of all options this player can perform execute at the moment. /// From this set one option is picked and executed by the game. /// </summary> /// <param name="playCards"></param> /// <returns></returns> public List <PlayerTask> Options(bool playCards = true) { var result = new List <PlayerTask>(); if (this != Game.CurrentPlayer) { return(result); } if (Choice != null) { switch (Choice.ChoiceType) { case ChoiceType.GENERAL: Choice.Choices.ToList().ForEach(p => result.Add(ChooseTask.Pick(this, p))); return(result); case ChoiceType.MULLIGAN: IEnumerable <IEnumerable <int> > choices = Util.GetPowerSet(Choice.Choices); choices.ToList().ForEach(p => result.Add(ChooseTask.Mulligan(this, p.ToList()))); return(result); default: throw new NotImplementedException(); } } // no options till mulligan is done for both players if (Game.Step != Step.MAIN_ACTION) { return(result); } // add end turn task ... result.Add(EndTurnTask.Any(this)); if (playCards) { foreach (IPlayable playableCard in HandZone) { var minion = playableCard as Minion; if (!playableCard.IsPlayableByPlayer) { continue; } List <IPlayable> playables = playableCard.ChooseOne && !Game.CurrentPlayer.ChooseBoth ? playableCard.ChooseOnePlayables.ToList() : new List <IPlayable> { playableCard }; foreach (IPlayable t in playables) { if (!t.IsPlayableByCardReq) { continue; } var targets = t.ValidPlayTargets.ToList(); var subResult = new List <PlayCardTask>(); if (!targets.Any()) { subResult.Add(PlayCardTask.Any(this, playableCard, null, -1, playables.Count == 1 ? 0 : playables.IndexOf(t) + 1)); } subResult.AddRange( targets.Select( target => PlayCardTask.Any(this, playableCard, target, -1, playables.Count == 1 ? 0 : playables.IndexOf(t) + 1))); if (minion != null) { var tempSubResult = new List <PlayCardTask>(); int positions = BoardZone.Count + 1; for (int j = 0; j < positions; j++) { subResult.ForEach(p => { PlayCardTask task = p.Copy(); task.ZonePosition = j; tempSubResult.Add(task); }); } subResult = tempSubResult; } result.AddRange(subResult); } } } foreach (Minion minion in BoardZone) { if (!minion.CanAttack) { continue; } IEnumerable <ICharacter> targets = minion.ValidAttackTargets; targets.ToList().ForEach(p => result.Add(MinionAttackTask.Any(this, minion, p))); } if (Hero.CanAttack) { IEnumerable <ICharacter> targets = Hero.ValidAttackTargets; targets.ToList().ForEach(p => result.Add(HeroAttackTask.Any(this, p))); } if (Hero.Power.IsPlayable) { var targets = Hero.Power.GetValidPlayTargets().ToList(); if (targets.Any()) { targets.ToList().ForEach(p => result.Add(HeroPowerTask.Any(this, p))); } else { result.Add(HeroPowerTask.Any(this)); } } return(result); }