mirror of
https://github.com/correl/mage.git
synced 2025-03-07 20:53:18 -10:00
* Grasp of Fate - Fixed rule text. Fixed that exiled permanents did not return to battlefeild if the Grasp left the battlefield because its owner lost or left the game.
This commit is contained in:
parent
6ebd715e17
commit
7b2ff38225
5 changed files with 78 additions and 6 deletions
|
@ -44,7 +44,6 @@ import mage.constants.Zone;
|
|||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import static mage.filter.predicate.permanent.ControllerControlsIslandPredicate.filter;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
@ -59,11 +58,11 @@ import mage.util.CardUtil;
|
|||
public class GraspOfFate extends CardImpl {
|
||||
|
||||
public GraspOfFate(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}{W}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}");
|
||||
|
||||
// When Grasp of Fate enters the battlefield, for each opponent, exile up to one target nonland permanent that player controls until Grasp of Fate leaves the battlefield.
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new GraspOfFateExileEffect());
|
||||
ability.addTarget(new TargetPermanent(filter));
|
||||
ability.addTarget(new TargetPermanent());
|
||||
ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility()));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
@ -99,7 +98,7 @@ class GraspOfFateExileEffect extends OneShotEffect {
|
|||
|
||||
public GraspOfFateExileEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "exile up to one target nonland permanent that player controls until {this} leaves the battlefield";
|
||||
this.staticText = "for each opponent, exile up to one target nonland permanent that player controls until {this} leaves the battlefield";
|
||||
}
|
||||
|
||||
public GraspOfFateExileEffect(final GraspOfFateExileEffect effect) {
|
||||
|
@ -114,7 +113,7 @@ class GraspOfFateExileEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
if (permanent != null) { // 11/4/2015: If Grasp of Fate leaves the battlefield before its triggered ability resolves, no nonland permanents will be exiled.
|
||||
return new ConditionalOneShotEffect(new ExileTargetEffect(CardUtil.getCardExileZoneId(game, source), permanent.getIdName(), Zone.BATTLEFIELD, true), SourceOnBattlefieldCondition.instance).apply(game, source);
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -307,4 +307,47 @@ public class PlayerLeftGameRangeAllTest extends CardTestMultiPlayerBase {
|
|||
assertLife(playerA, 4);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* * 11/4/2015: In a multiplayer game, if Grasp of Fate's owner leaves the
|
||||
* game, the exiled cards will return to the battlefield. Because the
|
||||
* one-shot effect that returns the cards isn't an ability that goes on the
|
||||
* stack, it won't cease to exist along with the leaving player's spells and
|
||||
* abilities on the stack.
|
||||
*/
|
||||
@Test
|
||||
public void TestGraspOfFateReturn() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||
// When Grasp of Fate enters the battlefield, for each opponent, exile up to one target nonland permanent that player
|
||||
// controls until Grasp of Fate leaves the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Grasp of Fate"); // Enchantment {1}{W}{W}
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1);
|
||||
|
||||
addCard(Zone.HAND, playerC, "Lightning Bolt");
|
||||
addCard(Zone.BATTLEFIELD, playerC, "Mountain", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerC, "Juggernaut", 1);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerD, "Silvercoat Lion", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grasp of Fate");
|
||||
addTarget(playerA, "Pillarfield Ox");
|
||||
addTarget(playerA, "Juggernaut");
|
||||
addTarget(playerA, "Silvercoat Lion");
|
||||
|
||||
castSpell(2, PhaseStep.BEGIN_COMBAT, playerC, "Lightning Bolt", playerA);
|
||||
|
||||
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerC, "Lightning Bolt", 1);
|
||||
|
||||
assertLife(playerA, -1);
|
||||
Assert.assertFalse("Player D is no longer in the game", playerA.isInGame());
|
||||
|
||||
assertPermanentCount(playerB, "Pillarfield Ox", 1);
|
||||
assertPermanentCount(playerC, "Juggernaut", 1);
|
||||
assertPermanentCount(playerD, "Silvercoat Lion", 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,12 @@ import mage.util.CardUtil;
|
|||
*
|
||||
* Uses no stack
|
||||
*
|
||||
* 11/4/2015: In a multiplayer game, if Grasp of Fate's owner leaves the game,
|
||||
* the exiled cards will return to the battlefield. Because the one-shot effect
|
||||
* that returns the cards isn't an ability that goes on the stack, it won't
|
||||
* cease to exist along with the leaving player's spells and abilities on the
|
||||
* stack.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class OnLeaveReturnExiledToBattlefieldAbility extends DelayedTriggeredAbility {
|
||||
|
|
|
@ -2493,6 +2493,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
return;
|
||||
}
|
||||
//20100423 - 800.4a
|
||||
Set<Card> toOutside = new HashSet<>();
|
||||
for (Iterator<Permanent> it = getBattlefield().getAllPermanents().iterator(); it.hasNext();) {
|
||||
Permanent perm = it.next();
|
||||
if (perm.getOwnerId().equals(playerId)) {
|
||||
|
@ -2511,7 +2512,8 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
if (perm.isCreature() && this.getCombat() != null) {
|
||||
perm.removeFromCombat(this, true);
|
||||
}
|
||||
it.remove();
|
||||
toOutside.add(perm);
|
||||
// it.remove();
|
||||
} else if (perm.getControllerId().equals(player.getId())) {
|
||||
// and any effects which give that player control of any objects or players end
|
||||
Effects:
|
||||
|
@ -2531,6 +2533,18 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
}
|
||||
}
|
||||
// needed to send event that permanent leaves the battlefield to allow non stack effects to execute
|
||||
player.moveCards(toOutside, Zone.OUTSIDE, null, this);
|
||||
// triggered abilities that don't use the stack have to be executed
|
||||
List<TriggeredAbility> abilities = state.getTriggered(player.getId());
|
||||
for (Iterator<TriggeredAbility> it = abilities.iterator(); it.hasNext();) {
|
||||
TriggeredAbility triggeredAbility = it.next();
|
||||
if (!triggeredAbility.isUsesStack()) {
|
||||
state.removeTriggeredAbility(triggeredAbility);
|
||||
player.triggerAbility(triggeredAbility, this);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
// Then, if that player controlled any objects on the stack not represented by cards, those objects cease to exist.
|
||||
this.getState().getContinuousEffects().removeInactiveEffects(this);
|
||||
getStack().removeIf(object -> object.getControllerId().equals(playerId));
|
||||
|
|
|
@ -3461,6 +3461,16 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case OUTSIDE:
|
||||
for (Card card : cards) {
|
||||
if (card instanceof Permanent) {
|
||||
game.getBattlefield().removePermanent(((Permanent) card).getId());
|
||||
ZoneChangeEvent event = new ZoneChangeEvent(card.getId(), (source == null ? null : source.getSourceId()),
|
||||
byOwner ? card.getOwnerId() : getId(), Zone.BATTLEFIELD, Zone.OUTSIDE, appliedEffects);
|
||||
game.fireEvent(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("to Zone" + toZone.toString() + " not supported yet");
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue