* Hinder - Fixed that the countered spell was always moved to top of library.

This commit is contained in:
LevelX2 2015-12-31 12:45:58 +01:00
parent 554e81a462
commit 35c672fa7a
14 changed files with 126 additions and 33 deletions

View file

@ -33,6 +33,7 @@ import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.target.TargetSpell; import mage.target.TargetSpell;
/** /**
@ -46,7 +47,7 @@ public class Hinder extends CardImpl {
this.expansionSetCode = "CHK"; this.expansionSetCode = "CHK";
// Counter target spell. If that spell is countered this way, put that card on the top or bottom of its owner's library instead of into that player's graveyard. // Counter target spell. If that spell is countered this way, put that card on the top or bottom of its owner's library instead of into that player's graveyard.
this.getSpellAbility().addEffect(new CounterTargetWithReplacementEffect(Zone.LIBRARY, true)); this.getSpellAbility().addEffect(new CounterTargetWithReplacementEffect(Zone.LIBRARY, ZoneDetail.CHOOSE));
this.getSpellAbility().addTarget(new TargetSpell()); this.getSpellAbility().addTarget(new TargetSpell());
} }

View file

@ -36,6 +36,7 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetSpell; import mage.target.TargetSpell;
@ -86,7 +87,7 @@ class SpellCrumpleCounterEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
return game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, Zone.LIBRARY, false, false); return game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, Zone.LIBRARY, false, ZoneDetail.BOTTOM);
} }
return false; return false;
} }

View file

@ -28,11 +28,12 @@
package mage.sets.conflux; package mage.sets.conflux;
import java.util.UUID; import java.util.UUID;
import mage.abilities.effects.common.CounterTargetWithReplacementEffect;
import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.abilities.effects.common.CounterTargetWithReplacementEffect; import mage.constants.ZoneDetail;
import mage.cards.CardImpl;
import mage.target.TargetSpell; import mage.target.TargetSpell;
/** /**
@ -45,9 +46,8 @@ public class LapseOfCertainty extends CardImpl {
super(ownerId, 9, "Lapse of Certainty", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{W}"); super(ownerId, 9, "Lapse of Certainty", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{W}");
this.expansionSetCode = "CON"; this.expansionSetCode = "CON";
// Counter target spell. If that spell is countered this way, put it on top of its owner's library instead of into that player's graveyard. // Counter target spell. If that spell is countered this way, put it on top of its owner's library instead of into that player's graveyard.
this.getSpellAbility().addEffect(new CounterTargetWithReplacementEffect(Zone.LIBRARY, true)); this.getSpellAbility().addEffect(new CounterTargetWithReplacementEffect(Zone.LIBRARY, ZoneDetail.TOP));
this.getSpellAbility().addTarget(new TargetSpell()); this.getSpellAbility().addTarget(new TargetSpell());
} }

View file

@ -40,6 +40,7 @@ import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject; import mage.game.stack.StackObject;
@ -94,7 +95,7 @@ class SpelljackEffect extends OneShotEffect {
if (controller != null) { if (controller != null) {
UUID targetId = targetPointer.getFirst(game, source); UUID targetId = targetPointer.getFirst(game, source);
StackObject stackObject = game.getStack().getStackObject(targetId); StackObject stackObject = game.getStack().getStackObject(targetId);
if (stackObject != null && game.getStack().counter(targetId, source.getSourceId(), game, Zone.EXILED, false, false)) { if (stackObject != null && game.getStack().counter(targetId, source.getSourceId(), game, Zone.EXILED, false, ZoneDetail.NONE)) {
Card card = ((Spell) stackObject).getCard(); Card card = ((Spell) stackObject).getCard();
if (card != null) { if (card != null) {
ContinuousEffect effect = new SpelljackCastFromExileEffect(); ContinuousEffect effect = new SpelljackCastFromExileEffect();

View file

@ -45,6 +45,7 @@ import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject; import mage.game.stack.StackObject;
@ -109,7 +110,7 @@ class KheruSpellsnatcherEffect extends OneShotEffect {
StackObject stackObject = game.getStack().getStackObject(objectId); StackObject stackObject = game.getStack().getStackObject(objectId);
if (stackObject != null if (stackObject != null
&& game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, Zone.EXILED, false, false)) { && game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, Zone.EXILED, false, ZoneDetail.NONE)) {
if (!((Spell) stackObject).isCopiedSpell()) { if (!((Spell) stackObject).isCopiedSpell()) {
MageObject card = game.getObject(stackObject.getSourceId()); MageObject card = game.getObject(stackObject.getSourceId());
if (card instanceof Card) { if (card instanceof Card) {

View file

@ -27,15 +27,15 @@
*/ */
package mage.sets.seventhedition; package mage.sets.seventhedition;
import mage.constants.CardType; import java.util.UUID;
import mage.constants.Rarity;
import mage.abilities.effects.common.CounterTargetWithReplacementEffect; import mage.abilities.effects.common.CounterTargetWithReplacementEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.target.TargetSpell; import mage.target.TargetSpell;
import java.util.UUID;
/** /**
* *
* @author magenoxx_at_gmail.com * @author magenoxx_at_gmail.com
@ -46,9 +46,8 @@ public class MemoryLapse extends CardImpl {
super(ownerId, 88, "Memory Lapse", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{U}"); super(ownerId, 88, "Memory Lapse", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{U}");
this.expansionSetCode = "7ED"; this.expansionSetCode = "7ED";
// Counter target spell. If that spell is countered this way, put it on top of its owner's library instead of into that player's graveyard. // Counter target spell. If that spell is countered this way, put it on top of its owner's library instead of into that player's graveyard.
this.getSpellAbility().addEffect(new CounterTargetWithReplacementEffect(Zone.LIBRARY, true)); this.getSpellAbility().addEffect(new CounterTargetWithReplacementEffect(Zone.LIBRARY, ZoneDetail.TOP));
this.getSpellAbility().addTarget(new TargetSpell()); this.getSpellAbility().addTarget(new TargetSpell());
} }

View file

@ -35,6 +35,7 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.filter.FilterSpell; import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
@ -95,7 +96,7 @@ class DesertionEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
return game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, Zone.BATTLEFIELD, false, false); return game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, Zone.BATTLEFIELD, false, ZoneDetail.NONE);
} }
return false; return false;
} }

View file

@ -32,6 +32,7 @@ import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -41,28 +42,28 @@ import mage.players.Player;
public class CounterTargetWithReplacementEffect extends OneShotEffect { public class CounterTargetWithReplacementEffect extends OneShotEffect {
private Zone targetZone; private Zone targetZone;
private boolean flag; private ZoneDetail zoneDetail;
public CounterTargetWithReplacementEffect(Zone targetZone) { public CounterTargetWithReplacementEffect(Zone targetZone) {
this(targetZone, false); this(targetZone, ZoneDetail.NONE);
} }
/** /**
* *
* @param targetZone * @param targetZone
* @param flag use to specify when moving card to library <ul><li>true = put * @param zoneDetail use to specify when moving card to library <ul><li>true
* on top</li><li>false = put on bottom</li></ul> * = put on top</li><li>false = put on bottom</li></ul>
*/ */
public CounterTargetWithReplacementEffect(Zone targetZone, boolean flag) { public CounterTargetWithReplacementEffect(Zone targetZone, ZoneDetail zoneDetail) {
super(Outcome.Detriment); super(Outcome.Detriment);
this.targetZone = targetZone; this.targetZone = targetZone;
this.flag = flag; this.zoneDetail = zoneDetail;
} }
public CounterTargetWithReplacementEffect(final CounterTargetWithReplacementEffect effect) { public CounterTargetWithReplacementEffect(final CounterTargetWithReplacementEffect effect) {
super(effect); super(effect);
this.targetZone = effect.targetZone; this.targetZone = effect.targetZone;
this.flag = effect.flag; this.zoneDetail = effect.zoneDetail;
} }
@Override @Override
@ -74,7 +75,7 @@ public class CounterTargetWithReplacementEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
return game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, targetZone, false, flag); return game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, targetZone, false, zoneDetail);
} }
return false; return false;
} }
@ -92,7 +93,16 @@ public class CounterTargetWithReplacementEffect extends OneShotEffect {
} }
if (targetZone.equals(Zone.LIBRARY)) { if (targetZone.equals(Zone.LIBRARY)) {
sb.append("put it on "); sb.append("put it on ");
sb.append(flag ? "top" : "the bottom"); switch (zoneDetail) {
case BOTTOM:
sb.append("the bottom");
case TOP:
sb.append("top");
case CHOOSE:
sb.append("top or bottom");
case NONE:
sb.append("<not allowed value>");
}
sb.append(" of its owner's library instead of into that player's graveyard"); sb.append(" of its owner's library instead of into that player's graveyard");
} }

