1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-12 17:00:08 -09:00

* Fixed a problem that triggered abilities that face down permanents got from other sourced did not trigger (fixes ).

This commit is contained in:
LevelX2 2018-03-16 15:06:15 +01:00
parent fdd8cd0e09
commit b035d85f98
3 changed files with 60 additions and 14 deletions
Mage.Sets/src/mage/cards/e
Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords
Mage/src/main/java/mage/abilities

View file

@ -56,7 +56,7 @@ import mage.target.common.TargetOpponent;
public class EndlessWhispers extends CardImpl {
public EndlessWhispers(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}");
// Each creature has "When this creature dies, choose target opponent. That player puts this card from its owner's graveyard onto the battlefield under his or her control at the beginning of the next end step."
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnSourceToBattlefieldEffect());

View file

@ -853,4 +853,45 @@ public class MorphTest extends CardTestPlayerBase {
assertTappedCount("Island", true, 3);
}
/**
* If you have Endless Whispers in play and a morph creature dies, it should
* be returned to play face up at end of turn under the control of an
* opponent.
*/
@Test
public void testMorphEndlessWhispers() {
/*
Quicksilver Dragon {4}{U}{U}
Creature - Dragon
5/5
Flying
{U}: If target spell has only one target and that target is Quicksilver Dragon, change that spell's target to another creature.
Morph {4}{U}
*/
addCard(Zone.HAND, playerA, "Quicksilver Dragon");
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
// Each creature has "When this creature dies, choose target opponent. That player puts this card from its owner's graveyard
// onto the battlefield under his or her control at the beginning of the next end step."
addCard(Zone.BATTLEFIELD, playerA, "Endless Whispers", 1);
addCard(Zone.HAND, playerB, "Lightning Bolt");
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Quicksilver Dragon");
setChoice(playerA, "Yes"); // cast it face down as 2/2 creature
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "");
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertGraveyardCount(playerB, "Lightning Bolt", 1);
assertGraveyardCount(playerA, "Quicksilver Dragon", 0);
assertPermanentCount(playerA, "Quicksilver Dragon", 0);
assertPermanentCount(playerB, "Quicksilver Dragon", 1);
}
}

View file

@ -28,6 +28,8 @@
*/
package mage.abilities;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import mage.MageObject;
import mage.constants.Zone;
import mage.game.Game;
@ -36,15 +38,12 @@ import mage.game.events.NumberOfTriggersEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author BetaSteward_at_googlemail.com
* <p>
* This class uses ConcurrentHashMap to avoid ConcurrentModificationExceptions.
* See ticket https://github.com/magefree/mage/issues/966 and
* https://github.com/magefree/mage/issues/473
* <p>
* This class uses ConcurrentHashMap to avoid ConcurrentModificationExceptions.
* See ticket https://github.com/magefree/mage/issues/966 and
* https://github.com/magefree/mage/issues/473
*/
public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbility> {
@ -63,7 +62,7 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
}
public void checkStateTriggers(Game game) {
for (Iterator<TriggeredAbility> it = this.values().iterator(); it.hasNext(); ) {
for (Iterator<TriggeredAbility> it = this.values().iterator(); it.hasNext();) {
TriggeredAbility ability = it.next();
if (ability instanceof StateTriggeredAbility && ((StateTriggeredAbility) ability).canTrigger(game)) {
checkTrigger(ability, null, game);
@ -72,7 +71,7 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
}
public void checkTriggers(GameEvent event, Game game) {
for (Iterator<TriggeredAbility> it = this.values().iterator(); it.hasNext(); ) {
for (Iterator<TriggeredAbility> it = this.values().iterator(); it.hasNext();) {
TriggeredAbility ability = it.next();
if (ability.checkEventType(event, game)) {
checkTrigger(ability, event, game);
@ -98,7 +97,10 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
// need to check if object was face down for dies and destroy events because the ability triggers in the new zone, zone counter -1 is used
Permanent permanent = (Permanent) game.getLastKnownInformation(ability.getSourceId(), Zone.BATTLEFIELD, ability.getSourceObjectZoneChangeCounter() - 1);
if (permanent != null) {
if (!ability.getWorksFaceDown() && permanent.isFaceDown(game)) {
if (permanent.isFaceDown(game)
&& !isGainedAbility(ability, permanent) // the face down creature got the ability from an effect => so it should work
&& !ability.getWorksFaceDown()) { // the ability is declared to work also face down
// Not all triggered abilities of face down creatures work if they are faced down
return;
}
controllerSet = true;
@ -130,8 +132,8 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
/**
* Adds a by sourceId gained triggered ability
*
* @param ability - the gained ability
* @param sourceId - the source that assigned the ability
* @param ability - the gained ability
* @param sourceId - the source that assigned the ability
* @param attachedTo - the object that gained the ability
*/
public void add(TriggeredAbility ability, UUID sourceId, MageObject attachedTo) {
@ -161,7 +163,6 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
return key;
}
public void removeAbilitiesOfSource(UUID sourceId) {
keySet().removeIf(key -> key.endsWith(sourceId.toString()));
}
@ -171,6 +172,10 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
sources.clear();
}
public boolean isGainedAbility(TriggeredAbility abilityToCheck, MageObject attachedTo) {
return sources.containsKey(getKey(abilityToCheck, attachedTo));
}
public void removeAbilitiesOfNonExistingSources(Game game) {
// e.g. Token that had triggered abilities