From a245c0ed6fb9f13844c000d8a010308b5eb87017 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 2 Feb 2015 22:08:33 +0100 Subject: [PATCH 1/6] Fixed a bug of Undying. --- .../test/cards/cost/sacrifice/MomentousFallTest.java | 2 ++ Mage/src/mage/abilities/keyword/UndyingAbility.java | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/sacrifice/MomentousFallTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/sacrifice/MomentousFallTest.java index 8fa9d92d758..b7be3260b5f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/sacrifice/MomentousFallTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/sacrifice/MomentousFallTest.java @@ -2,6 +2,7 @@ package org.mage.test.cards.cost.sacrifice; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -39,6 +40,7 @@ public class MomentousFallTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Geralf's Messenger", 1); + assertCounterCount("Geralf's Messenger", CounterType.P1P1, 1); assertPowerToughness(playerA, "Geralf's Messenger", 5, 4); // +1/+1 counter + Anthem effect assertHandCount(playerA, 4); // +4 cards assertLife(playerA, 23); // +3 life diff --git a/Mage/src/mage/abilities/keyword/UndyingAbility.java b/Mage/src/mage/abilities/keyword/UndyingAbility.java index 0fa2100676f..e5aad5a8e76 100644 --- a/Mage/src/mage/abilities/keyword/UndyingAbility.java +++ b/Mage/src/mage/abilities/keyword/UndyingAbility.java @@ -1,5 +1,6 @@ package mage.abilities.keyword; + import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesTriggeredAbility; @@ -13,6 +14,7 @@ import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import org.apache.log4j.Logger; /** * @author Loki @@ -38,6 +40,7 @@ public class UndyingAbility extends DiesTriggeredAbility { if (super.checkTrigger(event, game)) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (!permanent.getCounters().containsKey(CounterType.P1P1) || permanent.getCounters().getCount(CounterType.P1P1) == 0) { + Logger.getLogger(UndyingAbility.class).info("Undying trigger: " + getSourceId()); game.getState().setValue("undying" + getSourceId(),permanent.getId()); return true; } @@ -95,6 +98,7 @@ class UndyingReplacementEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null) { + game.getState().setValue("undying" + source.getSourceId(), null); permanent.addCounters(CounterType.P1P1.createInstance(), game); } used = true; @@ -110,9 +114,10 @@ class UndyingReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { // Check if undying condition is true - UUID target = (UUID) game.getState().getValue("undying" + source.getSourceId()); - if (target.equals(source.getSourceId())) { - game.getState().setValue("undying" + source.getSourceId(), null); + UUID targetId = (UUID) game.getState().getValue("undying" + source.getSourceId()); + Logger.getLogger(UndyingReplacementEffect.class).info("Undying replacement applies: " + targetId + " eventSourceId " + event.getTargetId()); + + if (targetId != null && targetId.equals(source.getSourceId())) { return true; } } From 9877e499361059dbfdcf9aa3904c7b2e742728ac Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 2 Feb 2015 22:08:58 +0100 Subject: [PATCH 2/6] Changed TurnFaceUpAbility to a SpecialAbility. --- Mage/src/mage/abilities/common/TurnFaceUpAbility.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Mage/src/mage/abilities/common/TurnFaceUpAbility.java b/Mage/src/mage/abilities/common/TurnFaceUpAbility.java index 0b24e5edda4..c61a260c637 100644 --- a/Mage/src/mage/abilities/common/TurnFaceUpAbility.java +++ b/Mage/src/mage/abilities/common/TurnFaceUpAbility.java @@ -30,6 +30,7 @@ package mage.abilities.common; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.SpecialAction; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.effects.OneShotEffect; @@ -46,10 +47,12 @@ import mage.players.Player; * @author LevelX2 */ -public class TurnFaceUpAbility extends ActivatedAbilityImpl { +public class TurnFaceUpAbility extends SpecialAction { public TurnFaceUpAbility(Costs costs) { - super(Zone.BATTLEFIELD, new TurnFaceUpEffect(), costs); + super(Zone.BATTLEFIELD); + this.addEffect(new TurnFaceUpEffect()); + this.addCost(costs); this.usesStack = false; this.abilityType = AbilityType.SPECIAL_ACTION; this.setRuleVisible(false); // will be made visible only to controller in CardView From dd54269216657153c4d818ec08b6a3db3d2440a2 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 3 Feb 2015 00:05:30 +0100 Subject: [PATCH 3/6] * Fixed handling of Split cards (fixes #670). --- Mage.Client/serverlist.txt | 11 +-- .../mage/player/ai/ComputerPlayerMCTS.java | 2 +- .../src/mage/player/ai/MCTSNode.java | 2 +- .../java/mage/server/util/SystemUtil.java | 4 +- .../sets/worldwake/JaceTheMindSculptor.java | 6 +- .../effects/AuraReplacementEffect.java | 2 +- Mage/src/mage/cards/Card.java | 8 +++ Mage/src/mage/cards/CardImpl.java | 33 ++++++--- Mage/src/mage/cards/SplitCard.java | 71 +++++++++++++++++-- Mage/src/mage/game/GameImpl.java | 7 +- Mage/src/mage/game/stack/Spell.java | 12 +++- Mage/src/mage/players/Library.java | 6 +- Mage/src/mage/players/PlayerImpl.java | 4 +- 13 files changed, 127 insertions(+), 41 deletions(-) diff --git a/Mage.Client/serverlist.txt b/Mage.Client/serverlist.txt index 1a756c1784b..021697d81e3 100644 --- a/Mage.Client/serverlist.txt +++ b/Mage.Client/serverlist.txt @@ -1,6 +1,7 @@ -woogerworks (North America):xmage.woogerworks.com:17171 -XMage.info 1 (Europe) :176.31.186.181:17171 -XMage.info 2 (Europe) :176.31.186.181:17000 -Seedds Server (Asia) :115.29.203.80:17171 -Felipejoys (Brazil) :felipejoys.no-ip.org:17171 +woogerworks (North America/USA) :xmage.woogerworks.com:17171 +XMage.info 1 (Europe/France) :176.31.186.181:17171 +XMage.info 2 (Europe/France) :176.31.186.181:17000 +IceMage (Europe/Netherlands) :ring0.cc:17171 +Seedds Server (Asia) :115.29.203.80:17171 +Felipejoys (South America/Brazil):felipejoys.no-ip.org:17171 localhost -> connect to your local server (must be started):localhost:17171 diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java index c737e45ca75..56959a416d7 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/ComputerPlayerMCTS.java @@ -387,7 +387,7 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player { newPlayer.getLibrary().shuffle(); for (int i = 0; i < handSize; i++) { Card card = newPlayer.getLibrary().removeFromTop(mcts); - mcts.setZone(card.getId(), Zone.HAND); + card.setZone(Zone.HAND, mcts); newPlayer.getHand().add(card); } } diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java index b3e2a16e495..bebd0914a7b 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java @@ -328,7 +328,7 @@ public class MCTSNode { player.getLibrary().shuffle(); for (int i = 0; i < handSize; i++) { Card card = player.getLibrary().removeFromTop(game); - game.setZone(card.getId(), Zone.HAND); + card.setZone(Zone.HAND, game); player.getHand().add(card); } } diff --git a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java index e8bef838cf1..2f89506befc 100644 --- a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java +++ b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java @@ -96,7 +96,7 @@ public class SystemUtil { } Random random = new Random(); - Set cardsToLoad = new HashSet(); + Set cardsToLoad = new HashSet<>(); for (int i = 0; i < amount; i++) { CardInfo cardInfo = cards.get(random.nextInt(cards.size())); Card card = cardInfo != null ? cardInfo.getCard() : null; @@ -128,7 +128,7 @@ public class SystemUtil { if (zone.equals(Zone.BATTLEFIELD)) { card.putOntoBattlefield(game, Zone.OUTSIDE, null, player.getId()); } else if (zone.equals(Zone.LIBRARY)) { - game.setZone(card.getId(), Zone.LIBRARY); + card.setZone(Zone.LIBRARY, game); player.getLibrary().putOnTop(card, game); } else { card.moveToZone(zone, null, game, false); diff --git a/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java b/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java index fd7a7573706..09411bfbfef 100644 --- a/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java +++ b/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java @@ -195,15 +195,15 @@ class JaceTheMindSculptorEffect3 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getFirstTarget()); - ExileZone exile = game.getExile().getPermanentExile(); if (player != null) { while (true) { if (player.getLibrary().getFromTop(game) == null) { break; } Card card = player.getLibrary().removeFromTop(game); - exile.add(card); - game.setZone(card.getId(), Zone.EXILED); + if (card != null) { + card.moveToExile(null, "", source.getSourceId(), game); + } } for (Card card : player.getHand().getCards(game)) { card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); diff --git a/Mage/src/mage/abilities/effects/AuraReplacementEffect.java b/Mage/src/mage/abilities/effects/AuraReplacementEffect.java index 99602f9073d..6d21bb62768 100644 --- a/Mage/src/mage/abilities/effects/AuraReplacementEffect.java +++ b/Mage/src/mage/abilities/effects/AuraReplacementEffect.java @@ -152,7 +152,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { PermanentCard permanent = new PermanentCard(card, card.getOwnerId()); game.getBattlefield().addPermanent(permanent); - game.setZone(card.getId(), Zone.BATTLEFIELD); + card.setZone(Zone.BATTLEFIELD, game); game.applyEffects(); permanent.entersBattlefield(event.getSourceId(), game, fromZone, true); game.applyEffects(); diff --git a/Mage/src/mage/cards/Card.java b/Mage/src/mage/cards/Card.java index e91f5ed8d1a..006601129a6 100644 --- a/Mage/src/mage/cards/Card.java +++ b/Mage/src/mage/cards/Card.java @@ -140,4 +140,12 @@ public interface Card extends MageObject { @Override Card copy(); + + /** + * + * @return The main card of a split half card, otherwise thae card itself is returned + */ + Card getMainCard(); + + void setZone(Zone zone, Game game); } diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index aada14c563c..03c9e906848 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -419,38 +419,39 @@ public abstract class CardImpl extends MageObjectImpl implements Card { @Override public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { - ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, ability.getId(), controllerId, fromZone, Zone.STACK); + Card mainCard = getMainCard(); + ZoneChangeEvent event = new ZoneChangeEvent(mainCard.getId(), ability.getId(), controllerId, fromZone, Zone.STACK); if (!game.replaceEvent(event)) { if (event.getFromZone() != null) { switch (event.getFromZone()) { case GRAVEYARD: - game.getPlayer(ownerId).removeFromGraveyard(this, game); + game.getPlayer(ownerId).removeFromGraveyard(mainCard, game); break; case HAND: - game.getPlayer(ownerId).removeFromHand(this, game); + game.getPlayer(ownerId).removeFromHand(mainCard, game); break; case LIBRARY: - game.getPlayer(ownerId).removeFromLibrary(this, game); + game.getPlayer(ownerId).removeFromLibrary(mainCard, game); break; case EXILED: - game.getExile().removeCard(this, game); + game.getExile().removeCard(mainCard, game); break; case OUTSIDE: - game.getPlayer(ownerId).getSideboard().remove(this); + game.getPlayer(ownerId).getSideboard().remove(mainCard); break; case COMMAND: - game.getState().getCommand().remove((Commander)game.getObject(objectId)); + game.getState().getCommand().remove((Commander)game.getObject(mainCard.getId())); break; default: //logger.warning("moveToZone, not fully implemented: from="+event.getFromZone() + ", to="+event.getToZone()); } - game.rememberLKI(objectId, event.getFromZone(), this); + game.rememberLKI(mainCard.getId(), event.getFromZone(), this); } game.getStack().push(new Spell(this, ability.copy(), controllerId, event.getFromZone())); - game.setZone(objectId, event.getToZone()); + setZone(event.getToZone(), game); game.fireEvent(event); - return game.getState().getZone(objectId) == Zone.STACK; + return game.getState().getZone(mainCard.getId()) == Zone.STACK; } return false; } @@ -557,7 +558,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { // make sure the controller of all continuous effects of this card are switched to the current controller game.getContinuousEffects().setController(objectId, event.getPlayerId()); game.addPermanent(permanent); - game.setZone(objectId, Zone.BATTLEFIELD); + setZone(Zone.BATTLEFIELD, game); game.setScopeRelevant(true); permanent.setTapped(tapped); permanent.entersBattlefield(sourceId, game, event.getFromZone(), true); @@ -777,4 +778,14 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } return name; } + + @Override + public Card getMainCard() { + return this; + } + + @Override + public void setZone(Zone zone, Game game) { + game.setZone(getId(), zone); + } } diff --git a/Mage/src/mage/cards/SplitCard.java b/Mage/src/mage/cards/SplitCard.java index bbff7f6e079..cce2b36ac07 100644 --- a/Mage/src/mage/cards/SplitCard.java +++ b/Mage/src/mage/cards/SplitCard.java @@ -31,15 +31,16 @@ package mage.cards; import java.util.ArrayList; import java.util.List; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.SpellAbilityType; -import mage.constants.Zone; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; import mage.abilities.SpellAbility; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.SpellAbilityType; +import static mage.constants.SpellAbilityType.SPLIT_LEFT; +import static mage.constants.SpellAbilityType.SPLIT_RIGHT; +import mage.constants.Zone; import mage.game.Game; import mage.watchers.Watcher; @@ -90,7 +91,28 @@ public abstract class SplitCard extends CardImpl { public Card getRightHalfCard () { return rightHalfCard; } - + + @Override + public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, ArrayList appliedEffects) { + if (super.moveToZone(toZone, sourceId, game, flag, appliedEffects)) { + game.getState().setZone(getLeftHalfCard().getId(), toZone); + game.getState().setZone(getRightHalfCard().getId(), toZone); + return true; + } + return false; + } + + @Override + public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList appliedEffects) { + if (super.moveToExile(exileId, name, sourceId, game, appliedEffects)) { + Zone currentZone = game.getState().getZone(getId()); + game.getState().setZone(getLeftHalfCard().getId(), currentZone); + game.getState().setZone(getRightHalfCard().getId(), currentZone); + return true; + } + return false; + } + @Override public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { switch(ability.getSpellAbilityType()) { @@ -103,6 +125,14 @@ public abstract class SplitCard extends CardImpl { } } + @Override + public void setZone(Zone zone, Game game) { + super.setZone(zone, game); + game.setZone(getLeftHalfCard().getId(), zone); + game.setZone(getRightHalfCard().getId(), zone); + } + + @Override public Abilities getAbilities(){ Abilities allAbilites = new AbilitiesImpl<>(); @@ -198,7 +228,21 @@ class LeftHalfCard extends CardImpl { @Override public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList appliedEffects) { return splitCardParent.moveToExile(exileId, name, sourceId, game, appliedEffects); - } + } + + @Override + public Card getMainCard() { + return splitCardParent; + } + + @Override + public void setZone(Zone zone, Game game) { + super.setZone(zone, game); + game.setZone(splitCardParent.getId(), zone); + game.setZone(splitCardParent.getRightHalfCard().getId(), zone); + } + + } /* @@ -247,4 +291,17 @@ class RightHalfCard extends CardImpl { public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList appliedEffects) { return splitCardParent.moveToExile(exileId, name, sourceId, game, appliedEffects); } + + @Override + public Card getMainCard() { + return splitCardParent; + } + + @Override + public void setZone(Zone zone, Game game) { + super.setZone(zone, game); + game.setZone(splitCardParent.getId(), zone); + game.setZone(splitCardParent.getLeftHalfCard().getId(), zone); + } + } diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index a16426c9a21..8200578caa7 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -2328,19 +2328,18 @@ public abstract class GameImpl implements Game, Serializable { loadCards(ownerId, graveyard); for (Card card : library) { - setZone(card.getId(), Zone.LIBRARY); player.getLibrary().putOnTop(card, this); } for (Card card : hand) { - setZone(card.getId(), Zone.HAND); + card.setZone(Zone.HAND, this); player.getHand().add(card); } for (Card card : graveyard) { - setZone(card.getId(), Zone.GRAVEYARD); + card.setZone(Zone.GRAVEYARD, this); player.getGraveyard().add(card); } for (PermanentCard card : battlefield) { - setZone(card.getId(), Zone.BATTLEFIELD); + card.setZone(Zone.BATTLEFIELD, this); card.setOwnerId(ownerId); PermanentCard permanent = new PermanentCard(card.getCard(), ownerId); getBattlefield().addPermanent(permanent); diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 5e9a9d75302..36788c92a6a 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -210,7 +210,7 @@ public class Spell implements StackObject, Card { } } } - if (game.getState().getZone(card.getId()) == Zone.STACK) { + if (game.getState().getZone(card.getMainCard().getId()) == Zone.STACK) { card.moveToZone(Zone.GRAVEYARD, ability.getSourceId(), game, false); } } @@ -999,4 +999,14 @@ public class Spell implements StackObject, Card { return card.isMorphCard(); } + @Override + public Card getMainCard() { + return card.getMainCard(); + } + + @Override + public void setZone(Zone zone, Game game) { + card.setZone(zone, game); + } + } diff --git a/Mage/src/mage/players/Library.java b/Mage/src/mage/players/Library.java index 5b878648f7d..4a920c885e4 100644 --- a/Mage/src/mage/players/Library.java +++ b/Mage/src/mage/players/Library.java @@ -131,7 +131,7 @@ public class Library implements Serializable { public void putOnTop(Card card, Game game) { if (card.getOwnerId().equals(playerId)) { - game.setZone(card.getId(), Zone.LIBRARY); + card.setZone(Zone.LIBRARY, game); library.addFirst(card.getId()); } else { @@ -141,7 +141,7 @@ public class Library implements Serializable { public void putOnBottom(Card card, Game game) { if (card.getOwnerId().equals(playerId)) { - game.setZone(card.getId(), Zone.LIBRARY); + card.setZone(Zone.LIBRARY, game); if (library.contains(card.getId())) { library.remove(card.getId()); } @@ -226,7 +226,7 @@ public class Library implements Serializable { public void addAll(Set cards, Game game) { for (Card card: cards) { - game.setZone(card.getId(), Zone.LIBRARY); + card.setZone(Zone.LIBRARY, game); library.add(card.getId()); } } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index f1f598202c7..2da315c33f3 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -650,8 +650,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean putInHand(Card card, Game game) { if (card.getOwnerId().equals(playerId)) { + card.setZone(Zone.HAND, game); this.hand.add(card); - game.setZone(card.getId(), Zone.HAND); } else { return game.getPlayer(card.getOwnerId()).putInHand(card, game); } @@ -924,7 +924,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (card != null) { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId))) { int bookmark = game.bookmarkState(); - Zone fromZone = game.getState().getZone(card.getId()); + Zone fromZone = game.getState().getZone(card.getMainCard().getId()); card.cast(game, fromZone, ability, playerId); Spell spell = game.getStack().getSpell(ability.getId()); // some effects set sourceId to cast without paying mana costs From 015759d8ed036f304454ac4e4e6c428461fc39b9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 3 Feb 2015 00:22:31 +0100 Subject: [PATCH 4/6] * Skaab Ruinator - Fixed that casting from graveyard was implemented as activated ability instead of casting creature spell (that prevented the use of Ancient Ziggurat for casting from graveyard). --- .../mage/sets/innistrad/SkaabRuinator.java | 91 ++++++------------- 1 file changed, 30 insertions(+), 61 deletions(-) diff --git a/Mage.Sets/src/mage/sets/innistrad/SkaabRuinator.java b/Mage.Sets/src/mage/sets/innistrad/SkaabRuinator.java index d8517074e57..756cbf4be62 100644 --- a/Mage.Sets/src/mage/sets/innistrad/SkaabRuinator.java +++ b/Mage.Sets/src/mage/sets/innistrad/SkaabRuinator.java @@ -28,27 +28,23 @@ package mage.sets.innistrad; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; -import mage.constants.Outcome; -import mage.constants.TimingRule; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.ExileFromGraveCost; -import mage.abilities.costs.mana.ManaCosts; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.keyword.FlyingAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; -import mage.target.targetpointer.FixedTarget; /** * @@ -69,10 +65,11 @@ public class SkaabRuinator extends CardImpl { // As an additional cost to cast Skaab Ruinator, exile three creature cards from your graveyard. this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(3, 3, new FilterCreatureCard("creature card from your graveyard")))); + // Flying this.addAbility(FlyingAbility.getInstance()); + // You may cast Skaab Ruinator from your graveyard. - this.addAbility(new SkaabRuinatorAbility(new ManaCostsImpl("{1}{U}{U}"), TimingRule.INSTANT)); - + this.addAbility(new SimpleStaticAbility(Zone.GRAVEYARD, new SkaabRuinatorPlayEffect())); } public SkaabRuinator(final SkaabRuinator card) { @@ -85,63 +82,35 @@ public class SkaabRuinator extends CardImpl { } } -class SkaabRuinatorAbility extends ActivatedAbilityImpl { - public SkaabRuinatorAbility(ManaCosts costs, TimingRule timingRule) { - super(Zone.GRAVEYARD, new SkaabRuinatorEffect(), costs); - this.timing = TimingRule.SORCERY; - this.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(3, 3, new FilterCreatureCard("creature card from your graveyard")))); - this.usesStack = false; +class SkaabRuinatorPlayEffect extends AsThoughEffectImpl { + + public SkaabRuinatorPlayEffect() { + super(AsThoughEffectType.PLAY_FROM_NON_HAND_ZONE, Duration.EndOfGame, Outcome.PutCreatureInPlay); + staticText = "You may cast {this} from your graveyard"; } - @Override - public boolean activate(Game game, boolean noMana) { - Card card = game.getCard(sourceId); - if (card != null) { - getEffects().get(0).setTargetPointer(new FixedTarget(card.getId())); - return super.activate(game, noMana); - } - return false; - } - - public SkaabRuinatorAbility(final SkaabRuinatorAbility ability) { - super(ability); - } - - @Override - public SkaabRuinatorAbility copy() { - return new SkaabRuinatorAbility(this); - } - - @Override - public String getRule() { - return "You may cast Skaab Ruinator from your graveyard."; - } -} - -class SkaabRuinatorEffect extends OneShotEffect { - - public SkaabRuinatorEffect() { - super(Outcome.PutCreatureInPlay); - staticText = ""; - } - - public SkaabRuinatorEffect(final SkaabRuinatorEffect effect) { + public SkaabRuinatorPlayEffect(final SkaabRuinatorPlayEffect effect) { super(effect); } @Override - public SkaabRuinatorEffect copy() { - return new SkaabRuinatorEffect(this); + public boolean apply(Game game, Ability source) { + return true; } @Override - public boolean apply(Game game, Ability source) { - Card target = (Card) game.getObject(targetPointer.getFirst(game, source)); - if (target != null) { - Player controller = game.getPlayer(target.getOwnerId()); - if (controller != null) { - return target.cast(game, Zone.GRAVEYARD, target.getSpellAbility(), controller.getId()); + public SkaabRuinatorPlayEffect copy() { + return new SkaabRuinatorPlayEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (objectId.equals(source.getSourceId()) && + affectedControllerId.equals(source.getControllerId())) { + Card card = game.getCard(source.getSourceId()); + if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { + return true; } } return false; From 6e45f703358d8546ac0fcc525a48ae42f313310c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 3 Feb 2015 00:51:22 +0100 Subject: [PATCH 5/6] * Manifest - Fixed that turn face up costs of creatures with bestow were the bestow costs instead of the normal casting costs without bestow (fixes #677). --- Mage/src/mage/cards/CardImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index 03c9e906848..c37202f14ba 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -258,7 +258,8 @@ public abstract class CardImpl extends MageObjectImpl implements Card { public SpellAbility getSpellAbility() { if (spellAbility == null) { for (Ability ability : abilities.getActivatedAbilities(Zone.HAND)) { - if (ability instanceof SpellAbility) { + // name check prevents that alternate casting methods (like "cast [card name] using bestow") are returned here + if (ability instanceof SpellAbility && ability.toString().endsWith(getName())) { spellAbility = (SpellAbility) ability; } } From 4efc2a75823dc93e50cf50b43490306b9499bdc6 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 3 Feb 2015 01:40:08 +0100 Subject: [PATCH 6/6] * Bestow - Fixed that a permanent card cast with bestow has the bestow ability as spell ability. --- Mage/src/mage/abilities/keyword/BestowAbility.java | 1 - Mage/src/mage/cards/Card.java | 1 + Mage/src/mage/cards/CardImpl.java | 6 ++++++ Mage/src/mage/game/stack/Spell.java | 8 +++++++- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Mage/src/mage/abilities/keyword/BestowAbility.java b/Mage/src/mage/abilities/keyword/BestowAbility.java index 3e59a0c83a0..6f933711cc3 100644 --- a/Mage/src/mage/abilities/keyword/BestowAbility.java +++ b/Mage/src/mage/abilities/keyword/BestowAbility.java @@ -168,7 +168,6 @@ class BestowTypeChangingEffect extends ContinuousEffectImpl implements SourceEff permanent.getCardType().remove(CardType.CREATURE); permanent.getSubtype().clear(); if (!permanent.getSubtype().contains("Aura")) { - permanent.getSubtype().add("Aura"); } } diff --git a/Mage/src/mage/cards/Card.java b/Mage/src/mage/cards/Card.java index 006601129a6..d08f7796e04 100644 --- a/Mage/src/mage/cards/Card.java +++ b/Mage/src/mage/cards/Card.java @@ -53,6 +53,7 @@ public interface Card extends MageObject { void setOwnerId(UUID ownerId); void addAbility(Ability ability); void addWatcher(Watcher watcher); + void setSpellAbility(SpellAbility ability); SpellAbility getSpellAbility(); List getRules(); List getWatchers(); diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index c37202f14ba..a157a59e86b 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -789,4 +789,10 @@ public abstract class CardImpl extends MageObjectImpl implements Card { public void setZone(Zone zone, Game game) { game.setZone(getId(), zone); } + + @Override + public void setSpellAbility(SpellAbility ability) { + spellAbility = ability; + } + } diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 36788c92a6a..1a2ac5e69df 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -235,7 +235,8 @@ public class Spell implements StackObject, Card { // TODO: Find a better way to prevent bestow creatures from being effected by creature affecting abilities Permanent permanent = game.getPermanent(card.getId()); if (permanent != null && permanent instanceof PermanentCard) { - ((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE); + permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set + ((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE); } card.getCardType().add(CardType.CREATURE); } @@ -1009,4 +1010,9 @@ public class Spell implements StackObject, Card { card.setZone(zone, game); } + @Override + public void setSpellAbility(SpellAbility ability) { + throw new UnsupportedOperationException("Not supported."); + } + }