diff --git a/res/cardsfolder/b/broken_dam.txt b/res/cardsfolder/b/broken_dam.txt index 3e846a867c4..aaf860b918e 100644 --- a/res/cardsfolder/b/broken_dam.txt +++ b/res/cardsfolder/b/broken_dam.txt @@ -3,7 +3,6 @@ ManaCost:U Types:Sorcery Text:no text A:SP$ Tap | Cost$ U | TargetMin$ 1 | TargetMax$ 2 | TgtPrompt$ Choose target creature without horsemanship | ValidTgts$ Creature.withoutHorsemanship | SpellDescription$ Tap one or two target creatures without horsemanship. -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/broken_dam.jpg SetInfo:PTK|Common|http://magiccards.info/scans/en/p3k/37.jpg diff --git a/res/cardsfolder/c/crown_of_empires.txt b/res/cardsfolder/c/crown_of_empires.txt index bf0f4e62089..7fdf298aa17 100644 --- a/res/cardsfolder/c/crown_of_empires.txt +++ b/res/cardsfolder/c/crown_of_empires.txt @@ -4,7 +4,7 @@ Types:Artifact Text:no text A:AB$ Tap | Cost$ 3 T | ValidTgts$ Creature | TgtPrompt$ Select target creature | ConditionNotAllM12Empires$ True | SubAbility$ DBControl | SpellDescription$ Tap target creature. Gain control of that creature instead if you control artifacts named Scepter of Empires and Throne of Empires. SVar:DBControl:DB$ GainControl | Defined$ Targeted | ConditionAllM12Empires$ True -SVar:RemAIDeck:True +SVar:RemRandomDeck:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/crown_of_empires.jpg SetInfo:M12|Uncommon|http://magiccards.info/scans/en/m12/203.jpg diff --git a/res/cardsfolder/f/feeling_of_dread.txt b/res/cardsfolder/f/feeling_of_dread.txt index cf084624d5b..d5e146f5f6c 100644 --- a/res/cardsfolder/f/feeling_of_dread.txt +++ b/res/cardsfolder/f/feeling_of_dread.txt @@ -4,7 +4,6 @@ Types:Instant Text:no text K:Flashback 1 U A:SP$ Tap | Cost$ 1 W | ValidTgts$ Creature | TgtPrompt$ Select up to two target creatures | TargetMin$ 0 | TargetMax$ 2 | SpellDescription$ Tap up to two target creatures. -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/feeling_of_dread.jpg SetInfo:ISD|Common|http://magiccards.info/scans/en/isd/14.jpg diff --git a/res/cardsfolder/f/frost_breath.txt b/res/cardsfolder/f/frost_breath.txt index ade946124f9..3f809e90aaa 100644 --- a/res/cardsfolder/f/frost_breath.txt +++ b/res/cardsfolder/f/frost_breath.txt @@ -4,7 +4,6 @@ Types:Instant Text:no text A:SP$ Tap | Cost$ 2 U | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Choose target creature | ValidTgts$ Creature | SubAbility$ TrigPump | SpellDescription$ Tap up to two target creatures. Those creatures don't untap during their controller's next untap step. SVar:TrigPump:DB$Pump | Cost$ 0 | Defined$ Targeted | KW$ HIDDEN This card doesn't untap during your next untap step. | Permanent$ True -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/frost_breath.jpg SetInfo:M12|Common|http://magiccards.info/scans/en/m12/54.jpg diff --git a/res/cardsfolder/f/fulgent_distraction.txt b/res/cardsfolder/f/fulgent_distraction.txt index 45d0964357b..9f9790fa12c 100644 --- a/res/cardsfolder/f/fulgent_distraction.txt +++ b/res/cardsfolder/f/fulgent_distraction.txt @@ -4,7 +4,6 @@ Types:Instant Text:no text A:SP$ Tap | Cost$ 2 W | ValidTgts$ Creature | TgtPrompt$ Select target creature | TargetMin$ 2 | TargetMax$ 2 | SubAbility$ DBUnattach | SpellDescription$ Choose two target creatures. Tap those creatures, then unattach all Equipment from them. SVar:DBUnattach:DB$ UnattachAll | Defined$ Targeted | UnattachValid$ Equipment -SVar:RemAIDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/fulgent_distraction.jpg SetInfo:SOM|Common|http://magiccards.info/scans/en/som/7.jpg Oracle:Choose two target creatures. Tap those creatures, then unattach all Equipment from them. diff --git a/res/cardsfolder/l/lead_astray.txt b/res/cardsfolder/l/lead_astray.txt index cf735ac894d..88507aecdba 100644 --- a/res/cardsfolder/l/lead_astray.txt +++ b/res/cardsfolder/l/lead_astray.txt @@ -3,7 +3,6 @@ ManaCost:1 W Types:Instant Text:no text A:SP$ Tap | Cost$ 1 W | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Choose target creature | ValidTgts$ Creature | SpellDescription$ Tap up to two target creatures. -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/lead_astray.jpg SetInfo:JUD|Common|http://magiccards.info/scans/en/ju/14.jpg diff --git a/res/cardsfolder/r/repel_the_darkness.txt b/res/cardsfolder/r/repel_the_darkness.txt index d903f67659e..d6be0a19f81 100644 --- a/res/cardsfolder/r/repel_the_darkness.txt +++ b/res/cardsfolder/r/repel_the_darkness.txt @@ -4,7 +4,6 @@ Types:Instant Text:no text A:SP$ Tap | Cost$ 2 W | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Choose target creature | ValidTgts$ Creature | SpellDescription$ Tap up to two target creatures. | SubAbility$ DBDraw SVar:DBDraw:DB$Draw | NumCards$ 1 | SpellDescription$ Draw a card. -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/repel_the_darkness.jpg SetInfo:ROE|Common|http://magiccards.info/scans/en/roe/42.jpg diff --git a/res/cardsfolder/s/scepter_of_empires.txt b/res/cardsfolder/s/scepter_of_empires.txt index 2034e7a2fa6..ff4afbbaf62 100644 --- a/res/cardsfolder/s/scepter_of_empires.txt +++ b/res/cardsfolder/s/scepter_of_empires.txt @@ -4,7 +4,7 @@ Types:Artifact Text:no text A:AB$ DealDamage | Cost$ T | Tgt$ TgtP | NumDmg$ X | References$ X | SpellDescription$ CARDNAME deals 1 damage to target player. It deals 3 damage to that player instead if you control artifacts named Crown of Empires and Throne of Empires. SVar:X:Count$AllM12Empires.3.1 -SVar:RemAIDeck:True +SVar:RemRandomDeck:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/scepter_of_empires.jpg SetInfo:M12|Uncommon|http://magiccards.info/scans/en/m12/216.jpg diff --git a/res/cardsfolder/t/terashis_cry.txt b/res/cardsfolder/t/terashis_cry.txt index 3f00b685574..4f525b80a63 100644 --- a/res/cardsfolder/t/terashis_cry.txt +++ b/res/cardsfolder/t/terashis_cry.txt @@ -3,7 +3,6 @@ ManaCost:3 W Types:Sorcery Arcane Text:no text A:SP$ Tap | Cost$ 3 W | TargetMin$ 0 | TargetMax$ 3 | TgtPrompt$ Choose target creature | ValidTgts$ Creature | SpellDescription$ Tap up to three target creatures. -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/terashis_cry.jpg SetInfo:CHK|Common|http://magiccards.info/scans/en/chk/47.jpg diff --git a/res/cardsfolder/t/tidal_surge.txt b/res/cardsfolder/t/tidal_surge.txt index 85f2651bdd5..806349cb27a 100644 --- a/res/cardsfolder/t/tidal_surge.txt +++ b/res/cardsfolder/t/tidal_surge.txt @@ -3,7 +3,6 @@ ManaCost:1 U Types:Sorcery Text:no text A:SP$ Tap | Cost$ 1 U | TargetMin$ 0 | TargetMax$ 3 | TgtPrompt$ Choose target creature without flying | ValidTgts$ Creature.withoutFlying | SpellDescription$ Tap up to three target creatures without flying. -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/tidal_surge.jpg SetInfo:PO2|Common|http://magiccards.info/scans/en/po2/56.jpg diff --git a/res/cardsfolder/w/winter_blast.txt b/res/cardsfolder/w/winter_blast.txt index 736b0102abc..ecc48d129b5 100644 --- a/res/cardsfolder/w/winter_blast.txt +++ b/res/cardsfolder/w/winter_blast.txt @@ -6,7 +6,6 @@ A:SP$ Tap | Cost$ X G | ValidTgts$ Creature | TgtPrompt$ Select target creature SVar:DBDamage:DB$ DamageAll | NumDmg$ 2 | ValidCards$ Remembered.withFlying | SpellDescription$ CARDNAME deals 2 damage to each of those creatures with flying. SVar:X:Targeted$Amount SVar:MaxTgts:Count$Valid Creature -SVar:RemAIDeck:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/winter_blast.jpg SetInfo:5ED|Uncommon|http://magiccards.info/scans/en/5e/205.jpg diff --git a/res/cardsfolder/w/word_of_binding.txt b/res/cardsfolder/w/word_of_binding.txt index e7804cbe31d..84e48342547 100644 --- a/res/cardsfolder/w/word_of_binding.txt +++ b/res/cardsfolder/w/word_of_binding.txt @@ -6,7 +6,6 @@ A:SP$ Tap | Cost$ X B B | TargetMin$ 0 | TargetMax$ MaxTgts | References$ X,MaxT # It may seem wrong to not use X in the target, but since the Targets are what defines X, it's redundant (and not supported by the code) SVar:X:Targeted$Amount SVar:MaxTgts:Count$Valid Creature -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/word_of_binding.jpg SetInfo:DRK|Common|http://magiccards.info/scans/en/dk/17.jpg diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryPermanentState.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryPermanentState.java index f14b282f6f1..9e55b3fd3f0 100644 --- a/src/main/java/forge/card/abilityfactory/AbilityFactoryPermanentState.java +++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryPermanentState.java @@ -36,9 +36,12 @@ import forge.card.spellability.AbilitySub; import forge.card.spellability.Spell; import forge.card.spellability.SpellAbility; import forge.card.spellability.Target; +import forge.game.phase.Combat; +import forge.game.phase.CombatUtil; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.ComputerUtil; +import forge.game.player.ComputerUtilBlock; import forge.game.player.Player; import forge.game.zone.ZoneType; import forge.gui.GuiUtils; @@ -352,7 +355,6 @@ public class AbilityFactoryPermanentState { * @return a boolean. */ private static boolean untapPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa) { - // AI cannot use this properly until he can use SAs during Humans turn final Target tgt = sa.getTarget(); boolean randomReturn = true; @@ -852,8 +854,6 @@ public class AbilityFactoryPermanentState { * @return a boolean. */ private static boolean tapCanPlayAI(final AbilityFactory af, final SpellAbility sa) { - // AI cannot use this properly until he can use SAs during Humans turn - final HashMap params = af.getMapParams(); final Target tgt = sa.getTarget(); final Card source = sa.getSourceCard(); @@ -867,10 +867,11 @@ public class AbilityFactoryPermanentState { if (turn.isHuman()) { // Tap things down if it's Human's turn } else if (phase.inCombat() && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) { - // TODO Tap creatures down if in combat + // Tap creatures down if in combat -- handled in tapPrefTargeting(). + } else if (source.isSorcery()) { + // Cast it if it's a sorcery. } else { - // Generally don't want to tap things during AI turn outside of - // combat + // Generally don't want to tap things with an Instant during AI turn outside of combat return false; } @@ -953,7 +954,6 @@ public class AbilityFactoryPermanentState { * @return a boolean. */ private static boolean tapPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa) { - // AI cannot use this properly until he can use SAs during Humans turn final Target tgt = sa.getTarget(); final Card source = sa.getSourceCard(); @@ -999,8 +999,7 @@ public class AbilityFactoryPermanentState { CardList tapList = AllZone.getHumanPlayer().getCardsIn(ZoneType.Battlefield); tapList = tapList.filter(CardListFilter.UNTAPPED); tapList = tapList.getValidCards(tgt.getValidTgts(), source.getController(), source); - // filter out enchantments and planeswalkers, their tapped state doesn't - // matter. + // filter out enchantments and planeswalkers, their tapped state doesn't matter. final String[] tappablePermanents = { "Creature", "Land", "Artifact" }; tapList = tapList.getValidCards(tappablePermanents, source.getController(), source); tapList = tapList.getTargetableCards(sa); @@ -1019,17 +1018,21 @@ public class AbilityFactoryPermanentState { } return false; } else { - // TODO is this good enough? for up to amounts? + if (!tapCastLessThanMax(source)) { + return false; + } break; } } - if (tapList.getNotType("Creature").size() == 0) { - choice = CardFactoryUtil.getBestCreatureAI(tapList); // if only - // creatures - // take - // the - // best + PhaseHandler phase = Singletons.getModel().getGameState().getPhaseHandler(); + if (phase.inCombat() && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) { + // Tap creatures if in combat during AI's turn. + CardList creatureList = tapList.filter(CardListFilter.CREATURES); + choice = CardFactoryUtil.getBestCreatureAI(creatureList); + } else if (tapList.getNotType("Creature").size() == 0) { + // if only creatures take the best + choice = CardFactoryUtil.getBestCreatureAI(tapList); } else { choice = CardFactoryUtil.getMostExpensivePermanentAI(tapList, sa, false); } @@ -1041,7 +1044,9 @@ public class AbilityFactoryPermanentState { } return false; } else { - // TODO is this good enough? for up to amounts? + if (!tapCastLessThanMax(source)) { + return false; + } break; } } @@ -1053,6 +1058,31 @@ public class AbilityFactoryPermanentState { return true; } + /** + * Is it OK to cast this for less than the Max Targets? + * @param source + */ + private static boolean tapCastLessThanMax(final Card source) { + boolean ret = true; + if (source.getManaCost().countX() > 0) { + // If TargetMax is MaxTgts (i.e., an "X" cost), this is fine because AI is limited by mana available. + } else { + // Otherwise, if life is possibly in danger, then this is fine. + Combat combat = new Combat(); + combat.initiatePossibleDefenders(AllZone.getComputerPlayer()); + CardList attackers = AllZoneUtil.getCreaturesInPlay(AllZone.getHumanPlayer()); + for (Card att : attackers) { + combat.addAttacker(att); + } + combat = ComputerUtilBlock.getBlockers(combat, AllZoneUtil.getCreaturesInPlay(AllZone.getComputerPlayer())); + if (!CombatUtil.lifeInDanger(combat)) { + // Otherwise, return false. Do not play now. + ret = false; + } + } + return ret; + } + /** *

