diff --git a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java index 5358f6e670d..bbe277b07f0 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java @@ -68,7 +68,6 @@ import forge.util.Aggregates; public class ControlGainAi extends SpellAbilityAi { @Override protected boolean canPlayAI(final Player ai, final SpellAbility sa) { - final List lose = Lists.newArrayList(); if (sa.hasParam("LoseControl")) { diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java index 8c2df450d8b..1a8bbc4de42 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java @@ -39,6 +39,7 @@ import forge.game.keyword.Keyword; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; +import forge.game.player.PlayerCollection; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.game.spellability.TargetChoices; @@ -844,7 +845,7 @@ public class DamageDealAi extends DamageAiBase { // this is for Triggered targets that are mandatory final boolean noPrevention = sa.hasParam("NoPrevention"); final boolean divided = sa.isDividedAsYouChoose(); - final Player opp = ai.getWeakestOpponent(); + PlayerCollection opps = ai.getOpponents(); while (sa.canAddMoreTarget()) { if (tgt.canTgtPlaneswalker()) { @@ -872,13 +873,17 @@ public class DamageDealAi extends DamageAiBase { } } - if (sa.canTarget(opp)) { - if (sa.getTargets().add(opp)) { - if (divided) { - sa.addDividedAllocation(opp, dmg); - break; + if (!opps.isEmpty()) { + Player opp = opps.getFirst(); + opps.remove(opp); + if (sa.canTarget(opp)) { + if (sa.getTargets().add(opp)) { + if (divided) { + sa.addDividedAllocation(opp, dmg); + break; + } + continue; } - continue; } } diff --git a/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java b/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java index d72eedd0249..608e91a3f82 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java @@ -1,5 +1,6 @@ package forge.ai.ability; +import forge.ai.AiAttackController; import forge.ai.SpellAbilityAi; import forge.game.player.Player; import forge.game.player.PlayerActionConfirmMode; @@ -8,16 +9,33 @@ import forge.game.spellability.SpellAbility; public class SkipPhaseAi extends SpellAbilityAi { @Override protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { - return true; + return targetPlayer(aiPlayer, sa, false); } @Override protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) { - return mandatory || canPlayAI(aiPlayer, sa); + return targetPlayer(aiPlayer, sa, mandatory); } @Override public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) { return true; } + + public boolean targetPlayer(Player ai, SpellAbility sa, boolean mandatory) { + if (sa.usesTargeting()) { + final Player opp = AiAttackController.choosePreferredDefenderPlayer(ai); + sa.resetTargets(); + if (sa.canTarget(opp)) { + sa.getTargets().add(opp); + } + else if (mandatory && sa.canTarget(ai)) { + sa.getTargets().add(ai); + } + else { + return false; + } + } + return true; + } } diff --git a/forge-ai/src/main/java/forge/ai/ability/SkipTurnAi.java b/forge-ai/src/main/java/forge/ai/ability/SkipTurnAi.java index 14cae9165fc..fb7f3415e1a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SkipTurnAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SkipTurnAi.java @@ -1,6 +1,5 @@ package forge.ai.ability; - import forge.ai.SpellAbilityAi; import forge.game.player.Player; import forge.game.spellability.SpellAbility; diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index dc6ad094dd8..cfe291cb69d 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -2731,7 +2731,6 @@ public class AbilityUtils { return doXMath(powers.size(), expr, c, ctb); } - if (sq[0].startsWith("MostProminentCreatureType")) { String restriction = l[0].split(" ")[1]; CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), restriction, player, c, ctb); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index 5e903cfbc13..5ed22a22f26 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -291,7 +291,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect { * @return a {@link java.lang.String} object. */ private static String changeKnownOriginStackDescription(final SpellAbility sa) { - final StringBuilder sb = new StringBuilder(); final Card host = sa.getHostCard(); @@ -1047,7 +1046,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { // only multi-select if player can select more than one if (changeNum > 1 && allowMultiSelect(decider, sa)) { List selectedCards; - if (! sa.hasParam("SelectPrompt")) { + if (!sa.hasParam("SelectPrompt")) { // new default messaging for multi select if (fetchList.size() > changeNum) { //Select up to %changeNum cards from %players %origin diff --git a/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java index fa30bbe8fe8..16d97edd34d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java @@ -58,8 +58,8 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect { Card lki = CardUtil.getLKICopy(gameCard); lki.clearControllers(); lki.setOwner(sa.getActivatingPlayer()); - // if this trigger is part of ETBReplacement it shouldn't run with LKI from incomplete zone change (Wall of Stolen Identity) - final Card trigHost = sa.getRootAbility().getReplacementEffect() != null && sa.getRootAbility().getReplacementEffect().getMode().equals(ReplacementType.Moved) ? gameCard : lki; + // if this trigger is part of ETBReplacement it shouldn't run with LKI from incomplete zone change (Mimic Vat + Wall of Stolen Identity) + final Card trigHost = sa.getRootAbility().getReplacementEffect() != null && sa.getRootAbility().getReplacementEffect().getMode().equals(ReplacementType.Moved) && gameCard.getZone() == null ? gameCard : lki; final Trigger immediateTrig = TriggerHandler.parseTrigger(mapParams, trigHost, sa.isIntrinsic(), null); immediateTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true)); diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java index f6181cdf596..6c00b9158a7 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -275,7 +275,7 @@ public final class CardUtil { newCopy.addRemembered(in.getRemembered()); newCopy.addImprintedCards(in.getImprintedCards()); - for(Table.Cell cl : in.getEtbCounters()) { + for (Table.Cell cl : in.getEtbCounters()) { newCopy.addEtbCounter(cl.getColumnKey(), cl.getValue(), cl.getRowKey()); } diff --git a/forge-game/src/main/java/forge/game/cost/CostPartMana.java b/forge-game/src/main/java/forge/game/cost/CostPartMana.java index cdc958d7962..19d7d609d93 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPartMana.java +++ b/forge-game/src/main/java/forge/game/cost/CostPartMana.java @@ -112,13 +112,11 @@ public class CostPartMana extends CostPart { @Override public boolean isUndoable() { return true; } - @Override public final String toString() { return cost.toString(); } - @Override public final boolean canPay(final SpellAbility ability, final Player payer) { // For now, this will always return true. But this should probably be diff --git a/forge-gui/res/cardsfolder/c/crypt_champion.txt b/forge-gui/res/cardsfolder/c/crypt_champion.txt index 27812dbc796..67ce5c9e9de 100644 --- a/forge-gui/res/cardsfolder/c/crypt_champion.txt +++ b/forge-gui/res/cardsfolder/c/crypt_champion.txt @@ -6,7 +6,7 @@ K:Double Strike T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ When CARDNAME enters the battlefield, each player puts a creature card with mana value 3 or less from their graveyard onto the battlefield. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSac | ManaNotSpent$ R | TriggerDescription$ When CARDNAME enters the battlefield, sacrifice it unless {R} was spent to cast it. SVar:TrigChangeZone:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBChangeZone -SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl+cmcLE3 | ChangeNum$ 1 | Hidden$ True | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered +SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl+cmcLE3 | ChangeNum$ 1 | Hidden$ True | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | Mandatory$ True SVar:TrigSac:DB$ Sacrifice | Defined$ Self SVar:ManaNeededToAvoidNegativeEffect:red SVar:Picture:http://www.wizards.com/global/images/magic/general/crypt_champion.jpg diff --git a/forge-gui/res/cardsfolder/e/exhume.txt b/forge-gui/res/cardsfolder/e/exhume.txt index 1cb43db32b8..eb8a9202200 100644 --- a/forge-gui/res/cardsfolder/e/exhume.txt +++ b/forge-gui/res/cardsfolder/e/exhume.txt @@ -2,7 +2,7 @@ Name:Exhume ManaCost:1 B Types:Sorcery A:SP$ RepeatEach | Cost$ 1 B | RepeatSubAbility$ DBChangeZone | RepeatPlayers$ Player | SpellDescription$ Each player puts a creature card from their graveyard onto the battlefield. -SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | ChangeNum$ 1 | Hidden$ True +SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | ChangeNum$ 1 | Hidden$ True | Mandatory$ True SVar:X:Count$TypeInYourYard.Creature SVar:NeedsToPlayVar:X GE1 SVar:Picture:http://www.wizards.com/global/images/magic/general/exhume.jpg diff --git a/forge-gui/res/cardsfolder/i/infernal_offering.txt b/forge-gui/res/cardsfolder/i/infernal_offering.txt index 39090272fda..40f9f46daad 100644 --- a/forge-gui/res/cardsfolder/i/infernal_offering.txt +++ b/forge-gui/res/cardsfolder/i/infernal_offering.txt @@ -7,8 +7,8 @@ SVar:DBRepeat:DB$ RepeatEach | RepeatPlayers$ ChosenAndYou | RepeatSubAbility$ D SVar:DBDraw:DB$ Draw | Defined$ Player.IsRemembered | NumCards$ 2 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 SVar:X:RememberedLKI$Valid Creature.RememberedPlayerCtrl SVar:DBChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent | SubAbility$ DBReturnYou -SVar:DBReturnYou:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouCtrl | ChangeNum$ 1 | Hidden$ True | SubAbility$ DBReturnOpp -SVar:DBReturnOpp:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.ChosenCtrl | DefinedPlayer$ ChosenPlayer | Chooser$ ChosenPlayer | ChangeNum$ 1 | Hidden$ True | SubAbility$ DBCleanup +SVar:DBReturnYou:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouCtrl | ChangeNum$ 1 | Hidden$ True | Mandatory$ True | SubAbility$ DBReturnOpp +SVar:DBReturnOpp:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.ChosenCtrl | DefinedPlayer$ ChosenPlayer | Chooser$ ChosenPlayer | ChangeNum$ 1 | Hidden$ True | Mandatory$ True | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True AI:RemoveDeck:All AI:RemoveDeck:Random diff --git a/forge-gui/res/cardsfolder/k/kindred_summons.txt b/forge-gui/res/cardsfolder/k/kindred_summons.txt index 66d52cd0549..826d15be225 100644 --- a/forge-gui/res/cardsfolder/k/kindred_summons.txt +++ b/forge-gui/res/cardsfolder/k/kindred_summons.txt @@ -6,7 +6,6 @@ SVar:DBDigUntil:DB$ DigUntil | Amount$ X | ConditionCheckSVar$ X | ConditionSVar SVar:DBShuffle:DB$ Shuffle | Defined$ You SVar:X:Count$Valid Creature.ChosenType+YouCtrl AI:RemoveDeck:Random -#TODO: This could benefit from something like "Creature.YouCtrl+sharesCreatureTypeWithAnotherCreature" (doesn't exist in code yet) -SVar:NeedsToPlay:Creature.YouCtrl+inZoneBattlefield -SVar:Picture:http://www.wizards.com/global/images/magic/general/kindred_summons.jpg +SVar:NeedsToPlayVar:MaxTypes GE2 +SVar:MaxTypes:Count$MostProminentCreatureType Creature.YouCtrl Oracle:Choose a creature type. Reveal cards from the top of your library until you reveal X creature cards of the chosen type, where X is the number of creatures you control of that type. Put those cards onto the battlefield, then shuffle the rest of the revealed cards into your library. diff --git a/forge-gui/res/cardsfolder/m/martyrs_cause.txt b/forge-gui/res/cardsfolder/m/martyrs_cause.txt index 0252267dcc1..0e6479ff3e0 100644 --- a/forge-gui/res/cardsfolder/m/martyrs_cause.txt +++ b/forge-gui/res/cardsfolder/m/martyrs_cause.txt @@ -4,7 +4,7 @@ Types:Enchantment A:AB$ ChooseSource | Cost$ Sac<1/Creature> | Choices$ Card,Emblem | AILogic$ NeedsPrevention | SubAbility$ DBEffect | SpellDescription$ The next time a source of your choice would deal damage to any target this turn, prevent that damage. SVar:DBEffect:DB$ Effect | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target to prevent damage to | Triggers$ OutOfSight | ReplacementEffects$ RPreventNextFromSource | RememberObjects$ Targeted | SubAbility$ DBCleanup | ConditionDefined$ ChosenCard | ConditionPresent$ Card,Emblem | ConditionCompare$ GE1 SVar:OutOfSight:Mode$ ChangesZone | TriggerZones$ Command | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.IsRemembered | Execute$ ExileEffect | Static$ True -SVar:RPreventNextFromSource:Event$ DamageDone | ValidSource$ Card.ChosenCard,Emblem.ChosenCard | ValidTarget$ Card.IsRemembered,Player.IsRemembered | ReplaceWith$ ExileEffect | PreventionEffect$ True | Description$ The next time the chosen source deals damage to the any target, prevent that damage. +SVar:RPreventNextFromSource:Event$ DamageDone | ValidSource$ Card.ChosenCard,Emblem.ChosenCard | ValidTarget$ Card.IsRemembered,Player.IsRemembered | ReplaceWith$ ExileEffect | PreventionEffect$ True | Description$ The next time the chosen source deals damage to the target, prevent that damage. SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True AI:RemoveDeck:All diff --git a/forge-gui/res/cardsfolder/p/plane_merge_elf.txt b/forge-gui/res/cardsfolder/p/plane_merge_elf.txt index d9fe2eecb7b..d2ce1b63b8e 100644 --- a/forge-gui/res/cardsfolder/p/plane_merge_elf.txt +++ b/forge-gui/res/cardsfolder/p/plane_merge_elf.txt @@ -6,7 +6,7 @@ T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigLandship | Trigg SVar:TrigLandship:DB$ PeekAndReveal | PeekAmount$ 1 | RevealValid$ Land | RevealOptional$ True | RememberRevealed$ True | SubAbility$ DBToken SVar:DBToken:DB$ Token | TokenScript$ g_1_1_elf_warrior | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ1 | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.sharesCreatureTypeWith | TriggerZones$ Battlefield | Execute$ TrigPumpAll | TriggerDescription$ Kinfall — Whenever a creature enters the battlefield under your control, if it shares a creature type with Plane-Merge Elf, creatures you control get +1/+1 until end of turn. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.YouCtrl+sharesCreatureTypeWith | TriggerZones$ Battlefield | Execute$ TrigPumpAll | TriggerDescription$ Kinfall — Whenever a creature enters the battlefield under your control, if it shares a creature type with Plane-Merge Elf, creatures you control get +1/+1 until end of turn. SVar:TrigPumpAll:DB$ PumpAll | ValidCards$ Creature.YouCtrl | NumAtt$ +1 | NumDef$ +1 | ConditionDefined$ TriggeredCard | ConditionPresent$ Card.sharesCreatureTypeWith DeckHas:Ability$Token Oracle:Landship — At the beginning of your upkeep, you may look at the top card of your library. If it's a land, you may reveal it. If you do, create a 1/1 green Elf Warrior creature token.\nKinfall — Whenever a creature enters the battlefield under your control, if it shares a creature type with Plane-Merge Elf, creatures you control get +1/+1 until end of turn. diff --git a/forge-gui/res/cardsfolder/s/sigil_captain.txt b/forge-gui/res/cardsfolder/s/sigil_captain.txt index 549ad5bdc45..130aa522cc8 100644 --- a/forge-gui/res/cardsfolder/s/sigil_captain.txt +++ b/forge-gui/res/cardsfolder/s/sigil_captain.txt @@ -2,7 +2,6 @@ Name:Sigil Captain ManaCost:1 G W W Types:Creature Rhino Soldier PT:3/3 -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.powerEQ1+toughnessEQ1+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it. -SVar:TrigPutCounter:DB$ PutCounter | Defined$ TriggeredCardLKICopy | CounterType$ P1P1 | CounterNum$ 2 -SVar:Picture:http://www.wizards.com/global/images/magic/general/sigil_captain.jpg +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.powerEQ1+toughnessEQ1+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it. +SVar:TrigPutCounter:DB$ PutCounter | Defined$ TriggeredCardLKICopy | CounterType$ P1P1 | CounterNum$ 2 | ConditionDefined$ TriggeredCard | ConditionPresent$ Card.powerEQ1+toughnessEQ1 Oracle:Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it. diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java index a913181585c..68f3d28c69d 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java @@ -271,7 +271,7 @@ public abstract class InputPayMana extends InputSyncronizedBase { } // Store some information about color costs to help with any mana choices - if (colorNeeded == 0) { // only colorless left + if (colorNeeded == 0) { // only colorless left if (saPaidFor.getHostCard() != null && saPaidFor.getHostCard().hasSVar("ManaNeededToAvoidNegativeEffect")) { String[] negEffects = saPaidFor.getHostCard().getSVar("ManaNeededToAvoidNegativeEffect").split(","); for (String negColor : negEffects) { diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java index dceeebe121c..7b84fe7df0b 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java @@ -72,7 +72,6 @@ public class InputPayManaOfCostPayment extends InputPayMana { msg.append(messagePrefix).append("\n"); } if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DETAILED_SPELLDESC_IN_PROMPT)) { - // msg.append(saPaidFor.getStackDescription().replace("(Targeting ERROR)", "")); if (saPaidFor.isSpell()) { msg.append(saPaidFor.getStackDescription().replace("(Targeting ERROR)", "")).append("\n\n"); } else {