mirror of
https://github.com/magefree/mage.git
synced 2025-12-22 03:22:00 -08:00
Some changes related to #4893.
This commit is contained in:
parent
9919a3403d
commit
cddd81123b
37 changed files with 245 additions and 137 deletions
|
|
@ -45,8 +45,11 @@ public final class CardImageUtils {
|
||||||
pathCache.put(card, filePath);
|
pathCache.put(card, filePath);
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.warn("Token image file not found. Set: " + card.getSet() + " Token Set Code: " + card.getTokenSetCode() + " Name: " + card.getName() + " File path: " + filePath);
|
||||||
|
} else {
|
||||||
|
log.warn("Trying to get token path for non token card. Set: " + card.getSet() + " Set Code: " + card.getTokenSetCode() + " Name: " + card.getName());
|
||||||
}
|
}
|
||||||
log.warn("Token image file not found: " + card.getSet() + " - " + card.getTokenSetCode() + " - " + card.getName());
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -430,7 +430,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
||||||
}
|
}
|
||||||
stackObject.resolve(game);
|
stackObject.resolve(game);
|
||||||
if (stackObject instanceof StackAbility) {
|
if (stackObject instanceof StackAbility) {
|
||||||
game.getStack().remove(stackObject);
|
game.getStack().remove(stackObject, game);
|
||||||
}
|
}
|
||||||
game.applyEffects();
|
game.applyEffects();
|
||||||
game.getPlayers().resetPassed();
|
game.getPlayers().resetPassed();
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ class NorinTheWaryTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return new StringBuilder("When a player casts a spell or a creature attacks, ").append(super.getRule()).toString();
|
return "When a player casts a spell or a creature attacks, " + super.getRule();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package mage.cards.u;
|
package mage.cards.u;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -37,8 +36,8 @@ import mage.abilities.keyword.UnearthAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -56,8 +55,9 @@ public class UndeadLeotau extends CardImpl {
|
||||||
this.toughness = new MageInt(4);
|
this.toughness = new MageInt(4);
|
||||||
|
|
||||||
// {R}: Undead Leotau gets +1/-1 until end of turn.
|
// {R}: Undead Leotau gets +1/-1 until end of turn.
|
||||||
// Unearth {2}{B}
|
|
||||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(+1, -1, Duration.EndOfTurn), new ManaCostsImpl("{R}")));
|
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(+1, -1, Duration.EndOfTurn), new ManaCostsImpl("{R}")));
|
||||||
|
|
||||||
|
// Unearth {2}{B}
|
||||||
this.addAbility(new UnearthAbility(new ManaCostsImpl("{2}{B}")));
|
this.addAbility(new UnearthAbility(new ManaCostsImpl("{2}{B}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ import mage.abilities.keyword.FlyingAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -59,6 +59,7 @@ public class VoiceOfAll extends CardImpl {
|
||||||
// As Voice of All enters the battlefield, choose a color.
|
// As Voice of All enters the battlefield, choose a color.
|
||||||
this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Benefit)));
|
this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Benefit)));
|
||||||
|
|
||||||
|
// Voice of All has protection from the chosen color.
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ProtectionChosenColorSourceEffect()));
|
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ProtectionChosenColorSourceEffect()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,11 @@ import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import org.junit.Ignore;
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author noxx
|
* @author noxx
|
||||||
|
|
@ -179,6 +176,9 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
|
||||||
@Test
|
@Test
|
||||||
public void testCopyEntersTapped() {
|
public void testCopyEntersTapped() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
|
// You may have Phantasmal Image enter the battlefield as a copy of any creature
|
||||||
|
// on the battlefield, except it's an Illusion in addition to its other types and
|
||||||
|
// it gains "When this creature becomes the target of a spell or ability, sacrifice it."
|
||||||
addCard(Zone.HAND, playerA, "Phantasmal Image");
|
addCard(Zone.HAND, playerA, "Phantasmal Image");
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Geralf's Messenger");
|
addCard(Zone.BATTLEFIELD, playerB, "Geralf's Messenger");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Harm's Way: The next 2 damage that a source of your choice would deal to you
|
* Harm's Way: The next 2 damage that a source of your choice would deal to you
|
||||||
* and/or permanents you control this turn is dealt to any target
|
* and/or permanents you control this turn is dealt to any target instead.
|
||||||
* instead.
|
|
||||||
*
|
*
|
||||||
* @author noxx
|
* @author noxx
|
||||||
*/
|
*/
|
||||||
|
|
@ -23,7 +22,7 @@ public class HarmsWayRedirectDamageTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||||
|
|
||||||
addCard(Zone.HAND, playerB, "Harm's Way");
|
addCard(Zone.HAND, playerB, "Harm's Way"); // Instant {W}
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Plains");
|
addCard(Zone.BATTLEFIELD, playerB, "Plains");
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||||
|
|
@ -33,6 +32,9 @@ public class HarmsWayRedirectDamageTest extends CardTestPlayerBase {
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||||
|
assertGraveyardCount(playerB, "Harm's Way", 1);
|
||||||
|
|
||||||
// 2 damage was redirected back
|
// 2 damage was redirected back
|
||||||
assertLife(playerA, 18);
|
assertLife(playerA, 18);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ package org.mage.test.cards.single.bfz;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,8 @@ public abstract class AbilityImpl implements Ability {
|
||||||
public void newId() {
|
public void newId() {
|
||||||
if (!(this instanceof MageSingleton)) {
|
if (!(this instanceof MageSingleton)) {
|
||||||
this.id = UUID.randomUUID();
|
this.id = UUID.randomUUID();
|
||||||
|
// this.sourceObject = null;
|
||||||
|
// this.sourceObjectZoneChangeCounter = -1;
|
||||||
}
|
}
|
||||||
getEffects().newId();
|
getEffects().newId();
|
||||||
}
|
}
|
||||||
|
|
@ -1211,7 +1213,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Permanent getSourcePermanentIfItStillExists(Game game) {
|
public Permanent getSourcePermanentIfItStillExists(Game game) {
|
||||||
if (sourceObject == null) {
|
if (sourceObject == null || !sourceObject.getId().equals(getSourceId())) {
|
||||||
setSourceObject(game.getObject(getSourceId()), game);
|
setSourceObject(game.getObject(getSourceId()), game);
|
||||||
}
|
}
|
||||||
if (sourceObject instanceof Permanent) {
|
if (sourceObject instanceof Permanent) {
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ public class ExileFromStackCost extends CostImpl {
|
||||||
}
|
}
|
||||||
String spellName = spellToExile.getName();
|
String spellName = spellToExile.getName();
|
||||||
if (spellToExile.isCopy()) {
|
if (spellToExile.isCopy()) {
|
||||||
game.getStack().remove(spellToExile);
|
game.getStack().remove(spellToExile, game);
|
||||||
} else {
|
} else {
|
||||||
spellToExile.moveToExile(null, "", ability.getSourceId(), game);
|
spellToExile.moveToExile(null, "", ability.getSourceId(), game);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
*/
|
*/
|
||||||
package mage.abilities.effects.common;
|
package mage.abilities.effects.common;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.Mode;
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
|
|
@ -36,8 +37,6 @@ import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.GameEvent.EventType;
|
import mage.game.events.GameEvent.EventType;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author jeffwadsworth
|
* @author jeffwadsworth
|
||||||
|
|
@ -67,6 +66,17 @@ public class CantBeRegeneratedSourceEffect extends ContinuousRuleModifyingEffect
|
||||||
return event.getType() == EventType.REGENERATE;
|
return event.getType() == EventType.REGENERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
if (duration.isOnlyValidIfNoZoneChange()) {
|
||||||
|
// If source permanent is no longer onto battlefield discard the effect
|
||||||
|
if (source.getSourcePermanentIfItStillExists(game) == null) {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
return Objects.equals(source.getSourceId(), event.getTargetId());
|
return Objects.equals(source.getSourceId(), event.getTargetId());
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ public class DestroySourceEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
permanent.destroy(source.getSourceId(), game, noRegen);
|
permanent.destroy(source.getSourceId(), game, noRegen);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
*/
|
*/
|
||||||
package mage.abilities.effects.common;
|
package mage.abilities.effects.common;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.Mode;
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
|
@ -50,21 +51,19 @@ public class FightTargetSourceEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent originalPermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
MageObject sourceObject = source.getSourceObject(game);
|
||||||
if (originalPermanent != null) {
|
if (sourceObject != null) {
|
||||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
// only if target is legal the effect will be applied
|
Permanent creature1 = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
if (source.getTargets().get(0).isLegal(source, game)) {
|
|
||||||
Permanent creature1 = game.getPermanent(source.getTargets().get(0).getFirstTarget());
|
|
||||||
// 20110930 - 701.10
|
// 20110930 - 701.10
|
||||||
if (creature1 != null && sourcePermanent != null) {
|
if (creature1 != null && sourcePermanent != null) {
|
||||||
if (creature1.isCreature() && sourcePermanent.isCreature()) {
|
if (creature1.isCreature() && sourcePermanent.isCreature()) {
|
||||||
return sourcePermanent.fight(creature1, source, game);
|
return sourcePermanent.fight(creature1, source, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!game.isSimulation()) {
|
||||||
|
game.informPlayers(sourceObject.getLogName() + ": Fighting effect has been fizzled.");
|
||||||
}
|
}
|
||||||
if (!game.isSimulation())
|
|
||||||
game.informPlayers(originalPermanent.getLogName() + ": Fighting effect has been fizzled.");
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -83,4 +82,3 @@ public class FightTargetSourceEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,9 @@ import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.token.TokenImpl;
|
|
||||||
import mage.game.permanent.token.Token;
|
import mage.game.permanent.token.Token;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Loki
|
* @author Loki
|
||||||
*/
|
*/
|
||||||
|
|
@ -33,14 +31,15 @@ public class FlipSourceEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (permanent != null && controller != null) {
|
if (permanent != null && controller != null) {
|
||||||
if (permanent.flip(game)) {
|
if (permanent.flip(game)) {
|
||||||
ContinuousEffect effect = new ConditionalContinuousEffect(new CopyTokenEffect(flipToken), FlippedCondition.instance, "");
|
ContinuousEffect effect = new ConditionalContinuousEffect(new CopyTokenEffect(flipToken), FlippedCondition.instance, "");
|
||||||
game.addEffect(effect, source);
|
game.addEffect(effect, source);
|
||||||
if (!game.isSimulation())
|
if (!game.isSimulation()) {
|
||||||
game.informPlayers(new StringBuilder(controller.getLogName()).append(" flips ").append(permanent.getName()).toString());
|
game.informPlayers(new StringBuilder(controller.getLogName()).append(" flips ").append(permanent.getName()).toString());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
package mage.abilities.effects.common;
|
package mage.abilities.effects.common;
|
||||||
|
|
||||||
import mage.MageObject;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
|
@ -34,9 +33,8 @@ public class PhaseOutSourceEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
if (sourceObject instanceof Permanent) {
|
if (permanent != null) {
|
||||||
Permanent permanent = (Permanent) sourceObject;
|
|
||||||
return permanent.phaseOut(game);
|
return permanent.phaseOut(game);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,17 @@ public class PreventDamageToSourceEffect extends PreventionEffectImpl {
|
||||||
return new PreventDamageToSourceEffect(this);
|
return new PreventDamageToSourceEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
if (duration.isOnlyValidIfNoZoneChange()) {
|
||||||
|
// If source permanent is no longer onto battlefield discard the effect
|
||||||
|
if (source.getSourcePermanentIfItStillExists(game) == null) {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,18 @@
|
||||||
package mage.abilities.effects.common;
|
package mage.abilities.effects.common;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||||
|
import mage.abilities.keyword.HasteAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -43,21 +49,25 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
|
||||||
|
|
||||||
private boolean tapped;
|
private boolean tapped;
|
||||||
private boolean ownerControl;
|
private boolean ownerControl;
|
||||||
|
private boolean haste;
|
||||||
|
|
||||||
public ReturnSourceFromGraveyardToBattlefieldEffect() {
|
public ReturnSourceFromGraveyardToBattlefieldEffect() {
|
||||||
this(false);
|
this(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped) {
|
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped) {
|
||||||
super(Outcome.PutCreatureInPlay);
|
this(tapped, true);
|
||||||
this.tapped = tapped;
|
|
||||||
setText();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped, boolean ownerControl) {
|
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped, boolean ownerControl) {
|
||||||
|
this(tapped, ownerControl, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped, boolean ownerControl, boolean haste) {
|
||||||
super(Outcome.PutCreatureInPlay);
|
super(Outcome.PutCreatureInPlay);
|
||||||
this.tapped = tapped;
|
this.tapped = tapped;
|
||||||
this.ownerControl = ownerControl;
|
this.ownerControl = ownerControl;
|
||||||
|
this.haste = haste;
|
||||||
setText();
|
setText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,6 +75,7 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
|
||||||
super(effect);
|
super(effect);
|
||||||
this.tapped = effect.tapped;
|
this.tapped = effect.tapped;
|
||||||
this.ownerControl = effect.ownerControl;
|
this.ownerControl = effect.ownerControl;
|
||||||
|
this.haste = effect.haste;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -89,6 +100,14 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
|
||||||
}
|
}
|
||||||
if (game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) {
|
if (game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) {
|
||||||
player.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, true, null);
|
player.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, true, null);
|
||||||
|
if (haste) {
|
||||||
|
Permanent permanent = game.getPermanent(card.getId());
|
||||||
|
if (permanent != null) {
|
||||||
|
ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom);
|
||||||
|
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||||
|
game.addEffect(effect, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import mage.cards.Card;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -81,16 +82,17 @@ public class ReturnToBattlefieldUnderOwnerControlSourceEffect extends OneShotEff
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Card card = game.getCard(source.getSourceId());
|
Card card = game.getCard(source.getSourceId());
|
||||||
if (card != null) {
|
if (controller != null && card != null) {
|
||||||
// return only from public zones
|
// return only from public zones
|
||||||
switch (game.getState().getZone(card.getId())) {
|
switch (game.getState().getZone(card.getId())) {
|
||||||
case EXILED:
|
case EXILED:
|
||||||
case COMMAND:
|
case COMMAND:
|
||||||
case GRAVEYARD:
|
case GRAVEYARD:
|
||||||
if (zoneChangeCounter < 0 || game.getState().getZoneChangeCounter(card.getId()) == zoneChangeCounter) {
|
if (zoneChangeCounter < 0 || game.getState().getZoneChangeCounter(card.getId()) == zoneChangeCounter) {
|
||||||
Zone currentZone = game.getState().getZone(card.getId());
|
|
||||||
if (card.putOntoBattlefield(game, currentZone, source.getSourceId(), card.getOwnerId(), tapped)) {
|
if (controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, true, null)) {
|
||||||
if (attacking) {
|
if (attacking) {
|
||||||
game.getCombat().addAttackingCreature(card.getId(), game);
|
game.getCombat().addAttackingCreature(card.getId(), game);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ public class ReturnToHandTargetEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (UUID copyId : copyIds) {
|
for (UUID copyId : copyIds) {
|
||||||
game.getStack().remove(game.getSpell(copyId));
|
game.getStack().remove(game.getSpell(copyId), game);
|
||||||
}
|
}
|
||||||
return controller.moveCards(cards, Zone.HAND, source, game);
|
return controller.moveCards(cards, Zone.HAND, source, game);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,7 @@ public class TapSourceEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
if (permanent == null) {
|
|
||||||
permanent = game.getPermanentEntering(source.getSourceId());
|
|
||||||
}
|
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
if (withoutTrigger) {
|
if (withoutTrigger) {
|
||||||
permanent.setTapped(true);
|
permanent.setTapped(true);
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,13 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
super.init(source, game);
|
super.init(source, game);
|
||||||
|
if (!onCard && Duration.WhileOnBattlefield != duration) {
|
||||||
|
// If source permanent is no longer onto battlefield discard the effect
|
||||||
|
if (source.getSourcePermanentIfItStillExists(game) == null) {
|
||||||
|
discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (affectedObjectsSet) {
|
if (affectedObjectsSet) {
|
||||||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import mage.constants.Outcome;
|
||||||
import mage.constants.SubLayer;
|
import mage.constants.SubLayer;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Noahsark
|
* @author Noahsark
|
||||||
|
|
@ -40,6 +41,17 @@ public class LoseAbilitySourceEffect extends ContinuousEffectImpl{
|
||||||
return new LoseAbilitySourceEffect(this);
|
return new LoseAbilitySourceEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
if (duration.isOnlyValidIfNoZoneChange()) {
|
||||||
|
// If source permanent is no longer onto battlefield discard the effect
|
||||||
|
if (source.getSourcePermanentIfItStillExists(game) == null) {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,17 @@ public class LoseCreatureTypeSourceEffect extends ContinuousEffectImpl implement
|
||||||
return new LoseCreatureTypeSourceEffect(this);
|
return new LoseCreatureTypeSourceEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
if (duration.isOnlyValidIfNoZoneChange()) {
|
||||||
|
// If source permanent is no longer onto battlefield discard the effect
|
||||||
|
if (source.getSourcePermanentIfItStillExists(game) == null) {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
||||||
if (dynamicValue.calculate(game, source, this) >= lessThan) {
|
if (dynamicValue.calculate(game, source, this) >= lessThan) {
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,12 @@
|
||||||
*/
|
*/
|
||||||
package mage.abilities.effects.common.continuous;
|
package mage.abilities.effects.common.continuous;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Layer;
|
import mage.constants.Layer;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.SubLayer;
|
import mage.constants.SubLayer;
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
|
|
@ -55,14 +55,29 @@ public class SwitchPowerToughnessSourceEffect extends ContinuousEffectImpl {
|
||||||
return new SwitchPowerToughnessSourceEffect(this);
|
return new SwitchPowerToughnessSourceEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
if (duration.isOnlyValidIfNoZoneChange()) {
|
||||||
|
// If source permanent is no longer onto battlefield discard the effect
|
||||||
|
if (source.getSourcePermanentIfItStillExists(game) == null) {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent target = game.getPermanent(source.getSourceId());
|
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
if (target != null) {
|
if (sourcePermanent != null) {
|
||||||
int power = target.getPower().getValue();
|
int power = sourcePermanent.getPower().getValue();
|
||||||
target.getPower().setValue(target.getToughness().getValue());
|
sourcePermanent.getPower().setValue(sourcePermanent.getToughness().getValue());
|
||||||
target.getToughness().setValue(power);
|
sourcePermanent.getToughness().setValue(power);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
if (duration.isOnlyValidIfNoZoneChange()) {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ public class RemoveAllCountersSourceEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
int count = permanent.getCounters(game).getCount(counterType);
|
int count = permanent.getCounters(game).getCount(counterType);
|
||||||
permanent.removeCounters(counterType.getName(), count, game);
|
permanent.removeCounters(counterType.getName(), count, game);
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
int toRemove = Math.min(counter.getCount(), permanent.getCounters(game).getCount(counter.getName()));
|
int toRemove = Math.min(counter.getCount(), permanent.getCounters(game).getCount(counter.getName()));
|
||||||
if (toRemove > 0) {
|
if (toRemove > 0) {
|
||||||
|
|
@ -67,6 +67,7 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (!(source.getSourceObject(game) instanceof Permanent)) {
|
||||||
Card card = game.getCard(source.getSourceId());
|
Card card = game.getCard(source.getSourceId());
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
int toRemove = Math.min(counter.getCount(), card.getCounters(game).getCount(counter.getName()));
|
int toRemove = Math.min(counter.getCount(), card.getCounters(game).getCount(counter.getName()));
|
||||||
|
|
@ -80,6 +81,7 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ import mage.abilities.effects.ReplacementEffectImpl;
|
||||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||||
import mage.abilities.effects.common.ExileSourceEffect;
|
import mage.abilities.effects.common.ExileSourceEffect;
|
||||||
import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect;
|
import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect;
|
||||||
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
|
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.TimingRule;
|
import mage.constants.TimingRule;
|
||||||
|
|
@ -63,9 +62,8 @@ import mage.game.events.ZoneChangeEvent;
|
||||||
public class UnearthAbility extends ActivatedAbilityImpl {
|
public class UnearthAbility extends ActivatedAbilityImpl {
|
||||||
|
|
||||||
public UnearthAbility(ManaCosts costs) {
|
public UnearthAbility(ManaCosts costs) {
|
||||||
super(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), costs);
|
super(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, true, true), costs);
|
||||||
this.timing = TimingRule.SORCERY;
|
this.timing = TimingRule.SORCERY;
|
||||||
this.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom));
|
|
||||||
this.addEffect(new CreateDelayedTriggeredAbilityEffect(new UnearthDelayedTriggeredAbility()));
|
this.addEffect(new CreateDelayedTriggeredAbilityEffect(new UnearthDelayedTriggeredAbility()));
|
||||||
this.addEffect(new UnearthLeavesBattlefieldEffect());
|
this.addEffect(new UnearthLeavesBattlefieldEffect());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
|
||||||
import mage.filter.predicate.mageobject.NamePredicate;
|
import mage.filter.predicate.mageobject.NamePredicate;
|
||||||
import mage.filter.predicate.mageobject.PowerPredicate;
|
import mage.filter.predicate.mageobject.PowerPredicate;
|
||||||
import mage.game.*;
|
import mage.game.*;
|
||||||
|
import mage.game.command.CommandObject;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
|
@ -618,14 +619,18 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
stackObject = game.getStack().getSpell(getId());
|
stackObject = game.getStack().getSpell(getId());
|
||||||
}
|
}
|
||||||
if (stackObject != null) {
|
if (stackObject != null) {
|
||||||
removed = game.getStack().remove(stackObject);
|
removed = game.getStack().remove(stackObject, game);
|
||||||
lkiObject = stackObject;
|
lkiObject = stackObject;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMMAND:
|
case COMMAND:
|
||||||
lkiObject = game.getObject(objectId);
|
for (CommandObject commandObject : game.getState().getCommand()) {
|
||||||
|
if (commandObject.getId().equals(objectId)) {
|
||||||
|
lkiObject = commandObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (lkiObject != null) {
|
if (lkiObject != null) {
|
||||||
removed = game.getState().getCommand().remove(game.getObject(objectId));
|
removed = game.getState().getCommand().remove((CommandObject) lkiObject);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OUTSIDE:
|
case OUTSIDE:
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,23 @@ package mage.constants;
|
||||||
* @author North
|
* @author North
|
||||||
*/
|
*/
|
||||||
public enum Duration {
|
public enum Duration {
|
||||||
OneUse(""),
|
OneUse("", true),
|
||||||
EndOfGame("for the rest of the game"),
|
EndOfGame("for the rest of the game", false),
|
||||||
WhileOnBattlefield(""),
|
WhileOnBattlefield("", false),
|
||||||
WhileOnStack(""),
|
WhileOnStack("", false),
|
||||||
WhileInGraveyard(""),
|
WhileInGraveyard("", false),
|
||||||
EndOfTurn("until end of turn"),
|
EndOfTurn("until end of turn", true),
|
||||||
UntilYourNextTurn("until your next turn"),
|
UntilYourNextTurn("until your next turn", true),
|
||||||
EndOfCombat("until end of combat"),
|
EndOfCombat("until end of combat", true),
|
||||||
EndOfStep("until end of phase step"),
|
EndOfStep("until end of phase step", true),
|
||||||
Custom("");
|
Custom("", true);
|
||||||
|
|
||||||
private final String text;
|
private final String text;
|
||||||
|
private final boolean onlyValidIfNoZoneChange; // defines if an effect lasts only if the source has not chnaged zone since init of the effect
|
||||||
|
|
||||||
Duration(String text) {
|
Duration(String text, boolean onlyValidIfNoZoneChange) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
this.onlyValidIfNoZoneChange = onlyValidIfNoZoneChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -27,4 +29,8 @@ public enum Duration {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOnlyValidIfNoZoneChange() {
|
||||||
|
return onlyValidIfNoZoneChange;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -328,12 +328,15 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
MageObject object;
|
MageObject object;
|
||||||
if (state.getBattlefield().containsPermanent(objectId)) {
|
if (state.getBattlefield().containsPermanent(objectId)) {
|
||||||
object = state.getBattlefield().getPermanent(objectId);
|
object = state.getBattlefield().getPermanent(objectId);
|
||||||
state.setZone(objectId, Zone.BATTLEFIELD); // why is this neccessary?
|
// state.setZone(objectId, Zone.BATTLEFIELD); // why is this neccessary?
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
if (getPermanentsEntering().containsKey(objectId)) {
|
||||||
|
return getPermanentEntering(objectId);
|
||||||
|
}
|
||||||
for (StackObject item : state.getStack()) {
|
for (StackObject item : state.getStack()) {
|
||||||
if (item.getId().equals(objectId)) {
|
if (item.getId().equals(objectId)) {
|
||||||
state.setZone(objectId, Zone.STACK); // why is this neccessary?
|
// state.setZone(objectId, Zone.STACK); // why is this neccessary?
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
if (item.getSourceId().equals(objectId) && item instanceof Spell) {
|
if (item.getSourceId().equals(objectId) && item instanceof Spell) {
|
||||||
|
|
@ -1421,7 +1424,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
top.resolve(this);
|
top.resolve(this);
|
||||||
} finally {
|
} finally {
|
||||||
if (top != null) {
|
if (top != null) {
|
||||||
state.getStack().remove(top); // seems partly redundant because move card from stack to grave is already done and the stack removed
|
state.getStack().remove(top, this); // seems partly redundant because move card from stack to grave is already done and the stack removed
|
||||||
rememberLKI(top.getSourceId(), Zone.STACK, top);
|
rememberLKI(top.getSourceId(), Zone.STACK, top);
|
||||||
checkInfiniteLoop(top.getSourceId());
|
checkInfiniteLoop(top.getSourceId());
|
||||||
if (!getTurn().isEndTurnRequested()) {
|
if (!getTurn().isEndTurnRequested()) {
|
||||||
|
|
|
||||||
|
|
@ -685,8 +685,12 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setZone(UUID id, Zone zone) {
|
public void setZone(UUID id, Zone zone) {
|
||||||
|
if (zone == null) {
|
||||||
|
zones.remove(id);
|
||||||
|
} else {
|
||||||
zones.put(id, zone);
|
zones.put(id, zone);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addSimultaneousEvent(GameEvent event, Game game) {
|
public void addSimultaneousEvent(GameEvent event, Game game) {
|
||||||
simultaneousEvents.add(event);
|
simultaneousEvents.add(event);
|
||||||
|
|
|
||||||
|
|
@ -134,12 +134,15 @@ public final class ZonesHandler {
|
||||||
case STACK:
|
case STACK:
|
||||||
// There should never be more than one card here.
|
// There should never be more than one card here.
|
||||||
for (Card card : cards.getCards(game)) {
|
for (Card card : cards.getCards(game)) {
|
||||||
|
Spell spell;
|
||||||
if (info instanceof ZoneChangeInfo.Stack && ((ZoneChangeInfo.Stack) info).spell != null) {
|
if (info instanceof ZoneChangeInfo.Stack && ((ZoneChangeInfo.Stack) info).spell != null) {
|
||||||
game.getStack().push(((ZoneChangeInfo.Stack) info).spell);
|
spell = ((ZoneChangeInfo.Stack) info).spell;
|
||||||
} else {
|
} else {
|
||||||
game.getStack().push(
|
spell = new Spell(card, card.getSpellAbility().copy(), card.getOwnerId(), event.getFromZone());
|
||||||
new Spell(card, card.getSpellAbility().copy(), card.getOwnerId(), event.getFromZone()));
|
|
||||||
}
|
}
|
||||||
|
game.getStack().push(spell);
|
||||||
|
game.getState().setZone(spell.getId(), Zone.STACK);
|
||||||
|
game.getState().setZone(card.getId(), Zone.STACK);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BATTLEFIELD:
|
case BATTLEFIELD:
|
||||||
|
|
|
||||||
|
|
@ -410,7 +410,7 @@ public class Spell extends StackObjImpl implements Card {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Copied spell, only remove from stack
|
// Copied spell, only remove from stack
|
||||||
game.getStack().remove(this);
|
game.getStack().remove(this, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -772,7 +772,7 @@ public class Spell extends StackObjImpl implements Card {
|
||||||
@Override
|
@Override
|
||||||
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
|
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
|
||||||
if (this.isCopiedSpell()) {
|
if (this.isCopiedSpell()) {
|
||||||
game.getStack().remove(this);
|
game.getStack().remove(this, game);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return this.card.moveToExile(exileId, name, sourceId, game, appliedEffects);
|
return this.card.moveToExile(exileId, name, sourceId, game, appliedEffects);
|
||||||
|
|
|
||||||
|
|
@ -67,15 +67,16 @@ public class SpellStack extends ArrayDeque<StackObject> {
|
||||||
if (top != null) {
|
if (top != null) {
|
||||||
if (contains(top)) {
|
if (contains(top)) {
|
||||||
logger.warn("StackObject was still on the stack after resoving" + top.getName());
|
logger.warn("StackObject was still on the stack after resoving" + top.getName());
|
||||||
this.remove(top);
|
this.remove(top, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean remove(StackObject object) {
|
public boolean remove(StackObject object, Game game) {
|
||||||
for (StackObject spell : this) {
|
for (StackObject spell : this) {
|
||||||
if (spell.getId().equals(object.getId())) {
|
if (spell.getId().equals(object.getId())) {
|
||||||
|
game.getState().setZone(spell.getId(), null);
|
||||||
return super.remove(spell);
|
return super.remove(spell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +108,7 @@ public class SpellStack extends ArrayDeque<StackObject> {
|
||||||
}
|
}
|
||||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, sourceId, stackObject.getControllerId()))) {
|
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, sourceId, stackObject.getControllerId()))) {
|
||||||
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, game);
|
||||||
}
|
}
|
||||||
stackObject.counter(sourceId, game, zone, owner, zoneDetail);
|
stackObject.counter(sourceId, game, zone, owner, zoneDetail);
|
||||||
if (!game.isSimulation()) {
|
if (!game.isSimulation()) {
|
||||||
|
|
|
||||||
|
|
@ -101,14 +101,14 @@ public class StackAbility extends StackObjImpl implements Ability {
|
||||||
public boolean resolve(Game game) {
|
public boolean resolve(Game game) {
|
||||||
if (ability.getTargets().stillLegal(ability, game) || !canFizzle()) {
|
if (ability.getTargets().stillLegal(ability, game) || !canFizzle()) {
|
||||||
boolean result = ability.resolve(game);
|
boolean result = ability.resolve(game);
|
||||||
game.getStack().remove(this);
|
game.getStack().remove(this, game);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (!game.isSimulation()) {
|
if (!game.isSimulation()) {
|
||||||
game.informPlayers("Ability has been fizzled: " + getRule());
|
game.informPlayers("Ability has been fizzled: " + getRule());
|
||||||
}
|
}
|
||||||
counter(null, game);
|
counter(null, game);
|
||||||
game.getStack().remove(this);
|
game.getStack().remove(this, game);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -284,7 +284,7 @@ public class Turn implements Serializable {
|
||||||
if (stackObject instanceof Spell) {
|
if (stackObject instanceof Spell) {
|
||||||
((Spell) stackObject).moveToExile(null, "", source.getSourceId(), game);
|
((Spell) stackObject).moveToExile(null, "", source.getSourceId(), game);
|
||||||
} else {
|
} else {
|
||||||
game.getStack().remove(stackObject); // stack ability
|
game.getStack().remove(stackObject, game); // stack ability
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2) All attacking and blocking creatures are removed from combat.
|
// 2) All attacking and blocking creatures are removed from combat.
|
||||||
|
|
|
||||||
|
|
@ -3687,7 +3687,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
final Spell spell = (Spell) card;
|
final Spell spell = (Spell) card;
|
||||||
if (spell.isCopiedSpell()) {
|
if (spell.isCopiedSpell()) {
|
||||||
// Copied spell, only remove from stack
|
// Copied spell, only remove from stack
|
||||||
game.getStack().remove(spell);
|
game.getStack().remove(spell, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() + (card.isCopy() ? " (Copy)" : "") : "a card face down") + ' '
|
game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() + (card.isCopy() ? " (Copy)" : "") : "a card face down") + ' '
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue