diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReefWormTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReefWormTest.java index 7c57a3d80f..def1af26a6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReefWormTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReefWormTest.java @@ -34,9 +34,9 @@ import org.mage.test.serverside.base.CardTestPlayerBase; /** * Checks that a dies triggered ability of a Token works + * * @author LevelX2 */ - public class ReefWormTest extends CardTestPlayerBase { @Test @@ -50,16 +50,18 @@ public class ReefWormTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Reef Worm", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Reef Worm"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Fish"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Whale"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Whale"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", "Fish"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Whale"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Whale"); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + setStopAt(1, PhaseStep.END_TURN); execute(); assertLife(playerA, 20); assertLife(playerB, 20); + assertGraveyardCount(playerA, "Lightning Bolt", 4); + assertPermanentCount(playerB, "Fish", 0); assertPermanentCount(playerB, "Whale", 0); assertPermanentCount(playerB, "Kraken", 1); @@ -68,4 +70,4 @@ public class ReefWormTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Lightning Bolt", 4); } -} \ No newline at end of file +} diff --git a/Mage/src/mage/abilities/TriggeredAbilities.java b/Mage/src/mage/abilities/TriggeredAbilities.java index 430ae35419..5bf7818a30 100644 --- a/Mage/src/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/mage/abilities/TriggeredAbilities.java @@ -160,6 +160,19 @@ public class TriggeredAbilities extends ConcurrentHashMap keysToRemove = new ArrayList<>(); + for (Entry entry : this.entrySet()) { + if (game.getObject(entry.getValue().getSourceId()) == null) { + keysToRemove.add(entry.getKey()); + } + } + for (String key : keysToRemove) { + remove(key); + } + } + public TriggeredAbilities copy() { return new TriggeredAbilities(this); } diff --git a/Mage/src/mage/abilities/common/DiesTriggeredAbility.java b/Mage/src/mage/abilities/common/DiesTriggeredAbility.java index 412d9518f0..aac46fbe9d 100644 --- a/Mage/src/mage/abilities/common/DiesTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/DiesTriggeredAbility.java @@ -1,40 +1,40 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.common; -import mage.constants.Zone; import mage.MageObject; import mage.abilities.effects.Effect; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; /** * @@ -58,14 +58,22 @@ public class DiesTriggeredAbility extends ZoneChangeTriggeredAbility { public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { // check it was previously on battlefield Permanent before = ((ZoneChangeEvent) event).getTarget(); - if (!this.hasSourceObjectAbility(game, before, event)) { + if (!(before instanceof PermanentToken) && !this.hasSourceObjectAbility(game, before, event)) { return false; - } + } // check now it is in graveyard Zone after = game.getState().getZone(sourceId); return before != null && after != null && Zone.GRAVEYARD.match(after); } + @Override + public boolean checkEventType(GameEvent event, Game game) { + if (super.checkEventType(event, game)) { + return ((ZoneChangeEvent) event).getFromZone().equals(Zone.BATTLEFIELD) && ((ZoneChangeEvent) event).getToZone().equals(Zone.GRAVEYARD); + } + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + @Override public DiesTriggeredAbility copy() { return new DiesTriggeredAbility(this); @@ -80,7 +88,7 @@ public class DiesTriggeredAbility extends ZoneChangeTriggeredAbility { return false; } } - for (Effect effect: getEffects()) { + for (Effect effect : getEffects()) { effect.setValue("diedPermanent", zEvent.getTarget()); } return true; diff --git a/Mage/src/mage/game/permanent/PermanentToken.java b/Mage/src/mage/game/permanent/PermanentToken.java index be5e63776a..d8e02c5e12 100644 --- a/Mage/src/mage/game/permanent/PermanentToken.java +++ b/Mage/src/mage/game/permanent/PermanentToken.java @@ -1,31 +1,30 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.game.permanent; import java.util.UUID; @@ -78,7 +77,7 @@ public class PermanentToken extends PermanentImpl { } this.abilities.setControllerId(this.controllerId); this.manaCost.clear(); - for (ManaCost cost: token.getManaCost()) { + for (ManaCost cost : token.getManaCost()) { this.getManaCost().add(cost.copy()); } this.cardType = token.getCardType(); @@ -95,8 +94,7 @@ public class PermanentToken extends PermanentImpl { game.rememberLKI(objectId, Zone.BATTLEFIELD, this); if (game.getPlayer(controllerId).removeFromBattlefield(this, game)) { game.setZone(objectId, zone); // needed for triggered dies abilities - game.addSimultaneousEvent(new ZoneChangeEvent(this, this.getControllerId(), Zone.BATTLEFIELD, zone)); // causes maybe a problem with Dies trigger of Tokens - // game.getState().removeTriggersOfSourceId(this.getId());// if token is gone endless triggered abilities have to be removed + game.addSimultaneousEvent(new ZoneChangeEvent(this, this.getControllerId(), Zone.BATTLEFIELD, zone)); return true; } } @@ -108,7 +106,7 @@ public class PermanentToken extends PermanentImpl { if (!game.replaceEvent(new ZoneChangeEvent(this, sourceId, this.getControllerId(), Zone.BATTLEFIELD, Zone.EXILED))) { game.rememberLKI(objectId, Zone.BATTLEFIELD, this); if (game.getPlayer(controllerId).removeFromBattlefield(this, game)) { - game.addSimultaneousEvent(new ZoneChangeEvent(this, sourceId, this.getControllerId(), Zone.BATTLEFIELD, Zone.EXILED)); + game.addSimultaneousEvent(new ZoneChangeEvent(this, sourceId, this.getControllerId(), Zone.BATTLEFIELD, Zone.EXILED)); return true; } } @@ -142,5 +140,4 @@ public class PermanentToken extends PermanentImpl { } } - } diff --git a/Mage/src/mage/game/turn/Phase.java b/Mage/src/mage/game/turn/Phase.java index 0fc741fcc4..511d6450cb 100644 --- a/Mage/src/mage/game/turn/Phase.java +++ b/Mage/src/mage/game/turn/Phase.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.game.turn; import java.io.Serializable; @@ -57,7 +56,8 @@ public abstract class Phase implements Serializable { public abstract Phase copy(); - public Phase() {} + public Phase() { + } public Phase(final Phase phase) { this.type = phase.type; @@ -69,7 +69,7 @@ public abstract class Phase implements Serializable { this.currentStep = phase.currentStep.copy(); } this.count = phase.count; - for (Step step: phase.steps) { + for (Step step : phase.steps) { this.steps.add(step.copy()); } } @@ -103,7 +103,7 @@ public abstract class Phase implements Serializable { if (beginPhase(game, activePlayerId)) { - for (Step step: steps) { + for (Step step : steps) { if (game.isPaused() || game.gameOver(null)) { return false; } @@ -184,6 +184,7 @@ public abstract class Phase implements Serializable { public void endPhase(Game game, UUID activePlayerId) { game.fireEvent(new GameEvent(postEvent, null, null, activePlayerId)); + game.getState().getTriggers().removeAbilitiesOfNonExistingSources(game); // e.g. tokens that left the battlefield } public void prePriority(Game game, UUID activePlayerId) { @@ -204,9 +205,9 @@ public abstract class Phase implements Serializable { prePriority(game, activePlayerId); if (!game.isPaused() && !game.gameOver(null)) { currentStep.priority(game, activePlayerId, false); - if(game.executingRollback()) { + if (game.executingRollback()) { return; - } + } } if (!game.isPaused() && !game.gameOver(null)) { postPriority(game, activePlayerId); @@ -225,8 +226,7 @@ public abstract class Phase implements Serializable { if (wasPaused) { currentStep.resumeBeginStep(game, activePlayerId); resuming = false; - } - else { + } else { prePriority(game, activePlayerId); } case PRIORITY: diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 4ad504cd50..c923bc63a2 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -116,7 +116,6 @@ import mage.game.events.ZoneChangeGroupEvent; import mage.game.match.MatchPlayer; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; -import mage.game.permanent.PermanentToken; import mage.game.stack.Spell; import mage.game.stack.StackAbility; import mage.game.stack.StackObject; @@ -813,9 +812,6 @@ public abstract class PlayerImpl implements Player, Serializable { pairedCard.clearPairedCard(); } } - if (permanent instanceof PermanentToken) { - game.getState().getTriggers().removeAbilitiesOfSource(permanent.getId()); - } return true; }