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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -430,7 +430,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
}
|
||||
stackObject.resolve(game);
|
||||
if (stackObject instanceof StackAbility) {
|
||||
game.getStack().remove(stackObject);
|
||||
game.getStack().remove(stackObject, game);
|
||||
}
|
||||
game.applyEffects();
|
||||
game.getPlayers().resetPassed();
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class NorinTheWaryTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
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
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.cards.u;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -37,8 +36,8 @@ import mage.abilities.keyword.UnearthAbility;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
|
|
@ -56,8 +55,9 @@ public class UndeadLeotau extends CardImpl {
|
|||
this.toughness = new MageInt(4);
|
||||
|
||||
// {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}")));
|
||||
|
||||
// Unearth {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.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
|
|
@ -59,6 +59,7 @@ public class VoiceOfAll extends CardImpl {
|
|||
// As Voice of All enters the battlefield, choose a color.
|
||||
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()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,14 +6,11 @@ import mage.constants.PhaseStep;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.permanent.Permanent;
|
||||
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.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author noxx
|
||||
|
|
@ -179,6 +176,9 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
|
|||
@Test
|
||||
public void testCopyEntersTapped() {
|
||||
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.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
|
||||
* and/or permanents you control this turn is dealt to any target
|
||||
* instead.
|
||||
* and/or permanents you control this turn is dealt to any target instead.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
|
|
@ -23,7 +22,7 @@ public class HarmsWayRedirectDamageTest extends CardTestPlayerBase {
|
|||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
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");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
|
|
@ -33,6 +32,9 @@ public class HarmsWayRedirectDamageTest extends CardTestPlayerBase {
|
|||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||
assertGraveyardCount(playerB, "Harm's Way", 1);
|
||||
|
||||
// 2 damage was redirected back
|
||||
assertLife(playerA, 18);
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ package org.mage.test.cards.single.bfz;
|
|||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,8 @@ public abstract class AbilityImpl implements Ability {
|
|||
public void newId() {
|
||||
if (!(this instanceof MageSingleton)) {
|
||||
this.id = UUID.randomUUID();
|
||||
// this.sourceObject = null;
|
||||
// this.sourceObjectZoneChangeCounter = -1;
|
||||
}
|
||||
getEffects().newId();
|
||||
}
|
||||
|
|
@ -1211,7 +1213,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
|
||||
@Override
|
||||
public Permanent getSourcePermanentIfItStillExists(Game game) {
|
||||
if (sourceObject == null) {
|
||||
if (sourceObject == null || !sourceObject.getId().equals(getSourceId())) {
|
||||
setSourceObject(game.getObject(getSourceId()), game);
|
||||
}
|
||||
if (sourceObject instanceof Permanent) {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class ExileFromStackCost extends CostImpl {
|
|||
}
|
||||
String spellName = spellToExile.getName();
|
||||
if (spellToExile.isCopy()) {
|
||||
game.getStack().remove(spellToExile);
|
||||
game.getStack().remove(spellToExile, game);
|
||||
} else {
|
||||
spellToExile.moveToExile(null, "", ability.getSourceId(), game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.Objects;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
|
|
@ -36,8 +37,6 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
|
|
@ -67,6 +66,17 @@ public class CantBeRegeneratedSourceEffect extends ContinuousRuleModifyingEffect
|
|||
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
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
return Objects.equals(source.getSourceId(), event.getTargetId());
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class DestroySourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent != null) {
|
||||
permanent.destroy(source.getSourceId(), game, noRegen);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
|
@ -50,21 +51,19 @@ public class FightTargetSourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent originalPermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
if (originalPermanent != null) {
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
// only if target is legal the effect will be applied
|
||||
if (source.getTargets().get(0).isLegal(source, game)) {
|
||||
Permanent creature1 = game.getPermanent(source.getTargets().get(0).getFirstTarget());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (sourceObject != null) {
|
||||
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
|
||||
Permanent creature1 = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
// 20110930 - 701.10
|
||||
if (creature1 != null && sourcePermanent != null) {
|
||||
if (creature1.isCreature() && sourcePermanent.isCreature()) {
|
||||
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;
|
||||
}
|
||||
|
|
@ -83,4 +82,3 @@ public class FightTargetSourceEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,9 @@ import mage.abilities.effects.OneShotEffect;
|
|||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.TokenImpl;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
|
||||
|
||||
/**
|
||||
* @author Loki
|
||||
*/
|
||||
|
|
@ -33,14 +31,15 @@ public class FlipSourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (permanent != null && controller != null) {
|
||||
if (permanent.flip(game)) {
|
||||
ContinuousEffect effect = new ConditionalContinuousEffect(new CopyTokenEffect(flipToken), FlippedCondition.instance, "");
|
||||
game.addEffect(effect, source);
|
||||
if (!game.isSimulation())
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(new StringBuilder(controller.getLogName()).append(" flips ").append(permanent.getName()).toString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
|
|
@ -34,9 +33,8 @@ public class PhaseOutSourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
|
||||
if (sourceObject instanceof Permanent) {
|
||||
Permanent permanent = (Permanent) sourceObject;
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent != null) {
|
||||
return permanent.phaseOut(game);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,17 @@ public class PreventDamageToSourceEffect extends PreventionEffectImpl {
|
|||
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
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -28,12 +28,18 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -43,21 +49,25 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
|
|||
|
||||
private boolean tapped;
|
||||
private boolean ownerControl;
|
||||
private boolean haste;
|
||||
|
||||
public ReturnSourceFromGraveyardToBattlefieldEffect() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped) {
|
||||
super(Outcome.PutCreatureInPlay);
|
||||
this.tapped = tapped;
|
||||
setText();
|
||||
this(tapped, true);
|
||||
}
|
||||
|
||||
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped, boolean ownerControl) {
|
||||
this(tapped, ownerControl, false);
|
||||
}
|
||||
|
||||
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped, boolean ownerControl, boolean haste) {
|
||||
super(Outcome.PutCreatureInPlay);
|
||||
this.tapped = tapped;
|
||||
this.ownerControl = ownerControl;
|
||||
this.haste = haste;
|
||||
setText();
|
||||
}
|
||||
|
||||
|
|
@ -65,6 +75,7 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
|
|||
super(effect);
|
||||
this.tapped = effect.tapped;
|
||||
this.ownerControl = effect.ownerControl;
|
||||
this.haste = effect.haste;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -89,6 +100,14 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
|
|||
}
|
||||
if (game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import mage.cards.Card;
|
|||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -81,16 +82,17 @@ public class ReturnToBattlefieldUnderOwnerControlSourceEffect extends OneShotEff
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
if (controller != null && card != null) {
|
||||
// return only from public zones
|
||||
switch (game.getState().getZone(card.getId())) {
|
||||
case EXILED:
|
||||
case COMMAND:
|
||||
case GRAVEYARD:
|
||||
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) {
|
||||
game.getCombat().addAttackingCreature(card.getId(), game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public class ReturnToHandTargetEffect extends OneShotEffect {
|
|||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,10 +63,7 @@ public class TapSourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
permanent = game.getPermanentEntering(source.getSourceId());
|
||||
}
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent != null) {
|
||||
if (withoutTrigger) {
|
||||
permanent.setTapped(true);
|
||||
|
|
|
|||
|
|
@ -92,6 +92,13 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou
|
|||
@Override
|
||||
public void init(Ability source, Game 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) {
|
||||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import mage.constants.Outcome;
|
|||
import mage.constants.SubLayer;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Noahsark
|
||||
|
|
@ -40,6 +41,17 @@ public class LoseAbilitySourceEffect extends ContinuousEffectImpl{
|
|||
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
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
|
|
|
|||
|
|
@ -69,6 +69,17 @@ public class LoseCreatureTypeSourceEffect extends ContinuousEffectImpl implement
|
|||
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
|
||||
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
||||
if (dynamicValue.calculate(game, source, this) >= lessThan) {
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@
|
|||
*/
|
||||
package mage.abilities.effects.common.continuous;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
|
|
@ -55,14 +55,29 @@ public class SwitchPowerToughnessSourceEffect extends ContinuousEffectImpl {
|
|||
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
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent target = game.getPermanent(source.getSourceId());
|
||||
if (target != null) {
|
||||
int power = target.getPower().getValue();
|
||||
target.getPower().setValue(target.getToughness().getValue());
|
||||
target.getToughness().setValue(power);
|
||||
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (sourcePermanent != null) {
|
||||
int power = sourcePermanent.getPower().getValue();
|
||||
sourcePermanent.getPower().setValue(sourcePermanent.getToughness().getValue());
|
||||
sourcePermanent.getToughness().setValue(power);
|
||||
return true;
|
||||
} else {
|
||||
if (duration.isOnlyValidIfNoZoneChange()) {
|
||||
discard();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public class RemoveAllCountersSourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent != null) {
|
||||
int count = permanent.getCounters(game).getCount(counterType);
|
||||
permanent.removeCounters(counterType.getName(), count, game);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent != null) {
|
||||
int toRemove = Math.min(counter.getCount(), permanent.getCounters(game).getCount(counter.getName()));
|
||||
if (toRemove > 0) {
|
||||
|
|
@ -67,6 +67,7 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
if (!(source.getSourceObject(game) instanceof Permanent)) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
int toRemove = Math.min(counter.getCount(), card.getCounters(game).getCount(counter.getName()));
|
||||
|
|
@ -80,6 +81,7 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ import mage.abilities.effects.ReplacementEffectImpl;
|
|||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||
import mage.abilities.effects.common.ExileSourceEffect;
|
||||
import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TimingRule;
|
||||
|
|
@ -63,9 +62,8 @@ import mage.game.events.ZoneChangeEvent;
|
|||
public class UnearthAbility extends ActivatedAbilityImpl {
|
||||
|
||||
public UnearthAbility(ManaCosts costs) {
|
||||
super(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), costs);
|
||||
super(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, true, true), costs);
|
||||
this.timing = TimingRule.SORCERY;
|
||||
this.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom));
|
||||
this.addEffect(new CreateDelayedTriggeredAbilityEffect(new UnearthDelayedTriggeredAbility()));
|
||||
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.PowerPredicate;
|
||||
import mage.game.*;
|
||||
import mage.game.command.CommandObject;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
|
@ -618,14 +619,18 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
stackObject = game.getStack().getSpell(getId());
|
||||
}
|
||||
if (stackObject != null) {
|
||||
removed = game.getStack().remove(stackObject);
|
||||
removed = game.getStack().remove(stackObject, game);
|
||||
lkiObject = stackObject;
|
||||
}
|
||||
break;
|
||||
case COMMAND:
|
||||
lkiObject = game.getObject(objectId);
|
||||
for (CommandObject commandObject : game.getState().getCommand()) {
|
||||
if (commandObject.getId().equals(objectId)) {
|
||||
lkiObject = commandObject;
|
||||
}
|
||||
}
|
||||
if (lkiObject != null) {
|
||||
removed = game.getState().getCommand().remove(game.getObject(objectId));
|
||||
removed = game.getState().getCommand().remove((CommandObject) lkiObject);
|
||||
}
|
||||
break;
|
||||
case OUTSIDE:
|
||||
|
|
|
|||
|
|
@ -5,21 +5,23 @@ package mage.constants;
|
|||
* @author North
|
||||
*/
|
||||
public enum Duration {
|
||||
OneUse(""),
|
||||
EndOfGame("for the rest of the game"),
|
||||
WhileOnBattlefield(""),
|
||||
WhileOnStack(""),
|
||||
WhileInGraveyard(""),
|
||||
EndOfTurn("until end of turn"),
|
||||
UntilYourNextTurn("until your next turn"),
|
||||
EndOfCombat("until end of combat"),
|
||||
EndOfStep("until end of phase step"),
|
||||
Custom("");
|
||||
OneUse("", true),
|
||||
EndOfGame("for the rest of the game", false),
|
||||
WhileOnBattlefield("", false),
|
||||
WhileOnStack("", false),
|
||||
WhileInGraveyard("", false),
|
||||
EndOfTurn("until end of turn", true),
|
||||
UntilYourNextTurn("until your next turn", true),
|
||||
EndOfCombat("until end of combat", true),
|
||||
EndOfStep("until end of phase step", true),
|
||||
Custom("", true);
|
||||
|
||||
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.onlyValidIfNoZoneChange = onlyValidIfNoZoneChange;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -27,4 +29,8 @@ public enum Duration {
|
|||
return text;
|
||||
}
|
||||
|
||||
public boolean isOnlyValidIfNoZoneChange() {
|
||||
return onlyValidIfNoZoneChange;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -328,12 +328,15 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
MageObject object;
|
||||
if (state.getBattlefield().containsPermanent(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;
|
||||
}
|
||||
if (getPermanentsEntering().containsKey(objectId)) {
|
||||
return getPermanentEntering(objectId);
|
||||
}
|
||||
for (StackObject item : state.getStack()) {
|
||||
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;
|
||||
}
|
||||
if (item.getSourceId().equals(objectId) && item instanceof Spell) {
|
||||
|
|
@ -1421,7 +1424,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
top.resolve(this);
|
||||
} finally {
|
||||
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);
|
||||
checkInfiniteLoop(top.getSourceId());
|
||||
if (!getTurn().isEndTurnRequested()) {
|
||||
|
|
|
|||
|
|
@ -685,8 +685,12 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
}
|
||||
|
||||
public void setZone(UUID id, Zone zone) {
|
||||
if (zone == null) {
|
||||
zones.remove(id);
|
||||
} else {
|
||||
zones.put(id, zone);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSimultaneousEvent(GameEvent event, Game game) {
|
||||
simultaneousEvents.add(event);
|
||||
|
|
|
|||
|
|
@ -134,12 +134,15 @@ public final class ZonesHandler {
|
|||
case STACK:
|
||||
// There should never be more than one card here.
|
||||
for (Card card : cards.getCards(game)) {
|
||||
Spell spell;
|
||||
if (info instanceof ZoneChangeInfo.Stack && ((ZoneChangeInfo.Stack) info).spell != null) {
|
||||
game.getStack().push(((ZoneChangeInfo.Stack) info).spell);
|
||||
spell = ((ZoneChangeInfo.Stack) info).spell;
|
||||
} else {
|
||||
game.getStack().push(
|
||||
new Spell(card, card.getSpellAbility().copy(), card.getOwnerId(), event.getFromZone()));
|
||||
spell = 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;
|
||||
case BATTLEFIELD:
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ public class Spell extends StackObjImpl implements Card {
|
|||
}
|
||||
} else {
|
||||
// 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
|
||||
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
|
||||
if (this.isCopiedSpell()) {
|
||||
game.getStack().remove(this);
|
||||
game.getStack().remove(this, game);
|
||||
return true;
|
||||
}
|
||||
return this.card.moveToExile(exileId, name, sourceId, game, appliedEffects);
|
||||
|
|
|
|||
|
|
@ -67,15 +67,16 @@ public class SpellStack extends ArrayDeque<StackObject> {
|
|||
if (top != null) {
|
||||
if (contains(top)) {
|
||||
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) {
|
||||
if (spell.getId().equals(object.getId())) {
|
||||
game.getState().setZone(spell.getId(), null);
|
||||
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 (!(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);
|
||||
if (!game.isSimulation()) {
|
||||
|
|
|
|||
|
|
@ -101,14 +101,14 @@ public class StackAbility extends StackObjImpl implements Ability {
|
|||
public boolean resolve(Game game) {
|
||||
if (ability.getTargets().stillLegal(ability, game) || !canFizzle()) {
|
||||
boolean result = ability.resolve(game);
|
||||
game.getStack().remove(this);
|
||||
game.getStack().remove(this, game);
|
||||
return result;
|
||||
}
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers("Ability has been fizzled: " + getRule());
|
||||
}
|
||||
counter(null, game);
|
||||
game.getStack().remove(this);
|
||||
game.getStack().remove(this, game);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ public class Turn implements Serializable {
|
|||
if (stackObject instanceof Spell) {
|
||||
((Spell) stackObject).moveToExile(null, "", source.getSourceId(), game);
|
||||
} else {
|
||||
game.getStack().remove(stackObject); // stack ability
|
||||
game.getStack().remove(stackObject, game); // stack ability
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
if (spell.isCopiedSpell()) {
|
||||
// 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") + ' '
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue