mirror of
https://github.com/correl/mage.git
synced 2024-11-14 19:19:32 +00: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();
|
||||
|
@ -968,7 +968,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
// swallow
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(scanner != null) {
|
||||
if (scanner != null) {
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ import mage.game.events.GameEvent.EventType;
|
|||
public class NorinTheWary extends CardImpl {
|
||||
|
||||
public NorinTheWary(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}");
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.WARRIOR);
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -47,21 +46,22 @@ import mage.constants.Zone;
|
|||
*/
|
||||
public class UndeadLeotau extends CardImpl {
|
||||
|
||||
public UndeadLeotau (UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}");
|
||||
public UndeadLeotau(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}");
|
||||
this.subtype.add(SubType.ZOMBIE);
|
||||
this.subtype.add(SubType.CAT);
|
||||
|
||||
this.power = new MageInt(3);
|
||||
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}")));
|
||||
}
|
||||
|
||||
public UndeadLeotau (final UndeadLeotau card) {
|
||||
public UndeadLeotau(final UndeadLeotau card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -48,17 +48,18 @@ import mage.constants.Zone;
|
|||
public class VoiceOfAll extends CardImpl {
|
||||
|
||||
public VoiceOfAll(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{W}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}");
|
||||
this.subtype.add(SubType.ANGEL);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
|
||||
// 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()));
|
||||
}
|
||||
|
||||
|
@ -70,4 +71,4 @@ public class VoiceOfAll extends CardImpl {
|
|||
public VoiceOfAll copy() {
|
||||
return new VoiceOfAll(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
// 20110930 - 701.10
|
||||
if (creature1 != null && sourcePermanent != null) {
|
||||
if (creature1.isCreature() && sourcePermanent.isCreature()) {
|
||||
return sourcePermanent.fight(creature1, source, game);
|
||||
}
|
||||
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(originalPermanent.getLogName() + ": Fighting effect has been fizzled.");
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(sourceObject.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,38 +12,50 @@ import mage.constants.Outcome;
|
|||
import mage.constants.SubLayer;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Noahsark
|
||||
*/
|
||||
public class LoseAbilitySourceEffect extends ContinuousEffectImpl{
|
||||
public class LoseAbilitySourceEffect extends ContinuousEffectImpl {
|
||||
|
||||
protected Ability ability;
|
||||
|
||||
public LoseAbilitySourceEffect(Ability ability){
|
||||
public LoseAbilitySourceEffect(Ability ability) {
|
||||
this(ability, Duration.WhileOnBattlefield);
|
||||
}
|
||||
|
||||
public LoseAbilitySourceEffect(Ability ability, Duration duration){
|
||||
public LoseAbilitySourceEffect(Ability ability, Duration duration) {
|
||||
super(duration, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.LoseAbility);
|
||||
this.ability = ability;
|
||||
staticText = "{this} loses " + ability.getRule() + ' ' + duration.toString();
|
||||
}
|
||||
|
||||
public LoseAbilitySourceEffect(final LoseAbilitySourceEffect effect){
|
||||
public LoseAbilitySourceEffect(final LoseAbilitySourceEffect effect) {
|
||||
super(effect);
|
||||
this.ability = effect.ability.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoseAbilitySourceEffect copy(){
|
||||
public LoseAbilitySourceEffect copy() {
|
||||
return new LoseAbilitySourceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source){
|
||||
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());
|
||||
if (permanent != null){
|
||||
if (permanent != null) {
|
||||
// 112.10
|
||||
while (permanent.getAbilities().remove(ability)) {
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
* 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
|
||||
|
@ -20,19 +20,19 @@
|
|||
* 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.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;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ import mage.game.permanent.Permanent;
|
|||
* @author TheElk801
|
||||
*/
|
||||
public class RemoveAllCountersSourceEffect extends OneShotEffect {
|
||||
|
||||
|
||||
private final CounterType counterType;
|
||||
|
||||
public RemoveAllCountersSourceEffect(CounterType counterType) {
|
||||
|
@ -55,13 +55,13 @@ public class RemoveAllCountersSourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if(permanent != null) {
|
||||
int count = permanent.getCounters(game).getCount(counterType);
|
||||
permanent.removeCounters(counterType.getName(), count, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent != null) {
|
||||
int count = permanent.getCounters(game).getCount(counterType);
|
||||
permanent.removeCounters(counterType.getName(), count, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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,18 +67,20 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
int toRemove = Math.min(counter.getCount(), card.getCounters(game).getCount(counter.getName()));
|
||||
if (toRemove > 0) {
|
||||
card.removeCounters(counter.getName(), toRemove, game);
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers("Removed " + toRemove + ' ' + counter.getName()
|
||||
+ " counter from " + card.getLogName()
|
||||
+ " (" + card.getCounters(game).getCount(counter.getName()) + " left)");
|
||||
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()));
|
||||
if (toRemove > 0) {
|
||||
card.removeCounters(counter.getName(), toRemove, game);
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers("Removed " + toRemove + ' ' + counter.getName()
|
||||
+ " counter from " + card.getLogName()
|
||||
+ " (" + card.getCounters(game).getCount(counter.getName()) + " left)");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
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()) {
|
||||
|
@ -2581,10 +2584,10 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (addPlaneAgain) {
|
||||
boolean addedAgain = false;
|
||||
for (Player aplayer : state.getPlayers().values()) {
|
||||
for (Player aplayer : state.getPlayers().values()) {
|
||||
if (!aplayer.hasLeft() && !addedAgain) {
|
||||
addedAgain = true;
|
||||
Plane plane = Plane.getRandomPlane();
|
||||
|
|
|
@ -685,7 +685,11 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
}
|
||||
|
||||
public void setZone(UUID id, Zone zone) {
|
||||
zones.put(id, zone);
|
||||
if (zone == null) {
|
||||
zones.remove(id);
|
||||
} else {
|
||||
zones.put(id, zone);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSimultaneousEvent(GameEvent event, Game game) {
|
||||
|
|
|
@ -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…
Reference in a new issue