* tapUnpreferredTargeting. @@ -1075,8 +1105,7 @@ public class AbilityFactoryPermanentState { list = list.getValidCards(tgt.getValidTgts(), source.getController(), source); list = list.getTargetableCards(sa); - // filter by enchantments and planeswalkers, their tapped state doesn't - // matter. + // filter by enchantments and planeswalkers, their tapped state doesn't matter. final String[] tappablePermanents = { "Enchantment", "Planeswalker" }; CardList tapList = list.getValidCards(tappablePermanents, source.getController(), source); @@ -1139,17 +1168,16 @@ public class AbilityFactoryPermanentState { } return false; } else { - // TODO is this good enough? for up to amounts? + if (!tapCastLessThanMax(source)) { + return false; + } break; } } if (tapList.getNotType("Creature").size() == 0) { - choice = CardFactoryUtil.getBestCreatureAI(tapList); // if only - // creatures - // take - // the - // best + // if only creatures take the best + choice = CardFactoryUtil.getBestCreatureAI(tapList); } else { choice = CardFactoryUtil.getMostExpensivePermanentAI(tapList, sa, false); } @@ -1161,7 +1189,9 @@ public class AbilityFactoryPermanentState { } return false; } else { - // TODO is this good enough? for up to amounts? + if (!tapCastLessThanMax(source)) { + return false; + } break; } } @@ -2061,8 +2091,6 @@ public class AbilityFactoryPermanentState { * @return a boolean. */ private static boolean tapOrUntapCanPlayAI(final AbilityFactory af, final SpellAbility sa) { - // AI cannot use this properly until he can use SAs during Humans turn - final HashMap params = af.getMapParams(); final Target tgt = sa.getTarget(); final Card source = sa.getSourceCard(); @@ -2152,7 +2180,6 @@ public class AbilityFactoryPermanentState { * @return a boolean. */ private static boolean tapOrUntapPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa) { - // AI cannot use this properly until he can use SAs during Humans turn final Target tgt = sa.getTarget(); final Card source = sa.getSourceCard(); @@ -2499,7 +2526,6 @@ public class AbilityFactoryPermanentState { * @return a boolean. */ private static boolean phasesPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa) { - // AI cannot use this properly until he can use SAs during Humans turn final Target tgt = sa.getTarget(); boolean randomReturn = true;