View file

@ -1,3 +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.
*/
package mage.constants; package mage.constants;
/** /**

View file

@ -0,0 +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.
*/
package mage.constants;
/**
*
* @author LevelX2
*/
public enum ZoneDetail {
NONE,
TOP,
BOTTOM,
CHOOSE
}

View file

@ -48,9 +48,11 @@ import mage.cards.Card;
import mage.cards.CardsImpl; import mage.cards.CardsImpl;
import mage.cards.SplitCard; import mage.cards.SplitCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.SpellAbilityType; import mage.constants.SpellAbilityType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.Counters; import mage.counters.Counters;
import mage.game.Game; import mage.game.Game;
@ -328,11 +330,11 @@ public class Spell extends StackObjImpl implements Card {
@Override @Override
public void counter(UUID sourceId, Game game) { public void counter(UUID sourceId, Game game) {
this.counter(sourceId, game, Zone.GRAVEYARD, false, true); this.counter(sourceId, game, Zone.GRAVEYARD, false, ZoneDetail.NONE);
} }
@Override @Override
public void counter(UUID sourceId, Game game, Zone zone, boolean owner, boolean top) { public void counter(UUID sourceId, Game game, Zone zone, boolean owner, ZoneDetail zoneDetail) {
this.countered = true; this.countered = true;
if (!isCopiedSpell()) { if (!isCopiedSpell()) {
Player player = game.getPlayer(game.getControllerId(sourceId)); Player player = game.getPlayer(game.getControllerId(sourceId));
@ -346,7 +348,14 @@ public class Spell extends StackObjImpl implements Card {
counteringAbility = ((StackObject) counteringObject).getStackAbility(); counteringAbility = ((StackObject) counteringObject).getStackAbility();
} }
if (zone.equals(Zone.LIBRARY)) { if (zone.equals(Zone.LIBRARY)) {
if (top) { if (zoneDetail.equals(ZoneDetail.CHOOSE)) {
if (player.chooseUse(Outcome.Detriment, "Move countered spell to the top of the library? (otherwise it goes to the bottom)", counteringAbility, game)) {
zoneDetail = ZoneDetail.TOP;
} else {
zoneDetail = ZoneDetail.BOTTOM;
}
}
if (zoneDetail.equals(ZoneDetail.TOP)) {
player.putCardsOnTopOfLibrary(new CardsImpl(card), game, counteringAbility, false); player.putCardsOnTopOfLibrary(new CardsImpl(card), game, counteringAbility, false);
} else { } else {
player.putCardsOnBottomOfLibrary(new CardsImpl(card), game, counteringAbility, false); player.putCardsOnBottomOfLibrary(new CardsImpl(card), game, counteringAbility, false);

View file

@ -32,6 +32,7 @@ import java.util.Date;
import java.util.UUID; import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -82,10 +83,10 @@ public class SpellStack extends ArrayDeque<StackObject> {
} }
public boolean counter(UUID objectId, UUID sourceId, Game game) { public boolean counter(UUID objectId, UUID sourceId, Game game) {
return counter(objectId, sourceId, game, Zone.GRAVEYARD, false, true); return counter(objectId, sourceId, game, Zone.GRAVEYARD, false, ZoneDetail.TOP);
} }
public boolean counter(UUID objectId, UUID sourceId, Game game, Zone zone, boolean owner, boolean onTop) { public boolean counter(UUID objectId, UUID sourceId, Game game, Zone zone, boolean owner, ZoneDetail zoneDetail) {
// the counter logic is copied by some spells to handle replacement effects of the countered spell // the counter logic is copied by some spells to handle replacement effects of the countered spell
// so if logic is changed here check those spells for needed changes too // so if logic is changed here check those spells for needed changes too
// Concerned cards to check: Hinder, Spell Crumple // Concerned cards to check: Hinder, Spell Crumple
@ -108,7 +109,7 @@ public class SpellStack extends ArrayDeque<StackObject> {
if (!(stackObject instanceof Spell)) { // spells are removed from stack by the card movement if (!(stackObject instanceof Spell)) { // spells are removed from stack by the card movement
this.remove(stackObject); this.remove(stackObject);
} }
stackObject.counter(sourceId, game, zone, owner, onTop); stackObject.counter(sourceId, game, zone, owner, zoneDetail);
if (!game.isSimulation()) { if (!game.isSimulation()) {
game.informPlayers(counteredObjectName + " is countered by " + sourceObject.getLogName()); game.informPlayers(counteredObjectName + " is countered by " + sourceObject.getLogName());
} }

View file

@ -57,6 +57,7 @@ import mage.constants.AbilityWord;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.EffectType; import mage.constants.EffectType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.players.Player; import mage.players.Player;
@ -123,11 +124,11 @@ public class StackAbility extends StackObjImpl implements Ability {
@Override @Override
public void counter(UUID sourceId, Game game) { public void counter(UUID sourceId, Game game) {
// zone, owner, top ignored // zone, owner, top ignored
this.counter(sourceId, game, Zone.GRAVEYARD, true, true); this.counter(sourceId, game, Zone.GRAVEYARD, true, ZoneDetail.TOP);
} }
@Override @Override
public void counter(UUID sourceId, Game game, Zone zone, boolean owner, boolean top) { public void counter(UUID sourceId, Game game, Zone zone, boolean owner, ZoneDetail zoneDetail) {
//20100716 - 603.8 //20100716 - 603.8
if (ability instanceof StateTriggeredAbility) { if (ability instanceof StateTriggeredAbility) {
((StateTriggeredAbility) ability).counter(game); ((StateTriggeredAbility) ability).counter(game);

View file

@ -31,6 +31,7 @@ import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.constants.Zone; import mage.constants.Zone;
import mage.constants.ZoneDetail;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.game.Controllable; import mage.game.Controllable;
import mage.game.Game; import mage.game.Game;
@ -43,7 +44,7 @@ public interface StackObject extends MageObject, Controllable {
void counter(UUID sourceId, Game game); void counter(UUID sourceId, Game game);
void counter(UUID sourceId, Game game, Zone zone, boolean owner, boolean top); void counter(UUID sourceId, Game game, Zone zone, boolean owner, ZoneDetail zoneDetail);
Ability getStackAbility(); Ability getStackAbility();