diff --git a/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java index eed76f8660c..c27dc7bd977 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java @@ -4,8 +4,12 @@ import forge.game.Game; import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; +import forge.game.card.CardCollection; import forge.game.event.GameEventCardRegenerated; import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; + +import java.util.Map; public class RegenerationEffect extends SpellAbilityEffect { @@ -17,6 +21,7 @@ public class RegenerationEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); final Game game = host.getGame(); + CardCollection tapped = new CardCollection(); for (Card c : getTargetCards(sa)) { // checks already done in ReplacementEffect @@ -24,7 +29,7 @@ public class RegenerationEffect extends SpellAbilityEffect { c.setDamage(0); c.setHasBeenDealtDeathtouchDamage(false); - c.tap(true, cause, c.getController()); + if (c.tap(true, cause, c.getController())) tapped.add(c); c.addRegeneratedThisTurn(); if (game.getCombat() != null) { @@ -40,6 +45,11 @@ public class RegenerationEffect extends SpellAbilityEffect { host.removeRemembered(c); } } + if (!tapped.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + game.getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/TapAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TapAllEffect.java index 6a9f8def1d4..e88b5faae87 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TapAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TapAllEffect.java @@ -1,15 +1,20 @@ package forge.game.ability.effects; import forge.game.Game; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; +import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.player.Player; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; +import java.util.Map; + public class TapAllEffect extends SpellAbilityEffect { @Override protected String getStackDescription(SpellAbility sa) { @@ -41,6 +46,7 @@ public class TapAllEffect extends SpellAbilityEffect { Player tapper = activator; + CardCollection tapped = new CardCollection(); for (final Card c : cards) { if (remTapped) { card.addRemembered(c); @@ -48,7 +54,12 @@ public class TapAllEffect extends SpellAbilityEffect { if (sa.hasParam("TapperController")) { tapper = c.getController(); } - c.tap(true, sa, tapper); + if (c.tap(true, sa, tapper)) tapped.add(c); + } + if (!tapped.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + game.getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/TapEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TapEffect.java index 379ec2634ff..a71f13779a2 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TapEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TapEffect.java @@ -1,5 +1,6 @@ package forge.game.ability.effects; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -7,10 +8,13 @@ import forge.game.card.CardCollection; import forge.game.card.CardLists; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; import forge.util.Lang; import forge.util.Localizer; +import java.util.Map; + public class TapEffect extends SpellAbilityEffect { /* (non-Javadoc) @@ -45,6 +49,7 @@ public class TapEffect extends SpellAbilityEffect { tapper = AbilityUtils.getDefinedPlayers(card, sa.getParam("Tapper"), sa).getFirst(); } + CardCollection tapped = new CardCollection(); for (final Card tgtC : toTap) { if (tgtC.isPhasedOut()) { continue; @@ -53,13 +58,18 @@ public class TapEffect extends SpellAbilityEffect { if (tgtC.isUntapped() && remTapped || alwaysRem) { card.addRemembered(tgtC); } - tgtC.tap(true, sa, tapper); + if (tgtC.tap(true, sa, tapper)) tapped.add(tgtC); } if (sa.hasParam("ETB")) { // do not fire Taps triggers tgtC.setTapped(true); } } + if (!tapped.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + activator.getGame().getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + } } @Override diff --git a/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapAllEffect.java index cc36e07137f..1aeb8e2897c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapAllEffect.java @@ -2,18 +2,23 @@ package forge.game.ability.effects; import forge.game.Game; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; +import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; import forge.game.player.Player; import forge.game.player.PlayerController; import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; import forge.util.Lang; import forge.util.Localizer; +import java.util.Map; + public class TapOrUntapAllEffect extends SpellAbilityEffect { @Override @@ -60,16 +65,22 @@ public class TapOrUntapAllEffect extends SpellAbilityEffect { toTap = sa.getActivatingPlayer().getController().chooseBinary(sa, sb.toString(), PlayerController.BinaryChoiceType.TapOrUntap); + CardCollection tapped = new CardCollection(); for (final Card tgtC : validCards) { if (!tgtC.isInPlay()) { continue; } if (toTap) { - tgtC.tap(true, sa, activator); + if (tgtC.tap(true, sa, activator)) tapped.add(tgtC); } else { tgtC.untap(true); } } + if (!tapped.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + game.getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapEffect.java index 7d1466b337d..b2f116cd08c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TapOrUntapEffect.java @@ -1,15 +1,20 @@ package forge.game.ability.effects; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; +import forge.game.card.CardCollection; import forge.game.player.Player; import forge.game.player.PlayerController; import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; import forge.util.CardTranslation; import forge.util.Lang; import forge.util.Localizer; +import java.util.Map; + public class TapOrUntapEffect extends SpellAbilityEffect { /* (non-Javadoc) @@ -32,6 +37,7 @@ public class TapOrUntapEffect extends SpellAbilityEffect { Player activator = sa.getActivatingPlayer(); PlayerController pc = activator.getController(); + CardCollection tapped = new CardCollection(); for (final Card tgtC : getTargetCards(sa)) { if (!tgtC.isInPlay()) { continue; @@ -50,11 +56,16 @@ public class TapOrUntapEffect extends SpellAbilityEffect { tapper = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Tapper"), sa).getFirst(); } - tgtC.tap(true, sa, tapper); + if (tgtC.tap(true, sa, tapper)) tapped.add(tgtC); } else { tgtC.untap(true); } } + if (!tapped.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + activator.getGame().getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + } } } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 48313103d3f..3c0f2806309 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -4439,11 +4439,11 @@ public class Card extends GameEntity implements Comparable, IHasSVars { view.updateTapped(this); } - public final void tap(boolean tapAnimation, SpellAbility cause, Player tapper) { - tap(false, tapAnimation, cause, tapper); + public final boolean tap(boolean tapAnimation, SpellAbility cause, Player tapper) { + return tap(false, tapAnimation, cause, tapper); } - public final void tap(boolean attacker, boolean tapAnimation, SpellAbility cause, Player tapper) { - if (tapped) { return; } + public final boolean tap(boolean attacker, boolean tapAnimation, SpellAbility cause, Player tapper) { + if (tapped) { return false; } // Run replacement effects getGame().getReplacementHandler().run(ReplacementType.Tap, AbilityKey.mapFromAffected(this)); @@ -4458,6 +4458,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { setTapped(true); view.updateNeedsTapAnimation(tapAnimation); getGame().fireEvent(new GameEventCardTapped(this, true)); + return true; } public final void untap(boolean untapAnimation) { diff --git a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java index 80d0b961c1e..4531202e1e9 100644 --- a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java +++ b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java @@ -4,6 +4,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import forge.game.ability.AbilityKey; +import forge.game.trigger.TriggerType; import org.apache.commons.lang3.StringUtils; import com.google.common.base.Strings; @@ -279,26 +281,36 @@ public class CostAdjustment { // GetSpellCostChange private static void adjustCostByConvokeOrImprovise(ManaCostBeingPaid cost, final SpellAbility sa, boolean improvise, boolean test) { - CardCollectionView untappedCards = CardLists.filter(sa.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.UNTAPPED); + final Player activator = sa.getActivatingPlayer(); + CardCollectionView untappedCards = CardLists.filter(activator.getCardsIn(ZoneType.Battlefield), + CardPredicates.Presets.UNTAPPED); if (improvise) { untappedCards = CardLists.filter(untappedCards, CardPredicates.Presets.ARTIFACTS); } else { untappedCards = CardLists.filter(untappedCards, CardPredicates.Presets.CREATURES); } - Map convokedCards = sa.getActivatingPlayer().getController().chooseCardsForConvokeOrImprovise(sa, cost.toManaCost(), untappedCards, improvise); + Map convokedCards = activator.getController().chooseCardsForConvokeOrImprovise(sa, + cost.toManaCost(), untappedCards, improvise); // Convoked creats are tapped here, setting up their taps triggers, // Then again when payment is done(In InputPayManaCost.done()) with suppression of Taps triggers. // This is to make sure that triggers go off at the right time // AND that you can't use mana tapabilities of convoked creatures to pay the convoked cost. + CardCollection tapped = new CardCollection(); for (final Entry conv : convokedCards.entrySet()) { - sa.addTappedForConvoke(conv.getKey()); + Card c = conv.getKey(); + sa.addTappedForConvoke(c); cost.decreaseShard(conv.getValue(), 1); if (!test) { - conv.getKey().tap(true, sa, sa.getActivatingPlayer()); + if (c.tap(true, sa, activator)) tapped.add(c); } } + if (!tapped.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + activator.getGame().getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + } } private static void adjustCostByOffering(final ManaCostBeingPaid cost, final SpellAbility sa) { diff --git a/forge-game/src/main/java/forge/game/cost/CostEnlist.java b/forge-game/src/main/java/forge/game/cost/CostEnlist.java index ae48c82738f..a77eceffc52 100644 --- a/forge-game/src/main/java/forge/game/cost/CostEnlist.java +++ b/forge-game/src/main/java/forge/game/cost/CostEnlist.java @@ -74,7 +74,12 @@ public class CostEnlist extends CostPartWithTrigger { @Override protected Card doPayment(Player payer, SpellAbility ability, Card targetCard, final boolean effect) { - targetCard.tap(true, ability, payer); + if (targetCard.tap(true, ability, payer)) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, new CardCollection(targetCard)); + payer.getGame().getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + } + // need to transfer info payTrig.addRemembered(targetCard); diff --git a/forge-game/src/main/java/forge/game/cost/CostTap.java b/forge-game/src/main/java/forge/game/cost/CostTap.java index 30f8956b181..0be24cc8d9b 100644 --- a/forge-game/src/main/java/forge/game/cost/CostTap.java +++ b/forge-game/src/main/java/forge/game/cost/CostTap.java @@ -17,9 +17,14 @@ */ package forge.game.cost; +import forge.game.ability.AbilityKey; import forge.game.card.Card; +import forge.game.card.CardCollection; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; + +import java.util.Map; /** * The Class CostTap. @@ -66,7 +71,12 @@ public class CostTap extends CostPart { @Override public boolean payAsDecided(Player payer, PaymentDecision decision, SpellAbility ability, final boolean effect) { - ability.getHostCard().tap(true, ability, payer); + Card hostCard = ability.getHostCard(); + if (hostCard.tap(true, ability, payer)) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, new CardCollection(hostCard)); + payer.getGame().getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + } return true; } diff --git a/forge-game/src/main/java/forge/game/cost/CostTapType.java b/forge-game/src/main/java/forge/game/cost/CostTapType.java index 4f4a6cad1b2..31f9eabafb6 100644 --- a/forge-game/src/main/java/forge/game/cost/CostTapType.java +++ b/forge-game/src/main/java/forge/game/cost/CostTapType.java @@ -18,17 +18,18 @@ package forge.game.cost; import forge.card.CardType; -import forge.game.card.Card; -import forge.game.card.CardCollection; -import forge.game.card.CardLists; -import forge.game.card.CardPredicates; +import forge.game.ability.AbilityKey; +import forge.game.card.*; import forge.game.card.CardPredicates.Presets; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; import forge.util.Lang; import forge.util.TextUtil; +import java.util.Map; + /** * The Class CostTapType. */ @@ -200,6 +201,24 @@ public class CostTapType extends CostPartWithList { return targetCard; } + @Override + protected boolean canPayListAtOnce() { + return true; + } + + @Override + protected CardCollectionView doListPayment(Player payer, SpellAbility ability, CardCollectionView targetCards, final boolean effect) { + CardCollection tapped = new CardCollection(); + for (Card c : targetCards) { + if (c.tap(true, ability, payer)) tapped.add(c); + } + + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + payer.getGame().getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + return targetCards; + } + /* (non-Javadoc) * @see forge.card.cost.CostPartWithList#getHashForList() */ diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java index ca73699ff44..a516a3f7722 100644 --- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java +++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java @@ -609,12 +609,18 @@ public class PhaseHandler implements java.io.Serializable { } while (!success); + CardCollection tapped = new CardCollection(); for (final Card attacker : combat.getAttackers()) { if (!attacker.attackVigilance()) { attacker.setTapped(false); - attacker.tap(true, true, null, null); + if (attacker.tap(true, true, null, null)) tapped.add(attacker); } } + if (!tapped.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + whoDeclares.getGame().getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + } } if (game.isGameOver()) { // they just like to close window at any moment diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTapAll.java b/forge-game/src/main/java/forge/game/trigger/TriggerTapAll.java new file mode 100644 index 00000000000..df8d0769a7e --- /dev/null +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTapAll.java @@ -0,0 +1,39 @@ +package forge.game.trigger; + +import com.google.common.collect.Iterables; +import forge.game.ability.AbilityKey; +import forge.game.card.Card; +import forge.game.card.CardPredicates; +import forge.game.spellability.SpellAbility; +import forge.util.Localizer; + +import java.util.Map; + +public class TriggerTapAll extends Trigger { + + public TriggerTapAll(final Map params, final Card host, final boolean intrinsic) { + super(params, host, intrinsic); + } + + + @Override + public boolean performTest(Map runParams) { + return matchesValidParam("ValidCards", runParams.get(AbilityKey.Cards)); + } + + @Override + public void setTriggeringObjects(SpellAbility sa, Map runParams) { + Iterable cards = (Iterable) runParams.get(AbilityKey.Cards); + if (hasParam("ValidCards")) { + cards = Iterables.filter(cards, CardPredicates.restriction(getParam("ValidCards").split(","), + getHostCard().getController(), getHostCard(), this)); + } + + sa.setTriggeringObject(AbilityKey.Cards, cards); + } + + @Override + public String getImportantStackObjects(SpellAbility sa) { + return Localizer.getInstance().getMessage("lblTapped") + ": " + sa.getTriggeringObject(AbilityKey.Cards); + } +} diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerType.java b/forge-game/src/main/java/forge/game/trigger/TriggerType.java index ac8b0eb8a5a..5ce3252b7d7 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerType.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerType.java @@ -119,6 +119,7 @@ public enum TriggerType { SpellCopy(TriggerSpellAbilityCastOrCopy.class), Surveil(TriggerSurveil.class), TakesInitiative(TriggerTakesInitiative.class), + TapAll(TriggerTapAll.class), Taps(TriggerTaps.class), TapsForMana(TriggerTapsForMana.class), TokenCreated(TriggerTokenCreated.class), diff --git a/forge-gui/res/cardsfolder/g/gangrenous_goliath.txt b/forge-gui/res/cardsfolder/g/gangrenous_goliath.txt index b2d28a411e3..00e225991eb 100644 --- a/forge-gui/res/cardsfolder/g/gangrenous_goliath.txt +++ b/forge-gui/res/cardsfolder/g/gangrenous_goliath.txt @@ -4,4 +4,5 @@ Types:Creature Zombie Giant PT:4/4 A:AB$ ChangeZone | Cost$ tapXType<3/Cleric> | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | SpellDescription$ Return CARDNAME from your graveyard to your hand. AI:RemoveDeck:Random +DeckNeeds:Type$Cleric Oracle:Tap three untapped Clerics you control: Return Gangrenous Goliath from your graveyard to your hand. diff --git a/forge-gui/res/cardsfolder/upcoming/deeproot_pilgrimage.txt b/forge-gui/res/cardsfolder/upcoming/deeproot_pilgrimage.txt new file mode 100644 index 00000000000..34876a2cc05 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/deeproot_pilgrimage.txt @@ -0,0 +1,9 @@ +Name:Deeproot Pilgrimage +ManaCost:1 U +Types:Enchantment +T:Mode$ TapAll | ValidCards$ Merfolk.nonToken+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever one or more nontoken Merfolk you control become tapped, create a 1/1 blue Merfolk creature token with hexproof. +SVar:TrigToken:DB$ Token | TokenScript$ u_1_1_merfolk_hexproof +DeckHas:Ability$Token & Type$Merfolk +AI:RemoveDeck:Random +DeckNeeds:Type$Merfolk +Oracle:Whenever one or more nontoken Merfolk you control become tapped, create a 1/1 blue Merfolk creature token with hexproof. diff --git a/forge-gui/res/cardsfolder/upcoming/succumb_to_the_cold.txt b/forge-gui/res/cardsfolder/upcoming/succumb_to_the_cold.txt index af3ecec4a06..b536a8dc550 100644 --- a/forge-gui/res/cardsfolder/upcoming/succumb_to_the_cold.txt +++ b/forge-gui/res/cardsfolder/upcoming/succumb_to_the_cold.txt @@ -1,7 +1,7 @@ Name:Succumb to the Cold ManaCost:2 U Types:Instant -A:SP$ Tap | ValidTgts$ Creature.OppCtrl | SubAbility$ DBCounter | TargetMin$ 1 | TargetMax$ 2 | TgtPrompt$ Select one or two target creatures an opponent controls | SpellDescription$ Tap one or two target creatures an opponent controls. Put a stun counter on each of them. (If a permanent with a stun counter would become untapped, remove one from it instead.) -SVar:DBCounter:DB$ PutCounter | Defined$ Targeted | CounterType$ Stun | CounterNum$ 1 +A:SP$ Tap | ValidTgts$ Creature.OppCtrl | SubAbility$ DBCounter | TargetMin$ 1 | TargetMax$ 2 | TgtPrompt$ Select one or two target creatures an opponent controls | SpellDescription$ Tap one or two target creatures an opponent controls. +SVar:DBCounter:DB$ PutCounter | Defined$ Targeted | CounterType$ Stun | CounterNum$ 1 | StackDescription$ REP Put_{p:You} puts | SpellDescription$ Put a stun counter on each of them. (If a permanent with a stun counter would become untapped, remove one from it instead.) DeckHas:Ability$Counters -Oracle:Tap one or two target creatures an opponent controls. Put a stun counter on each of them. (If a permanent with a stun counter would become untapped, remove one from it instead.) \ No newline at end of file +Oracle:Tap one or two target creatures an opponent controls. Put a stun counter on each of them. (If a permanent with a stun counter would become untapped, remove one from it instead.) diff --git a/forge-gui/src/main/java/forge/player/HumanPlay.java b/forge-gui/src/main/java/forge/player/HumanPlay.java index b4e51556c4b..d7c9b59d68e 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/player/HumanPlay.java @@ -2,8 +2,10 @@ package forge.player; import java.util.ArrayList; import java.util.List; +import java.util.Map; import forge.ImageKeys; +import forge.game.ability.AbilityKey; import forge.game.cost.*; import com.google.common.collect.Iterables; @@ -537,13 +539,19 @@ public class HumanPlay { } if (ability.getTappedForConvoke() != null) { game.getTriggerHandler().suppressMode(TriggerType.Taps); + CardCollection tapped = new CardCollection(); for (final Card c : ability.getTappedForConvoke()) { c.setTapped(false); if (!manaInputCancelled) { - c.tap(true, ability, ability.getActivatingPlayer()); + if (c.tap(true, ability, ability.getActivatingPlayer())) tapped.add(c); } } game.getTriggerHandler().clearSuppression(TriggerType.Taps); + if (!tapped.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + game.getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); + } if (manaInputCancelled) { ability.clearTappedForConvoke(); } diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 9d68af9eb88..41119d232d1 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -19,6 +19,7 @@ import java.util.Map.Entry; import java.util.stream.Collectors; import java.util.TreeSet; +import forge.game.trigger.TriggerType; import forge.trackable.TrackableCollection; import forge.util.ImageUtil; import org.apache.commons.lang3.ObjectUtils; @@ -2628,8 +2629,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont inp.setMessage(localizer.getMessage("lblChoosePermanentstoTap")); inp.showAndWait(); if (!inp.hasCancelled()) { + CardCollection tapped = new CardCollection(); for (final Card c : inp.getSelected()) { - c.tap(true, null, null); + if (c.tap(true, null, null)) tapped.add(c); + } + if (!tapped.isEmpty()) { + final Map runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Cards, tapped); + getGame().getTriggerHandler().runTrigger(TriggerType.TapAll, runParams, false); } } });