diff --git a/forge-ai/src/main/java/forge/ai/ability/ConniveAi.java b/forge-ai/src/main/java/forge/ai/ability/ConniveAi.java index 3beb8d09463..dc7abc8cdf0 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ConniveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ConniveAi.java @@ -119,7 +119,7 @@ public class ConniveAi extends SpellAbilityAi { } } return new AiAbilityDecision( - sa.isTargetNumberValid() && !sa.getTargets().isEmpty() ? 100 : 0, + sa.isTargetNumberValid() ? 100 : 0, sa.isTargetNumberValid() ? AiPlayDecision.WillPlay : AiPlayDecision.TargetingFailed ); } diff --git a/forge-ai/src/main/java/forge/ai/ability/ControlExchangeAi.java b/forge-ai/src/main/java/forge/ai/ability/ControlExchangeAi.java index 09faaaee18c..57262dd602a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ControlExchangeAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ControlExchangeAi.java @@ -53,17 +53,15 @@ public class ControlExchangeAi extends SpellAbilityAi { if (mandatory) { return new AiAbilityDecision(100, AiPlayDecision.WillPlay); } - } else { - if (mandatory) { - AiAbilityDecision decision = chkDrawback(sa, aiPlayer); - if (sa.isTargetNumberValid()) { - return new AiAbilityDecision(100, AiPlayDecision.WillPlay); - } - - return decision; - } else { - return canPlay(aiPlayer, sa); + } else if (mandatory) { + AiAbilityDecision decision = chkDrawback(sa, aiPlayer); + if (sa.isTargetNumberValid()) { + return new AiAbilityDecision(100, AiPlayDecision.WillPlay); } + + return decision; + } else { + return canPlay(aiPlayer, sa); } return new AiAbilityDecision(100, AiPlayDecision.WillPlay); } diff --git a/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java b/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java index 407f3e00eb0..e98c6924426 100644 --- a/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java @@ -6,10 +6,10 @@ import forge.game.Game; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardLists; +import forge.game.card.CardUtil; import forge.game.combat.Combat; import forge.game.combat.CombatUtil; import forge.game.keyword.Keyword; -import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; @@ -38,9 +38,6 @@ public class MustBlockAi extends SpellAbilityAi { if (!list.isEmpty()) { final Card blocker = ComputerUtilCard.getBestCreatureAI(list); - if (blocker == null) { - return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi); - } sa.getTargets().add(blocker); return new AiAbilityDecision(100, AiPlayDecision.WillPlay); } @@ -63,11 +60,6 @@ public class MustBlockAi extends SpellAbilityAi { protected AiAbilityDecision doTriggerNoCost(final Player ai, SpellAbility sa, boolean mandatory) { final Card source = sa.getHostCard(); - // only use on creatures that can attack - if (!ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)) { - return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi); - } - Card attacker = source; if (sa.hasParam("DefinedAttacker")) { final List cards = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedAttacker"), sa); @@ -81,13 +73,9 @@ public class MustBlockAi extends SpellAbilityAi { boolean chance = false; if (sa.usesTargeting()) { - final List list = determineGoodBlockers(attacker, ai, ai.getWeakestOpponent(), sa, true, true); - if (list.isEmpty()) { - if (sa.isTargetNumberValid()) { - return new AiAbilityDecision(100, AiPlayDecision.WillPlay); - } else { - return new AiAbilityDecision(0, AiPlayDecision.TargetingFailed); - } + List list = determineGoodBlockers(attacker, ai, ai.getWeakestOpponent(), sa, true, true); + if (list.isEmpty() && mandatory) { + list = CardUtil.getValidCardsToTarget(sa); } final Card blocker = ComputerUtilCard.getBestCreatureAI(list); if (blocker == null) { diff --git a/forge-ai/src/main/java/forge/ai/ability/PhasesAi.java b/forge-ai/src/main/java/forge/ai/ability/PhasesAi.java index 5cdbaafdc06..02ae927180f 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PhasesAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PhasesAi.java @@ -33,10 +33,8 @@ public class PhasesAi extends SpellAbilityAi { final boolean isThreatened = ComputerUtil.predictThreatenedObjects(aiPlayer, null, true).contains(source); if (isThreatened) { return new AiAbilityDecision(100, AiPlayDecision.WillPlay); - } else { - return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi); - } + return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi); } return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi); diff --git a/forge-gui/res/cardsfolder/a/axelrod_gunnarson.txt b/forge-gui/res/cardsfolder/a/axelrod_gunnarson.txt index b1e0d76711c..ce0610e463e 100644 --- a/forge-gui/res/cardsfolder/a/axelrod_gunnarson.txt +++ b/forge-gui/res/cardsfolder/a/axelrod_gunnarson.txt @@ -3,7 +3,7 @@ ManaCost:4 B B R R Types:Legendary Creature Giant PT:5/5 K:Trample -T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.DamagedBy | Execute$ DBGainLife | TriggerDescription$ Whenever a creature dealt damage by CARDNAME this turn dies, you gain 1 life and NICKNAME deals 1 damage to target player or planeswalker. +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.DamagedBy | Execute$ DBGainLife | TriggerDescription$ Whenever a creature dealt damage by CARDNAME this turn dies, you gain 1 life and NICKNAME deals 1 damage to target player or planeswalker. SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1 | SubAbility$ DBDealDamage SVar:DBDealDamage:DB$ DealDamage | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | NumDmg$ 1 DeckHas:Ability$LifeGain diff --git a/forge-gui/res/cardsfolder/b/brudiclad_telchor_engineer.txt b/forge-gui/res/cardsfolder/b/brudiclad_telchor_engineer.txt index bc3b3bbdcfd..62967b12daa 100644 --- a/forge-gui/res/cardsfolder/b/brudiclad_telchor_engineer.txt +++ b/forge-gui/res/cardsfolder/b/brudiclad_telchor_engineer.txt @@ -7,6 +7,6 @@ SVar:PlayMain1:TRUE T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ At the beginning of combat on your turn, create a 2/1 blue Phyrexian Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token. SVar:TrigToken:DB$ Token | TokenScript$ u_2_1_a_phyrexian_myr | SubAbility$ DBClone SVar:DBClone:DB$ Clone | Choices$ Card.token+YouCtrl | ChoiceTitle$ You may choose a token you control | ChoiceOptional$ True | ExcludeChosen$ True | CloneTarget$ Valid Card.token+YouCtrl -DeckHints:Type$Token -DeckHas:Type$Token & Type$Artifact|Myr +DeckHints:Ability$Token +DeckHas:Ability$Token & Type$Artifact|Myr Oracle:Creature tokens you control have haste.\nAt the beginning of combat on your turn, create a 2/1 blue Phyrexian Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token. diff --git a/forge-gui/res/cardsfolder/c/caesar_legions_emperor.txt b/forge-gui/res/cardsfolder/c/caesar_legions_emperor.txt index 7bffc1bd003..e42009cd035 100644 --- a/forge-gui/res/cardsfolder/c/caesar_legions_emperor.txt +++ b/forge-gui/res/cardsfolder/c/caesar_legions_emperor.txt @@ -11,5 +11,5 @@ SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 1 SVar:DBDamage:DB$ DealDamage | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | NumDmg$ X | SpellDescription$ CARDNAME deals damage equal to the number of creature tokens you control to target opponent. SVar:X:Count$Valid Creature.token+YouCtrl DeckHas:Ability$Token|Sacrifice -DeckHints:Type$Token +DeckHints:Ability$Token Oracle:Whenever you attack, you may sacrifice another creature. When you do, choose two —\n• Create two 1/1 red and white Soldier creature tokens with haste that are tapped and attacking.\n• You draw a card and you lose 1 life.\n• Caesar, Legion's Emperor deals damage equal to the number of creature tokens you control to target opponent. diff --git a/forge-gui/res/cardsfolder/c/crisis_of_conscience.txt b/forge-gui/res/cardsfolder/c/crisis_of_conscience.txt index 2b901551689..4269209413e 100644 --- a/forge-gui/res/cardsfolder/c/crisis_of_conscience.txt +++ b/forge-gui/res/cardsfolder/c/crisis_of_conscience.txt @@ -4,5 +4,5 @@ Types:Sorcery A:SP$ Charm | Choices$ DBDestroyAllTokens,DBDestroyAllNonlandNontokenPermanents | CharmNum$ 1 SVar:DBDestroyAllTokens:DB$ DestroyAll | ValidCards$ Card.token | SpellDescription$ Destroy all tokens. SVar:DBDestroyAllNonlandNontokenPermanents:DB$ DestroyAll | ValidCards$ Permanent.nonLand+!token | SpellDescription$ Destroy all nonland, nontoken permanents. -DeckHints:Type$Token +DeckHints:Ability$Token Oracle:Choose one —\n• Destroy all tokens.\n• Destroy all nonland, nontoken permanents. diff --git a/forge-gui/res/cardsfolder/g/grishnakh_brash_instigator.txt b/forge-gui/res/cardsfolder/g/grishnakh_brash_instigator.txt index d3123cc9d83..16869bce724 100644 --- a/forge-gui/res/cardsfolder/g/grishnakh_brash_instigator.txt +++ b/forge-gui/res/cardsfolder/g/grishnakh_brash_instigator.txt @@ -9,5 +9,5 @@ SVar:TrigGainControl:DB$ GainControl | ValidTgts$ Creature.nonLegendary+powerLEX SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:TriggerRemembered$CardPower DeckHas:Ability$Token|Counters & Type$Orc|Army -DeckHints:Type$Token +DeckHints:Ability$Token Oracle:When Grishnákh, Brash Instigator enters, amass Orcs 2. When you do, until end of turn, gain control of target nonlegendary creature an opponent controls with power less than or equal to the amassed Army's power. Untap that creature. It gains haste until end of turn. diff --git a/forge-gui/res/cardsfolder/p/prosperity_tycoon.txt b/forge-gui/res/cardsfolder/p/prosperity_tycoon.txt index 810d7051b69..6ca2cade710 100644 --- a/forge-gui/res/cardsfolder/p/prosperity_tycoon.txt +++ b/forge-gui/res/cardsfolder/p/prosperity_tycoon.txt @@ -7,5 +7,5 @@ SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ r_1_1_mercenary_tappump A:AB$ Pump | Cost$ 2 Sac<1/Card.token/token> | Defined$ Self | KW$ Indestructible | SubAbility$ DBTap | SpellDescription$ CARDNAME gains indestructible until end of turn. Tap it. (Damage and effects that say "destroy" don't destroy it.) SVar:DBTap:DB$ Tap | Defined$ Self DeckHas:Ability$Token|Sacrifice & Type$Mercenary -DeckHints:Type$Token +DeckHints:Ability$Token Oracle:When Prosperity Tycoon enters, create a 1/1 red Mercenary creature token with "{T}: Target creature you control gets +1/+0 until end of turn. Activate only as a sorcery."\n{2}, Sacrifice a token: Prosperity Tycoon gains indestructible until end of turn. Tap it. (Damage and effects that say "destroy" don't destroy it.) diff --git a/forge-gui/res/cardsfolder/s/soul_collector.txt b/forge-gui/res/cardsfolder/s/soul_collector.txt index 61dc9eb60bf..7be64f067d7 100644 --- a/forge-gui/res/cardsfolder/s/soul_collector.txt +++ b/forge-gui/res/cardsfolder/s/soul_collector.txt @@ -4,6 +4,6 @@ Types:Creature Vampire PT:3/4 K:Flying K:Morph:B B B -T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.DamagedBy | Execute$ TrigBounce | TriggerDescription$ Whenever a creature dealt damage by CARDNAME this turn dies, return that card to the battlefield under your control. +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.DamagedBy | Execute$ TrigBounce | TriggerDescription$ Whenever a creature dealt damage by CARDNAME this turn dies, return that card to the battlefield under your control. SVar:TrigBounce:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | Defined$ TriggeredCardLKICopy Oracle:Flying\nWhenever a creature dealt damage by Soul Collector this turn dies, return that card to the battlefield under your control.\nMorph {B}{B}{B} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)