mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
* Reworked/Cleaned card movement handling.
This commit is contained in:
parent
0f15f4a808
commit
8b8097878c
54 changed files with 714 additions and 687 deletions
|
@ -436,29 +436,32 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
}
|
||||
|
||||
protected void resolve(SimulationNode2 node, int depth, Game game) {
|
||||
StackObject ability = game.getStack().pop();
|
||||
if (ability instanceof StackAbility) {
|
||||
SearchEffect effect = getSearchEffect((StackAbility) ability);
|
||||
if (effect != null && ability.getControllerId().equals(playerId)) {
|
||||
StackObject stackObject = game.getStack().getFirst();
|
||||
if (stackObject instanceof StackAbility) {
|
||||
SearchEffect effect = getSearchEffect((StackAbility) stackObject);
|
||||
if (effect != null && stackObject.getControllerId().equals(playerId)) {
|
||||
Target target = effect.getTarget();
|
||||
if (!target.doneChosing()) {
|
||||
for (UUID targetId : target.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) {
|
||||
for (UUID targetId : target.possibleTargets(stackObject.getSourceId(), stackObject.getControllerId(), game)) {
|
||||
Game sim = game.copy();
|
||||
StackAbility newAbility = (StackAbility) ability.copy();
|
||||
StackAbility newAbility = (StackAbility) stackObject.copy();
|
||||
SearchEffect newEffect = getSearchEffect(newAbility);
|
||||
newEffect.getTarget().addTarget(targetId, newAbility, sim);
|
||||
sim.getStack().push(newAbility);
|
||||
SimulationNode2 newNode = new SimulationNode2(node, sim, depth, ability.getControllerId());
|
||||
SimulationNode2 newNode = new SimulationNode2(node, sim, depth, stackObject.getControllerId());
|
||||
node.children.add(newNode);
|
||||
newNode.getTargets().add(targetId);
|
||||
logger.trace("Sim search -- node#: " + SimulationNode2.getCount() + " for player: " + sim.getPlayer(ability.getControllerId()).getName());
|
||||
logger.trace("Sim search -- node#: " + SimulationNode2.getCount() + " for player: " + sim.getPlayer(stackObject.getControllerId()).getName());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
//logger.info("simulating resolve ");
|
||||
ability.resolve(game);
|
||||
stackObject.resolve(game);
|
||||
if (stackObject instanceof StackAbility) {
|
||||
game.getStack().remove(stackObject);
|
||||
}
|
||||
game.applyEffects();
|
||||
game.getPlayers().resetPassed();
|
||||
game.getPlayerList().setCurrent(game.getActivePlayerId());
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
*/
|
||||
package mage.sets.avacynrestored;
|
||||
|
||||
import mage.constants.*;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
|
@ -37,6 +38,11 @@ import mage.abilities.effects.ReplacementEffectImpl;
|
|||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
|
@ -47,8 +53,6 @@ import mage.target.TargetPermanent;
|
|||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.util.functions.EmptyApplyToPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
|
@ -60,7 +64,6 @@ public class InfiniteReflection extends CardImpl {
|
|||
this.expansionSetCode = "AVR";
|
||||
this.subtype.add("Aura");
|
||||
|
||||
|
||||
// Enchant creature
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
this.getSpellAbility().addTarget(auraTarget);
|
||||
|
@ -109,9 +112,9 @@ class InfiniteReflectionTriggeredEffect extends OneShotEffect {
|
|||
if (sourcePermanent != null && sourcePermanent.getAttachedTo() != null) {
|
||||
Permanent toCopyFromPermanent = game.getPermanent(sourcePermanent.getAttachedTo());
|
||||
if (toCopyFromPermanent != null) {
|
||||
for (Permanent toCopyToPermanent: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) {
|
||||
for (Permanent toCopyToPermanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) {
|
||||
if (!toCopyToPermanent.equals(toCopyFromPermanent) && !(toCopyToPermanent instanceof PermanentToken)) {
|
||||
game.copyPermanent(toCopyFromPermanent, toCopyToPermanent, source, new EmptyApplyToPermanent());
|
||||
game.copyPermanent(toCopyFromPermanent, toCopyToPermanent.getId(), source, new EmptyApplyToPermanent());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -144,15 +147,14 @@ class InfiniteReflectionEntersBattlefieldEffect extends ReplacementEffectImpl {
|
|||
&& !(permanent instanceof PermanentToken);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Permanent toCopyToPermanent = game.getPermanent(event.getTargetId());
|
||||
MageObject toCopyToObject = game.getObject(event.getTargetId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (sourcePermanent != null && toCopyToPermanent != null && sourcePermanent.getAttachedTo() != null) {
|
||||
if (sourcePermanent != null && toCopyToObject != null && sourcePermanent.getAttachedTo() != null) {
|
||||
Permanent toCopyFromPermanent = game.getPermanent(sourcePermanent.getAttachedTo());
|
||||
if (toCopyFromPermanent != null) {
|
||||
game.copyPermanent(toCopyFromPermanent, toCopyToPermanent, source, new EmptyApplyToPermanent());
|
||||
game.copyPermanent(toCopyFromPermanent, toCopyToObject.getId(), source, new EmptyApplyToPermanent());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -157,7 +157,6 @@ class PossibilityStormEffect extends OneShotEffect {
|
|||
if (exile != null) {
|
||||
while (exile.size() > 0) {
|
||||
card = exile.getRandom(game);
|
||||
exile.remove(card.getId());
|
||||
spellController.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.EXILED, false, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,13 +55,6 @@ import mage.players.Player;
|
|||
*/
|
||||
public class MycosynthGolem extends CardImpl {
|
||||
|
||||
private static final FilterSpell filter = new FilterSpell("Artifact creature spells you cast");
|
||||
|
||||
static {
|
||||
filter.add(new CardTypePredicate(CardType.ARTIFACT));
|
||||
filter.add(new CardTypePredicate(CardType.CREATURE));
|
||||
}
|
||||
|
||||
public MycosynthGolem(UUID ownerId) {
|
||||
super(ownerId, 137, "Mycosynth Golem", Rarity.RARE, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{11}");
|
||||
this.expansionSetCode = "5DN";
|
||||
|
@ -75,7 +68,7 @@ public class MycosynthGolem extends CardImpl {
|
|||
|
||||
// Artifact creature spells you cast have affinity for artifacts.
|
||||
this.addAbility(new SimpleStaticAbility(
|
||||
Zone.BATTLEFIELD, new MycosynthGolemGainAbilitySpellsEffect(new AffinityForArtifactsAbility(), filter)));
|
||||
Zone.BATTLEFIELD, new MycosynthGolemGainAbilitySpellsEffect()));
|
||||
|
||||
}
|
||||
|
||||
|
@ -91,20 +84,21 @@ public class MycosynthGolem extends CardImpl {
|
|||
|
||||
class MycosynthGolemGainAbilitySpellsEffect extends ContinuousEffectImpl {
|
||||
|
||||
private final Ability ability;
|
||||
private final FilterSpell filter;
|
||||
private static final FilterSpell filter = new FilterSpell("Artifact creature spells you cast");
|
||||
private static final Ability ability = new AffinityForArtifactsAbility();
|
||||
|
||||
public MycosynthGolemGainAbilitySpellsEffect(Ability ability, FilterSpell filter) {
|
||||
static {
|
||||
filter.add(new CardTypePredicate(CardType.ARTIFACT));
|
||||
filter.add(new CardTypePredicate(CardType.CREATURE));
|
||||
}
|
||||
|
||||
public MycosynthGolemGainAbilitySpellsEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
|
||||
this.ability = ability;
|
||||
this.filter = filter;
|
||||
staticText = filter.getMessage() + " have " + ability.getRule();
|
||||
staticText = "Artifact creature spells you cast have affinity for artifacts";
|
||||
}
|
||||
|
||||
public MycosynthGolemGainAbilitySpellsEffect(final MycosynthGolemGainAbilitySpellsEffect effect) {
|
||||
super(effect);
|
||||
this.ability = effect.ability;
|
||||
this.filter = effect.filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -114,17 +108,15 @@ class MycosynthGolemGainAbilitySpellsEffect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && permanent != null) {
|
||||
if (controller != null && permanent != null) {
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
// only spells cast, so no copies of spells
|
||||
if ((stackObject instanceof Spell) && !stackObject.isCopy() && stackObject.getControllerId().equals(source.getControllerId())) {
|
||||
Spell spell = (Spell) stackObject;
|
||||
if (filter.match(spell, game)) {
|
||||
if (!spell.getAbilities().contains(ability)) {
|
||||
game.getState().addOtherAbility(spell.getCard(), ability);
|
||||
}
|
||||
game.getState().addOtherAbility(spell.getCard(), ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
package mage.sets.gatecrash;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
@ -39,6 +35,9 @@ import mage.abilities.costs.mana.GenericManaCost;
|
|||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.mana.ColorlessManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
@ -80,7 +79,7 @@ class ThespiansStageCopyEffect extends OneShotEffect {
|
|||
|
||||
public ThespiansStageCopyEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "Thespian's Stage becomes a copy of target land and gains this ability";
|
||||
this.staticText = "{this} becomes a copy of target land and gains this ability";
|
||||
}
|
||||
|
||||
public ThespiansStageCopyEffect(final ThespiansStageCopyEffect effect) {
|
||||
|
@ -97,7 +96,7 @@ class ThespiansStageCopyEffect extends OneShotEffect {
|
|||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
Permanent copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
if (sourcePermanent != null && copyFromPermanent != null) {
|
||||
Permanent newPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent, source, new EmptyApplyToPermanent());
|
||||
Permanent newPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent());
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ThespiansStageCopyEffect(), new GenericManaCost(2));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addTarget(new TargetLandPermanent());
|
||||
|
|
|
@ -74,12 +74,11 @@ public class MizziumTransreliquat extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
class MizziumTransreliquatCopyEffect extends OneShotEffect {
|
||||
|
||||
public MizziumTransreliquatCopyEffect() {
|
||||
super(Outcome.Copy);
|
||||
this.staticText = "Mizzium Transreliquat becomes a copy of target artifact until end of turn";
|
||||
this.staticText = "{this} becomes a copy of target artifact until end of turn";
|
||||
}
|
||||
|
||||
public MizziumTransreliquatCopyEffect(final MizziumTransreliquatCopyEffect effect) {
|
||||
|
@ -96,17 +95,18 @@ class MizziumTransreliquatCopyEffect extends OneShotEffect {
|
|||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
Permanent copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
if (sourcePermanent != null && copyFromPermanent != null) {
|
||||
game.copyPermanent(Duration.EndOfTurn, copyFromPermanent, sourcePermanent, source, new EmptyApplyToPermanent());
|
||||
game.copyPermanent(Duration.EndOfTurn, copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class MizziumTransreliquatCopyAndGainAbilityEffect extends OneShotEffect {
|
||||
|
||||
public MizziumTransreliquatCopyAndGainAbilityEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "Mizzium Transreliquat becomes a copy of target artifact and gains this ability";
|
||||
this.staticText = "{this} becomes a copy of target artifact and gains this ability";
|
||||
}
|
||||
|
||||
public MizziumTransreliquatCopyAndGainAbilityEffect(final MizziumTransreliquatCopyAndGainAbilityEffect effect) {
|
||||
|
@ -123,7 +123,7 @@ class MizziumTransreliquatCopyAndGainAbilityEffect extends OneShotEffect {
|
|||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
Permanent copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
if (sourcePermanent != null && copyFromPermanent != null) {
|
||||
Permanent newPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent, source, new EmptyApplyToPermanent());
|
||||
Permanent newPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent());
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MizziumTransreliquatCopyAndGainAbilityEffect(), new ManaCostsImpl("{1}{U}{R}"));
|
||||
ability.addTarget(new TargetArtifactPermanent());
|
||||
newPermanent.addAbility(ability, source.getSourceId(), game);
|
||||
|
|
|
@ -107,10 +107,10 @@ class PolymorphousRushCopyEffect extends OneShotEffect {
|
|||
if (target.canChoose(source.getId(), controller.getId(), game) && controller.chooseTarget(outcome, target, source, game)) {
|
||||
Permanent copyFromCreature = game.getPermanent(target.getFirstTarget());
|
||||
if (copyFromCreature != null) {
|
||||
for (UUID copyToId: getTargetPointer().getTargets(game, source)) {
|
||||
for (UUID copyToId : getTargetPointer().getTargets(game, source)) {
|
||||
Permanent copyToCreature = game.getPermanent(copyToId);
|
||||
if (copyToCreature != null) {
|
||||
game.copyPermanent(Duration.EndOfTurn, copyFromCreature, copyToCreature, source, new EmptyApplyToPermanent());
|
||||
game.copyPermanent(Duration.EndOfTurn, copyFromCreature, copyToId, source, new EmptyApplyToPermanent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,4 +119,5 @@ class PolymorphousRushCopyEffect extends OneShotEffect {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ class WorldgorgerDragonEntersEffect extends OneShotEffect {
|
|||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller != null) {
|
||||
UUID exileId = CardUtil.getObjectExileZoneId(game, sourceObject);
|
||||
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||
if (exileId != null) {
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) {
|
||||
if (!permanent.getId().equals(source.getSourceId())) { // Another
|
||||
|
@ -145,7 +145,7 @@ class WorldgorgerDragonLeavesEffect extends OneShotEffect {
|
|||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller != null && sourceObject != null) {
|
||||
int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() -1;
|
||||
int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1;
|
||||
ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter));
|
||||
if (exile != null) {
|
||||
exile = exile.copy();
|
||||
|
|
|
@ -114,15 +114,15 @@ class CopyArtifactEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && sourcePermanent != null) {
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (player != null && sourceObject != null) {
|
||||
Target target = new TargetPermanent(filter);
|
||||
target.setNotTarget(true);
|
||||
if (target.canChoose(source.getControllerId(), game)) {
|
||||
player.choose(Outcome.Copy, target, source.getSourceId(), game);
|
||||
Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget());
|
||||
if (copyFromPermanent != null) {
|
||||
game.copyPermanent(copyFromPermanent, sourcePermanent, source, applier);
|
||||
game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, applier);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ import mage.target.TargetPermanent;
|
|||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.util.functions.EmptyApplyToPermanent;
|
||||
|
||||
|
||||
/**
|
||||
* @author duncant
|
||||
*/
|
||||
|
@ -71,8 +70,8 @@ public class Shapesharer extends CardImpl {
|
|||
|
||||
// {2}{U}: Target Shapeshifter becomes a copy of target creature until your next turn.
|
||||
Ability copyAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD,
|
||||
new ShapesharerEffect(),
|
||||
new ManaCostsImpl("{2}{U}"));
|
||||
new ShapesharerEffect(),
|
||||
new ManaCostsImpl("{2}{U}"));
|
||||
copyAbility.addTarget(new TargetPermanent(filterShapeshifter));
|
||||
copyAbility.addTarget(new TargetCreaturePermanent());
|
||||
this.addAbility(copyAbility);
|
||||
|
@ -89,6 +88,7 @@ public class Shapesharer extends CardImpl {
|
|||
}
|
||||
|
||||
class ShapesharerEffect extends OneShotEffect {
|
||||
|
||||
public ShapesharerEffect() {
|
||||
super(Outcome.Copy);
|
||||
this.staticText = "Target Shapeshifter becomes a copy of target creature until your next turn.";
|
||||
|
@ -105,10 +105,12 @@ class ShapesharerEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability ability) {
|
||||
Permanent copyTo = game.getPermanent(ability.getFirstTarget());
|
||||
Permanent copyTo = game.getPermanent(getTargetPointer().getFirst(game, ability));
|
||||
if (copyTo != null) {
|
||||
Permanent copyFrom = game.getPermanentOrLKIBattlefield(ability.getTargets().get(1).getFirstTarget());
|
||||
game.copyPermanent(Duration.EndOfTurn, copyFrom, copyTo, ability, new EmptyApplyToPermanent());
|
||||
if (copyFrom != null) {
|
||||
game.copyPermanent(Duration.EndOfTurn, copyFrom, copyTo.getId(), ability, new EmptyApplyToPermanent());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,12 +25,9 @@
|
|||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.sets.magic2012;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.constants.*;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
|
@ -38,6 +35,11 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
|||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
|
@ -47,20 +49,23 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
*/
|
||||
public class Flight extends CardImpl {
|
||||
|
||||
public Flight (UUID ownerId) {
|
||||
public Flight(UUID ownerId) {
|
||||
super(ownerId, 53, "Flight", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{U}");
|
||||
this.expansionSetCode = "M12";
|
||||
this.subtype.add("Aura");
|
||||
|
||||
// Enchant creature
|
||||
TargetPermanent auraTarget = new TargetCreaturePermanent();
|
||||
this.getSpellAbility().addTarget(auraTarget);
|
||||
this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility));
|
||||
Ability ability = new EnchantAbility(auraTarget.getTargetName());
|
||||
this.addAbility(ability);
|
||||
|
||||
// Enchanted creature has flying.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA)));
|
||||
}
|
||||
|
||||
public Flight (final Flight card) {
|
||||
public Flight(final Flight card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
|
|
|
@ -97,15 +97,15 @@ class PhantasmalImageCopyEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && sourcePermanent != null) {
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (player != null && sourceObject != null) {
|
||||
Target target = new TargetPermanent(new FilterCreaturePermanent("creature (you copy from)"));
|
||||
target.setNotTarget(true);
|
||||
if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) {
|
||||
player.choose(Outcome.Copy, target, source.getSourceId(), game);
|
||||
Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget());
|
||||
if (copyFromPermanent != null) {
|
||||
game.copyPermanent(copyFromPermanent, sourcePermanent, source, new ApplyToPermanent() {
|
||||
game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, new ApplyToPermanent() {
|
||||
@Override
|
||||
public Boolean apply(Game game, Permanent permanent) {
|
||||
if (!permanent.getSubtype().contains("Illusion")) {
|
||||
|
|
|
@ -29,6 +29,7 @@ package mage.sets.magic2015;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
|
@ -96,15 +97,15 @@ class MercurialPretenderCopyEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && sourcePermanent != null) {
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (player != null && sourceObject != null) {
|
||||
Target target = new TargetPermanent(new FilterControlledCreaturePermanent());
|
||||
target.setNotTarget(true);
|
||||
if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) {
|
||||
player.choose(Outcome.Copy, target, source.getSourceId(), game);
|
||||
Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget());
|
||||
if (copyFromPermanent != null) {
|
||||
game.copyPermanent(copyFromPermanent, sourcePermanent, source,
|
||||
game.copyPermanent(copyFromPermanent, sourceObject.getId(), source,
|
||||
// {2}{U}{U}: Return this creature to its owner's hand.
|
||||
new AbilityApplier(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), new ManaCostsImpl("{2}{U}{U}")))
|
||||
);
|
||||
|
|
|
@ -44,6 +44,7 @@ import mage.filter.common.FilterNonlandCard;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInExile;
|
||||
|
@ -100,7 +101,8 @@ class KnowledgePoolEffect1 extends OneShotEffect {
|
|||
Player player = game.getPlayer(playerId);
|
||||
if (player != null) {
|
||||
player.moveCardsToExile(player.getLibrary().getTopCards(game, 3), source, game, true,
|
||||
CardUtil.getObjectExileZoneId(game, sourceObject), sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ")");
|
||||
CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()),
|
||||
sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ")");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -168,7 +170,8 @@ class KnowledgePoolEffect2 extends OneShotEffect {
|
|||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null && spell != null && sourceObject != null) {
|
||||
UUID exileZoneId = CardUtil.getObjectExileZoneId(game, sourceObject);
|
||||
int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1;
|
||||
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter);
|
||||
if (controller.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) {
|
||||
Player player = game.getPlayer(spell.getControllerId());
|
||||
if (player != null && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) {
|
||||
|
|
|
@ -88,7 +88,7 @@ public class PhyrexianMetamorph extends CardImpl {
|
|||
// You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types.
|
||||
Effect effect = new CopyPermanentEffect(filter, phyrexianMetamorphApplier);
|
||||
effect.setText("You may have {this} enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types");
|
||||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect(effect));
|
||||
Ability ability = new SimpleStaticAbility(Zone.ALL, new EntersBattlefieldEffect(effect));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ class SkyshipWeatherlightEffect extends SearchEffect {
|
|||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (sourceObject != null && controller != null) {
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
UUID exileZone = CardUtil.getObjectExileZoneId(game, sourceObject);
|
||||
UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||
if (target.getTargets().size() > 0) {
|
||||
for (UUID cardID : target.getTargets()) {
|
||||
Card card = controller.getLibrary().getCard(cardID, game);
|
||||
|
|
|
@ -46,7 +46,6 @@ import mage.game.permanent.Permanent;
|
|||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.functions.EmptyApplyToPermanent;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
|
@ -142,7 +141,7 @@ class RenegadeDoppelgangerEffect extends OneShotEffect {
|
|||
return false;
|
||||
}
|
||||
|
||||
game.copyPermanent(Duration.EndOfTurn, targetCreature, permanent, source, new EmptyApplyToPermanent());
|
||||
game.copyPermanent(Duration.EndOfTurn, targetCreature, permanent.getId(), source, new EmptyApplyToPermanent());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,15 +98,15 @@ class SakashimaTheImpostorCopyEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && sourcePermanent != null) {
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (player != null && sourceObject != null) {
|
||||
Target target = new TargetPermanent(new FilterCreaturePermanent());
|
||||
target.setNotTarget(true);
|
||||
if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) {
|
||||
player.choose(Outcome.Copy, target, source.getSourceId(), game);
|
||||
Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget());
|
||||
if (copyFromPermanent != null) {
|
||||
game.copyPermanent(copyFromPermanent, sourcePermanent, source, new ApplyToPermanent() {
|
||||
game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, new ApplyToPermanent() {
|
||||
@Override
|
||||
public Boolean apply(Game game, Permanent permanent) {
|
||||
if (!permanent.getSupertype().contains("Legendary")) {
|
||||
|
|
|
@ -99,7 +99,7 @@ class CemeteryPucaEffect extends OneShotEffect {
|
|||
if (copyToCreature != null) {
|
||||
Permanent copyFromCreature = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD);
|
||||
if (copyFromCreature != null) {
|
||||
game.copyPermanent(Duration.WhileOnBattlefield, copyFromCreature, copyToCreature, source, new EmptyApplyToPermanent());
|
||||
game.copyPermanent(Duration.WhileOnBattlefield, copyFromCreature, copyToCreature.getId(), source, new EmptyApplyToPermanent());
|
||||
ContinuousEffect effect = new GainAbilityTargetEffect(new DiesCreatureTriggeredAbility(new DoIfCostPaid(new CemeteryPucaEffect(), new ManaCostsImpl("{1}")), false, new FilterCreaturePermanent("a creature"), true), Duration.WhileOnBattlefield);
|
||||
effect.setTargetPointer(new FixedTarget(copyToCreature.getId()));
|
||||
game.addEffect(effect, source);
|
||||
|
|
|
@ -30,22 +30,16 @@ package mage.sets.shadowmoor;
|
|||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.StateTriggeredAbility;
|
||||
import mage.abilities.common.AsEntersBattlefieldAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.SacrificeSourceEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.choices.ChoiceColor;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -62,7 +56,7 @@ public class LureboundScarecrow extends CardImpl {
|
|||
this.toughness = new MageInt(4);
|
||||
|
||||
// As Lurebound Scarecrow enters the battlefield, choose a color.
|
||||
this.addAbility(new AsEntersBattlefieldAbility(new LureboundScarecrowChooseColorEffect()));
|
||||
this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect()));
|
||||
|
||||
// When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow.
|
||||
this.addAbility(new LureboundScarecrowTriggeredAbility());
|
||||
|
@ -78,40 +72,6 @@ public class LureboundScarecrow extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class LureboundScarecrowChooseColorEffect extends OneShotEffect {
|
||||
|
||||
public LureboundScarecrowChooseColorEffect() {
|
||||
super(Outcome.BoostCreature);
|
||||
staticText = "choose a color";
|
||||
}
|
||||
|
||||
public LureboundScarecrowChooseColorEffect(final LureboundScarecrowChooseColorEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
StackObject sourceStackObject = game.getStack().getStackObject(source.getSourceId());
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && sourceStackObject != null && permanent != null) {
|
||||
ChoiceColor colorChoice = new ChoiceColor();
|
||||
if (player.choose(Outcome.BoostCreature, colorChoice, game)) {
|
||||
game.informPlayers(sourceStackObject.getName() + ": " + player.getLogName() + " has chosen " + colorChoice.getChoice());
|
||||
game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor());
|
||||
permanent.addInfo("chosen color", new StringBuilder("<font color='blue'>Chosen color: ").append(colorChoice.getColor().getDescription()).append("</font>").toString(), game);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LureboundScarecrowChooseColorEffect copy() {
|
||||
return new LureboundScarecrowChooseColorEffect(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LureboundScarecrowTriggeredAbility extends StateTriggeredAbility {
|
||||
|
||||
private static final String staticText = "When you control no permanents of the chosen color, sacrifice {this}.";
|
||||
|
|
|
@ -61,7 +61,6 @@ public class Mirrorweave extends CardImpl {
|
|||
super(ownerId, 143, "Mirrorweave", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{2}{W/U}{W/U}");
|
||||
this.expansionSetCode = "SHM";
|
||||
|
||||
|
||||
// Each other creature becomes a copy of target nonlegendary creature until end of turn.
|
||||
this.getSpellAbility().addEffect(new MirrorWeaveEffect());
|
||||
this.getSpellAbility().addTarget(new TargetPermanent(filter));
|
||||
|
@ -105,7 +104,7 @@ class MirrorWeaveEffect extends OneShotEffect {
|
|||
filter.add(Predicates.not(new PermanentIdPredicate(copyFromCreature.getId())));
|
||||
for (Permanent copyToCreature : game.getBattlefield().getAllActivePermanents(filter, game)) {
|
||||
if (copyToCreature != null) {
|
||||
game.copyPermanent(Duration.EndOfTurn, copyFromCreature, copyToCreature, source, new EmptyApplyToPermanent());
|
||||
game.copyPermanent(Duration.EndOfTurn, copyFromCreature, copyToCreature.getId(), source, new EmptyApplyToPermanent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ class TidehollowScullerExileEffect extends OneShotEffect {
|
|||
if (controller.choose(Outcome.Exile, opponent.getHand(), target, game)) {
|
||||
Card card = opponent.getHand().get(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
controller.moveCardToExileWithInfo(card, CardUtil.getObjectExileZoneId(game, sourcePermanent), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.HAND, true);
|
||||
controller.moveCardToExileWithInfo(card, CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.HAND, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,9 +28,6 @@
|
|||
package mage.sets.tempest;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Rarity;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
|
@ -39,7 +36,9 @@ import mage.abilities.costs.common.TapSourceCost;
|
|||
import mage.abilities.decorator.ConditionalContinuousEffect;
|
||||
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
|
@ -57,8 +56,9 @@ public class RootwaterMatriarch extends CardImpl {
|
|||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// {TAP}: Gain control of target creature for as long as that creature is enchanted
|
||||
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainControlTargetEffect(Duration.OneUse), EnchantedTargetCondition.getInstance(), "Gain control of target creature for as long as that creature is enchanted");
|
||||
// {T}: Gain control of target creature for as long as that creature is enchanted
|
||||
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainControlTargetEffect(Duration.Custom), EnchantedTargetCondition.getInstance(),
|
||||
"Gain control of target creature for as long as that creature is enchanted");
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost());
|
||||
ability.addTarget(new TargetCreaturePermanent());
|
||||
this.addAbility(ability);
|
||||
|
|
|
@ -73,7 +73,6 @@ public class AshiokNightmareWeaver extends CardImpl {
|
|||
this.expansionSetCode = "THS";
|
||||
this.subtype.add("Ashiok");
|
||||
|
||||
|
||||
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(3)), false));
|
||||
|
||||
// +2: Exile the top three cards of target opponent's library.
|
||||
|
@ -121,14 +120,9 @@ class AshiokNightmareWeaverExileEffect extends OneShotEffect {
|
|||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (sourceObject != null && opponent != null && controller != null) {
|
||||
UUID exileZone = CardUtil.getObjectExileZoneId(game, sourceObject);
|
||||
UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||
if (exileZone != null) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Card card = opponent.getLibrary().getFromTop(game);
|
||||
if (card != null) {
|
||||
controller.moveCardToExileWithInfo(card, exileZone, sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true);
|
||||
}
|
||||
}
|
||||
controller.moveCardsToExile(opponent.getLibrary().getTopCards(game, 3), source, game, true, exileZone, sourceObject.getIdName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -167,11 +161,10 @@ class AshiokNightmareWeaverPutIntoPlayEffect extends OneShotEffect {
|
|||
}
|
||||
}
|
||||
|
||||
FilterCard filter = new FilterCreatureCard(new StringBuilder("creature card with converted mana cost {").append(cmc).append("} exiled with Ashiok, Nightmare Weaver").toString());
|
||||
FilterCard filter = new FilterCreatureCard("creature card with converted mana cost {" + cmc + "} exiled with " + sourceObject.getIdName());
|
||||
filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.Equal, cmc));
|
||||
|
||||
Target target = new TargetCardInExile(filter, CardUtil.getObjectExileZoneId(game, sourceObject));
|
||||
|
||||
Target target = new TargetCardInExile(filter, CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()));
|
||||
|
||||
if (target.canChoose(source.getSourceId(), controller.getId(), game)) {
|
||||
if (controller.chooseTarget(Outcome.PutCreatureInPlay, target, source, game)) {
|
||||
|
@ -267,7 +260,7 @@ class AshiokNightmareWeaverExileAllEffect extends OneShotEffect {
|
|||
if (exileId == null) {
|
||||
return false;
|
||||
}
|
||||
for (UUID opponentId: game.getOpponents(source.getControllerId())) {
|
||||
for (UUID opponentId : game.getOpponents(source.getControllerId())) {
|
||||
Player opponent = game.getPlayer(opponentId);
|
||||
if (opponent != null) {
|
||||
Cards cards = new CardsImpl();
|
||||
|
@ -280,7 +273,7 @@ class AshiokNightmareWeaverExileAllEffect extends OneShotEffect {
|
|||
}
|
||||
cards.clear();
|
||||
cards.addAll(opponent.getGraveyard());
|
||||
for (UUID cardId :cards) {
|
||||
for (UUID cardId : cards) {
|
||||
Card card = game.getCard(cardId);
|
||||
if (card != null) {
|
||||
controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true);
|
||||
|
|
|
@ -108,7 +108,7 @@ class VesuvanDoppelgangerCopyEffect extends OneShotEffect {
|
|||
controller.choose(Outcome.Copy, target, source.getSourceId(), game);
|
||||
Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget());
|
||||
if (copyFromPermanent != null) {
|
||||
game.copyPermanent(copyFromPermanent, sourcePermanent, source, new ApplyToPermanent() {
|
||||
game.copyPermanent(copyFromPermanent, sourcePermanent.getId(), source, new ApplyToPermanent() {
|
||||
@Override
|
||||
public Boolean apply(Game game, Permanent permanent) {
|
||||
permanent.getColor(game).setColor(sourcePermanent.getColor(game));
|
||||
|
|
|
@ -16,7 +16,10 @@ public class ProteanHydraTest extends CardTestPlayerBase {
|
|||
@Test
|
||||
public void testEnteringWithCounters() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
|
||||
addCard(Zone.HAND, playerA, "Protean Hydra");
|
||||
// Protean Hydra enters the battlefield with X +1/+1 counters on it.
|
||||
// If damage would be dealt to Protean Hydra, prevent that damage and remove that many +1/+1 counters from it.
|
||||
// Whenever a +1/+1 counter is removed from Protean Hydra, put two +1/+1 counters on it at the beginning of the next end step.
|
||||
addCard(Zone.HAND, playerA, "Protean Hydra"); // CREATURE - {X}{G}
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Protean Hydra");
|
||||
|
||||
|
|
|
@ -51,8 +51,10 @@ public class MycosynthGolemTest extends CardTestPlayerBase {
|
|||
public void testSpellsAffinity() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
// Affinity for artifacts
|
||||
// Artifact creature spells you cast have affinity for artifacts.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mycosynth Golem");
|
||||
addCard(Zone.HAND, playerA, "Alpha Myr");
|
||||
addCard(Zone.HAND, playerA, "Alpha Myr"); // Creature - Myr 2/1
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Alpha Myr");
|
||||
|
||||
|
|
|
@ -66,6 +66,9 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase {
|
|||
@Test
|
||||
public void testSpellsReturnToHand() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
// Lifelink
|
||||
// Instant and sorcery spells you control have lifelink.
|
||||
// {2}{U/R}{U/R}: The next time you cast an instant or sorcery spell from your hand this turn, put that card into your hand instead of your graveyard as it resolves.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master");
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
|
@ -199,7 +202,6 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase {
|
|||
* Test that if Soulfire Grand Master has left the battlefield spell has no
|
||||
* longer lifelink
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testSoulfireLeft() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
|
@ -231,7 +233,6 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase {
|
|||
* the elemental, so stoke didnt resolve, but i still got the life from
|
||||
* lifelink.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testSoulfireStokeTheFlames() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8);
|
||||
|
@ -296,7 +297,6 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase {
|
|||
* Constructed.
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testWithDeflectingPalm() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.mage.test.cards.conditional;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
|
@ -32,7 +28,7 @@ public class RootwaterMatriarchTest extends CardTestPlayerBase {
|
|||
|
||||
@Test
|
||||
public void testTargetSuccess() {
|
||||
|
||||
// {T}: Gain control of target creature for as long as that creature is enchanted
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Rootwater Matriarch");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Memnite");
|
||||
|
|
|
@ -202,6 +202,9 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Llanowar Elves");
|
||||
addCard(Zone.HAND, playerA, "Phantasmal Image");
|
||||
|
||||
// As Lurebound Scarecrow enters the battlefield, choose a color.
|
||||
// When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow.
|
||||
addCard(Zone.HAND, playerA, "Lurebound Scarecrow");
|
||||
|
||||
setChoice(playerA, "Green");
|
||||
|
@ -418,26 +421,34 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Action
|
||||
* Game State 1 -----------------> Game State 2
|
||||
* (On 'field) (Move to GY) (In graveyard)
|
||||
* Action Game State 1 -----------------> Game State 2 (On 'field) (Move to
|
||||
* GY) (In graveyard)
|
||||
*
|
||||
* LTB abilities such as Persist are expceptional in that they trigger based on their existence and
|
||||
* state of objects before the event (Game State 1, when the card is on the battlefield) rather than
|
||||
* after (Game State 2, when the card is in the graveyard). It doesn't matter that the LTB ability
|
||||
* doesn't exist in Game State 2. [CR 603.6d]
|
||||
* LTB abilities such as Persist are expceptional in that they trigger based
|
||||
* on their existence and state of objects before the event (Game State 1,
|
||||
* when the card is on the battlefield) rather than after (Game State 2,
|
||||
* when the card is in the graveyard). It doesn't matter that the LTB
|
||||
* ability doesn't exist in Game State 2. [CR 603.6d]
|
||||
*
|
||||
* 603.6d Normally, objects that exist immediately after an event are checked to see if the event matched any trigger conditions.
|
||||
* Continuous effects that exist at that time are used to determine what the trigger conditions are and what the objects involved
|
||||
* in the event look like. However, some triggered abilities must be treated specially. Leaves-the-battlefield abilities, abilities
|
||||
* that trigger when a permanent phases out, abilities that trigger when an object that all players can see is put into a hand or
|
||||
* library, abilities that trigger specifically when an object becomes unattached, abilities that trigger when a player loses control
|
||||
* of an object, and abilities that trigger when a player planeswalks away from a plane will trigger based on their existence, and
|
||||
* the appearance of objects, prior to the event rather than afterward. The game has to “look back in time” to determine if these abilities trigger.
|
||||
* 603.6d Normally, objects that exist immediately after an event are
|
||||
* checked to see if the event matched any trigger conditions. Continuous
|
||||
* effects that exist at that time are used to determine what the trigger
|
||||
* conditions are and what the objects involved in the event look like.
|
||||
* However, some triggered abilities must be treated specially.
|
||||
* Leaves-the-battlefield abilities, abilities that trigger when a permanent
|
||||
* phases out, abilities that trigger when an object that all players can
|
||||
* see is put into a hand or library, abilities that trigger specifically
|
||||
* when an object becomes unattached, abilities that trigger when a player
|
||||
* loses control of an object, and abilities that trigger when a player
|
||||
* planeswalks away from a plane will trigger based on their existence, and
|
||||
* the appearance of objects, prior to the event rather than afterward. The
|
||||
* game has to “look back in time” to determine if these abilities trigger.
|
||||
*
|
||||
* Example: Two creatures are on the battlefield along with an artifact that has the ability “Whenever a creature dies, you gain 1 life.”
|
||||
* Someone plays a spell that destroys all artifacts, creatures, and enchantments. The artifact’s ability triggers twice, even though
|
||||
* the artifact goes to its owner’s graveyard at the same time as the creatures.
|
||||
* Example: Two creatures are on the battlefield along with an artifact that
|
||||
* has the ability “Whenever a creature dies, you gain 1 life.” Someone
|
||||
* plays a spell that destroys all artifacts, creatures, and enchantments.
|
||||
* The artifact’s ability triggers twice, even though the artifact goes to
|
||||
* its owner’s graveyard at the same time as the creatures.
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
|
@ -463,7 +474,6 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
|
|||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted
|
||||
setChoice(playerB, "Kitchen Finks");
|
||||
|
||||
|
||||
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Kitchen Finks");
|
||||
setChoice(playerB, "Kitchen Finks");
|
||||
|
||||
|
@ -480,7 +490,7 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
|
|||
assertHandCount(playerB, "Phantasmal Image", 0);
|
||||
assertGraveyardCount(playerB, "Phantasmal Image", 0);
|
||||
assertPermanentCount(playerB, "Kitchen Finks", 1);
|
||||
assertPowerToughness(playerB, "Kitchen Finks", 2, 1);
|
||||
assertPowerToughness(playerB, "Kitchen Finks", 2, 1);
|
||||
|
||||
}
|
||||
|
||||
|
@ -506,7 +516,6 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
|
|||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted
|
||||
setChoice(playerB, "Butcher Ghoul");
|
||||
|
||||
|
||||
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Butcher Ghoul");
|
||||
setChoice(playerB, "Butcher Ghoul");
|
||||
|
||||
|
@ -523,29 +532,25 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
|
|||
assertHandCount(playerB, "Phantasmal Image", 0);
|
||||
assertGraveyardCount(playerB, "Phantasmal Image", 0);
|
||||
assertPermanentCount(playerB, "Butcher Ghoul", 1);
|
||||
assertPowerToughness(playerB, "Butcher Ghoul", 2, 2);
|
||||
assertPowerToughness(playerB, "Butcher Ghoul", 2, 2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 12:29: Attacker: Wurmcoil Engine [466] (6/6) blocked by Wurmcoil Engine
|
||||
* [4ed] (6/6)
|
||||
* 12:29: yespair gains 6 life
|
||||
* 12:29: HipSomHap gains 6 life
|
||||
* 12:29: Wurmcoil Engine [4ed] died
|
||||
* 12:29: Ability triggers: Wurmcoil Engine [4ed] - When Wurmcoil Engine [4ed] dies, put a a 3/3 colorless
|
||||
* [4ed] (6/6) 12:29: yespair gains 6 life 12:29: HipSomHap gains 6 life
|
||||
* 12:29: Wurmcoil Engine [4ed] died 12:29: Ability triggers: Wurmcoil
|
||||
* Engine [4ed] - When Wurmcoil Engine [4ed] dies, put a a 3/3 colorless
|
||||
* Wurm artifact creature token with deathtouch onto the battlefield. Put a
|
||||
* a 3/3 colorless Wurm artifact creature token with lifelink onto the
|
||||
* battlefield.
|
||||
* 12:29: Phantasmal Image [466] died
|
||||
* 12:29: HipSomHap puts a Wurm [7d0] token onto the battlefield
|
||||
* 12:29: HipSomHap puts a Wurm [186] token onto the battlefield
|
||||
* battlefield. 12:29: Phantasmal Image [466] died 12:29: HipSomHap puts a
|
||||
* Wurm [7d0] token onto the battlefield 12:29: HipSomHap puts a Wurm [186]
|
||||
* token onto the battlefield
|
||||
*
|
||||
* To the best of my knowledge, the Phantasmal Image [466], which entered
|
||||
* the battlefield as a Wurmcoil Engine, should grant tokens through the
|
||||
* Dies-trigger as well, right?
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testDiesTriggered2() {
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Wurmcoil Engine");
|
||||
|
|
|
@ -36,10 +36,8 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class PhyrexianMetamorphTest extends CardTestPlayerBase {
|
||||
|
||||
|
||||
@Test
|
||||
public void testCopyCreature() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
|
@ -84,7 +82,6 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase {
|
|||
* to choose a new creature to clone when the Phyrexian Metamorph re-entered
|
||||
* the battlefield.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testFlickerWithBrago() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
|
@ -126,7 +123,7 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase {
|
|||
* destroying ability, where it should have had two of them and triggered
|
||||
* twice (the Metamorph might have nothing to do with this)
|
||||
*/
|
||||
@Test
|
||||
@Test
|
||||
public void testHarmonicSliver() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
|
||||
|
@ -154,8 +151,8 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* If a Harmonic Sliver enters the battlefield
|
||||
* the controller has to destroy one artifacts or enchantments
|
||||
* If a Harmonic Sliver enters the battlefield the controller has to destroy
|
||||
* one artifacts or enchantments
|
||||
*/
|
||||
@Test
|
||||
public void testHarmonicSliverNative1() {
|
||||
|
@ -179,8 +176,9 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* If a Harmonic Sliver enters the battlefield and there is already one on the battlefield
|
||||
* the controller has to destroy two artifacts or enchantments
|
||||
* If a Harmonic Sliver enters the battlefield and there is already one on
|
||||
* the battlefield the controller has to destroy two artifacts or
|
||||
* enchantments
|
||||
*/
|
||||
@Test
|
||||
public void testHarmonicSliverNative2() {
|
||||
|
@ -207,4 +205,53 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase {
|
|||
assertGraveyardCount(playerB, "Kitesail", 1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* I cast Show and Tell, and put Sheoldred, Whispering One into play and my
|
||||
* opponent put Phyrexian Metamorph into play and he was able to clone my
|
||||
* Sheoldred, Whispering One.
|
||||
*
|
||||
* 6/1/2011 If Phyrexian Metamorph somehow enters the battlefield at the
|
||||
* same time as another permanent (due to Mass Polymorph or Liliana Vess's
|
||||
* third ability, for example), Phyrexian Metamorph can't become a copy of
|
||||
* that permanent. You may only choose a permanent that's already on the
|
||||
* battlefield.
|
||||
*
|
||||
* 400.6. If an object would move from one zone to another, determine what
|
||||
* event is moving the object. If the object is moving to a public zone, all
|
||||
* players look at it to see if it has any abilities that would affect the
|
||||
* move. Then any appropriate replacement effects, whether they come from
|
||||
* that object or from elsewhere, are applied to that event. If any effects
|
||||
* or rules try to do two or more contradictory or mutually exclusive things
|
||||
* to a particular object, that object's controller -- or its owner if it
|
||||
* has no controller -- chooses which effect to apply, and what that effect
|
||||
* does. (Note that multiple instances of the same thing may be mutually
|
||||
* exclusive; for example, two simultaneous "destroy" effects.) Then the
|
||||
* event moves the object.
|
||||
*/
|
||||
@Test
|
||||
public void testShowAndTell() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
|
||||
|
||||
// Each player may put an artifact, creature, enchantment, or land card from his or her hand onto the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Show and Tell"); // SORCERY {2}{U}
|
||||
|
||||
// Swampwalk
|
||||
// At the beginning of your upkeep, return target creature card from your graveyard to the battlefield.
|
||||
// At the beginning of each opponent's upkeep, that player sacrifices a creature.
|
||||
addCard(Zone.HAND, playerA, "Sheoldred, Whispering One");
|
||||
|
||||
addCard(Zone.HAND, playerB, "Phyrexian Metamorph");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Show and Tell");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Sheoldred, Whispering One", 1);
|
||||
assertPermanentCount(playerB, "Sheoldred, Whispering One", 0);
|
||||
|
||||
assertGraveyardCount(playerB, "Phyrexian Metamorph", 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -554,7 +554,7 @@ public class TestPlayer implements Player {
|
|||
if (!choices.isEmpty()) {
|
||||
for (String choice : choices) {
|
||||
for (int index = 0; index < rEffects.size(); index++) {
|
||||
if (choice.equals(rEffects.get(index))) {
|
||||
if (choice.equals(rEffects.get(Integer.toString(index)))) {
|
||||
choices.remove(choice);
|
||||
return index;
|
||||
}
|
||||
|
@ -1951,6 +1951,11 @@ public class TestPlayer implements Player {
|
|||
return computerPlayer.scry(value, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects) {
|
||||
return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects);
|
||||
}
|
||||
|
||||
public void setAIPlayer(boolean AIPlayer) {
|
||||
this.AIPlayer = AIPlayer;
|
||||
}
|
||||
|
|
|
@ -283,7 +283,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
if (card == null) {
|
||||
throw new IllegalArgumentException("[TEST] Couldn't find a card: " + cardName);
|
||||
}
|
||||
PermanentCard p = new PermanentCard(card, null, currentGame);
|
||||
PermanentCard p = new PermanentCard(card, player.getId(), currentGame);
|
||||
p.setTapped(tapped);
|
||||
getBattlefieldCards(player).add(p);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
// So check here with the LKI of the enchantment
|
||||
Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId());
|
||||
if (attachment != null && attachment.getAttachedTo().equals(zEvent.getTargetId())
|
||||
&& attachment.getAttachedToZoneChangeCounter() == zEvent.getTarget().getZoneChangeCounter(game)) {
|
||||
&& attachment.getAttachedToZoneChangeCounter() == zEvent.getTarget().getZoneChangeCounter(game) - 1) {
|
||||
triggered = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.CardType;
|
||||
|
@ -16,7 +14,7 @@ import mage.target.Target;
|
|||
*/
|
||||
public class EnchantedTargetCondition implements Condition {
|
||||
|
||||
private static EnchantedTargetCondition fInstance = new EnchantedTargetCondition();
|
||||
private static final EnchantedTargetCondition fInstance = new EnchantedTargetCondition();
|
||||
|
||||
public static Condition getInstance() {
|
||||
return fInstance;
|
||||
|
|
|
@ -36,13 +36,13 @@ import mage.cards.Card;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
|
@ -103,12 +103,12 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
|
|||
UUID targetId = null;
|
||||
MageObject sourceObject = game.getObject(sourceId);
|
||||
boolean enchantCardInGraveyard = false;
|
||||
if (sourceObject instanceof Spell) {
|
||||
if (fromZone.equals(Zone.EXILED)) {
|
||||
// cast from exile (e.g. Neightveil Spector) -> no replacement
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// if (sourceObject instanceof Spell) {
|
||||
// if (fromZone.equals(Zone.EXILED)) {
|
||||
// // cast from exile (e.g. Neightveil Spector) -> no replacement
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
if (sourceObject instanceof StackAbility) {
|
||||
StackAbility stackAbility = (StackAbility) sourceObject;
|
||||
if (!stackAbility.getEffects().isEmpty()) {
|
||||
|
@ -118,25 +118,34 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
|
|||
|
||||
game.applyEffects(); // So continuousEffects are removed if previous effect of the same ability did move objects that cuase continuous effects
|
||||
if (targetId == null) {
|
||||
Target target = card.getSpellAbility().getTargets().get(0).copy();
|
||||
SpellAbility spellAbility = card.getSpellAbility();
|
||||
if (spellAbility.getTargets().isEmpty()) {
|
||||
for (Ability ability : card.getAbilities(game)) {
|
||||
if ((ability instanceof SpellAbility)
|
||||
&& SpellAbilityType.BASE_ALTERNATE.equals(((SpellAbility) ability).getSpellAbilityType())
|
||||
&& !ability.getTargets().isEmpty()) {
|
||||
spellAbility = (SpellAbility) ability;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (spellAbility.getTargets().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Target target = spellAbility.getTargets().get(0).copy();
|
||||
Outcome auraOutcome = Outcome.BoostCreature;
|
||||
for (Effect effect : spellAbility.getEffects()) {
|
||||
if (effect instanceof AttachEffect) {
|
||||
auraOutcome = effect.getOutcome();
|
||||
break;
|
||||
}
|
||||
}
|
||||
enchantCardInGraveyard = target instanceof TargetCardInGraveyard;
|
||||
if (target != null) {
|
||||
target.setNotTarget(true); // always not target because this way it's not handled targeted
|
||||
target.clearChosen(); // neccessary if e.g. aura is blinked multiple times
|
||||
}
|
||||
Player player = game.getPlayer(card.getOwnerId());
|
||||
Outcome auraOutcome = Outcome.BoostCreature;
|
||||
Ability:
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability instanceof SpellAbility) {
|
||||
for (Effect effect : ability.getEffects()) {
|
||||
if (effect instanceof AttachEffect) {
|
||||
auraOutcome = effect.getOutcome();
|
||||
break Ability;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (target != null && player != null && player.choose(auraOutcome, target, card.getId(), game)) {
|
||||
targetId = target.getFirstTarget();
|
||||
}
|
||||
|
@ -151,44 +160,27 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
|
|||
}
|
||||
Player targetPlayer = game.getPlayer(targetId);
|
||||
if (targetCard != null || targetPermanent != null || targetPlayer != null) {
|
||||
switch (fromZone) {
|
||||
case EXILED:
|
||||
game.getExile().removeCard(card, game);
|
||||
break;
|
||||
case GRAVEYARD:
|
||||
game.getPlayer(card.getOwnerId()).removeFromGraveyard(card, game);
|
||||
break;
|
||||
case HAND:
|
||||
game.getPlayer(card.getOwnerId()).removeFromHand(card, game);
|
||||
break;
|
||||
case LIBRARY:
|
||||
game.getPlayer(card.getOwnerId()).removeFromLibrary(card, game);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
game.rememberLKI(card.getId(), fromZone, card);
|
||||
|
||||
card.removeFromZone(game, fromZone, sourceId);
|
||||
card.updateZoneChangeCounter(game);
|
||||
PermanentCard permanent = new PermanentCard(card, card.getOwnerId(), game);
|
||||
game.getBattlefield().addPermanent(permanent);
|
||||
card.setZone(Zone.BATTLEFIELD, game);
|
||||
boolean entered = permanent.entersBattlefield(event.getSourceId(), game, fromZone, true);
|
||||
game.applyEffects();
|
||||
if (!entered) {
|
||||
return false;
|
||||
}
|
||||
game.fireEvent(new ZoneChangeEvent(permanent, controllerId, fromZone, Zone.BATTLEFIELD));
|
||||
if (permanent.entersBattlefield(event.getSourceId(), game, fromZone, true)) {
|
||||
if (targetCard != null) {
|
||||
permanent.attachTo(targetCard.getId(), game);
|
||||
} else if (targetPermanent != null) {
|
||||
targetPermanent.addAttachment(permanent.getId(), game);
|
||||
} else if (targetPlayer != null) {
|
||||
targetPlayer.addAttachment(permanent.getId(), game);
|
||||
}
|
||||
game.applyEffects();
|
||||
|
||||
if (targetCard != null) {
|
||||
permanent.attachTo(targetCard.getId(), game);
|
||||
}
|
||||
if (targetPermanent != null) {
|
||||
targetPermanent.addAttachment(permanent.getId(), game);
|
||||
}
|
||||
if (targetPlayer != null) {
|
||||
targetPlayer.addAttachment(permanent.getId(), game);
|
||||
game.fireEvent(new ZoneChangeEvent(permanent, controllerId, fromZone, Zone.BATTLEFIELD));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -199,7 +191,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
|
|||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (((ZoneChangeEvent) event).getToZone().equals(Zone.BATTLEFIELD)
|
||||
&& !(((ZoneChangeEvent) event).getFromZone().equals(Zone.HAND))) {
|
||||
&& !(((ZoneChangeEvent) event).getFromZone().equals(Zone.STACK))) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && card.getCardType().contains(CardType.ENCHANTMENT) && card.hasSubtype("Aura")) {
|
||||
return true;
|
||||
|
|
|
@ -1147,18 +1147,18 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
private void setControllerForEffect(ContinuousEffectsList<?> effects, UUID cardId, UUID controllerId) {
|
||||
private void setControllerForEffect(ContinuousEffectsList<?> effects, UUID sourceId, UUID controllerId) {
|
||||
for (Effect effect : effects) {
|
||||
HashSet<Ability> abilities = effects.getAbility(effect.getId());
|
||||
if (abilities != null) {
|
||||
for (Ability ability : abilities) {
|
||||
if (ability.getSourceId() != null) {
|
||||
if (ability.getSourceId().equals(cardId)) {
|
||||
if (ability.getSourceId().equals(sourceId)) {
|
||||
ability.setControllerId(controllerId);
|
||||
}
|
||||
} else {
|
||||
if (!ability.getZone().equals(Zone.COMMAND)) {
|
||||
logger.fatal(new StringBuilder("No sourceId Ability: ").append(ability));
|
||||
logger.fatal("Continuous effect for ability with no sourceId Ability: " + ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
/*
|
||||
* Copyright 2012 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL , EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
* Copyright 2012 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL , EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.abilities.effects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -52,12 +52,13 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
// the effectAbilityMap holds for each effect all abilities that are connected (used) with this effect
|
||||
private final Map<UUID, HashSet<Ability>> effectAbilityMap = new HashMap<>();
|
||||
|
||||
public ContinuousEffectsList() { }
|
||||
public ContinuousEffectsList() {
|
||||
}
|
||||
|
||||
public ContinuousEffectsList(final ContinuousEffectsList<T> effects) {
|
||||
this.ensureCapacity(effects.size());
|
||||
for (ContinuousEffect cost: effects) {
|
||||
this.add((T)cost.copy());
|
||||
for (ContinuousEffect cost : effects) {
|
||||
this.add((T) cost.copy());
|
||||
}
|
||||
for (Map.Entry<UUID, HashSet<Ability>> entry : effects.effectAbilityMap.entrySet()) {
|
||||
HashSet<Ability> newSet = new HashSet<>();
|
||||
|
@ -113,12 +114,12 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
Ability ability = it.next();
|
||||
if (ability == null) {
|
||||
it.remove();
|
||||
} else if (ability instanceof MageSingleton) {
|
||||
} else if (ability instanceof MageSingleton) {
|
||||
return false;
|
||||
} else if (effect.isDiscarded()) {
|
||||
} else if (effect.isDiscarded()) {
|
||||
it.remove();
|
||||
} else {
|
||||
switch(effect.getDuration()) {
|
||||
switch (effect.getDuration()) {
|
||||
case WhileOnBattlefield:
|
||||
case WhileInGraveyard:
|
||||
case WhileOnStack:
|
||||
|
@ -133,8 +134,8 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
break;
|
||||
case Custom:
|
||||
case UntilYourNextTurn:
|
||||
if (effect.isInactive(ability , game)) {
|
||||
it.remove();
|
||||
if (effect.isInactive(ability, game)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,9 +144,9 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds an effect and its connected ability to the list.
|
||||
* For each effect will be stored, which abilities are connected to the effect.
|
||||
* So an effect can be connected to multiple abilities.
|
||||
* Adds an effect and its connected ability to the list. For each effect
|
||||
* will be stored, which abilities are connected to the effect. So an effect
|
||||
* can be connected to multiple abilities.
|
||||
*
|
||||
* @param effect - effect to add
|
||||
* @param source - connected ability
|
||||
|
@ -153,8 +154,8 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
public void addEffect(T effect, Ability source) {
|
||||
if (effectAbilityMap.containsKey(effect.getId())) {
|
||||
HashSet<Ability> set = effectAbilityMap.get(effect.getId());
|
||||
for (Ability ability: set) {
|
||||
if (ability.getId().equals(source.getId()) && ability.getSourceId().equals(source.getSourceId()) ) {
|
||||
for (Ability ability : set) {
|
||||
if (ability.getId().equals(source.getId()) && ability.getSourceId().equals(source.getSourceId())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +1,43 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.abilities.effects;
|
||||
|
||||
import mage.constants.Duration;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
|
@ -116,12 +117,17 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
|
|||
}
|
||||
}
|
||||
Spell spell = game.getStack().getSpell(event.getSourceId());
|
||||
for (Effect effect: baseEffects) {
|
||||
if (spell == null) {
|
||||
StackObject stackObject = (StackObject) game.getLastKnownInformation(event.getSourceId(), Zone.STACK);
|
||||
if (stackObject instanceof Spell) {
|
||||
spell = (Spell) stackObject;
|
||||
}
|
||||
}
|
||||
for (Effect effect : baseEffects) {
|
||||
if (source.activate(game, false)) {
|
||||
if (effect instanceof ContinuousEffect) {
|
||||
game.addEffect((ContinuousEffect) effect, source);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (spell != null) {
|
||||
effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility());
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
|
@ -66,6 +67,7 @@ public class CopyPermanentEffect extends OneShotEffect {
|
|||
public CopyPermanentEffect(FilterPermanent filter, ApplyToPermanent applier) {
|
||||
this(filter, applier, false);
|
||||
}
|
||||
|
||||
public CopyPermanentEffect(FilterPermanent filter, ApplyToPermanent applier, boolean useTarget) {
|
||||
super(Outcome.Copy);
|
||||
this.applier = applier;
|
||||
|
@ -85,8 +87,8 @@ public class CopyPermanentEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && sourcePermanent != null) {
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (player != null && sourceObject != null) {
|
||||
Permanent copyFromPermanent = null;
|
||||
if (useTargetOfAbility) {
|
||||
copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
|
@ -99,7 +101,7 @@ public class CopyPermanentEffect extends OneShotEffect {
|
|||
}
|
||||
}
|
||||
if (copyFromPermanent != null) {
|
||||
bluePrintPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent, source, applier);
|
||||
bluePrintPermanent = game.copyPermanent(copyFromPermanent, sourceObject.getId(), source, applier);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
@ -56,7 +55,8 @@ public class CounterTargetWithReplacementEffect extends OneShotEffect {
|
|||
/**
|
||||
*
|
||||
* @param targetZone
|
||||
* @param flag use to specify when moving card to library <ul><li>true = put on top</li><li>false = put on bottom</li></ul>
|
||||
* @param flag use to specify when moving card to library <ul><li>true = put
|
||||
* on top</li><li>false = put on bottom</li></ul>
|
||||
*/
|
||||
public CounterTargetWithReplacementEffect(Zone targetZone, boolean flag) {
|
||||
super(Outcome.Detriment);
|
||||
|
@ -83,29 +83,10 @@ public class CounterTargetWithReplacementEffect extends OneShotEffect {
|
|||
if (controller != null) {
|
||||
StackObject stackObject = game.getStack().getStackObject(objectId);
|
||||
if (stackObject != null && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, sourceId, stackObject.getControllerId()))) {
|
||||
boolean spell = false;
|
||||
if (stackObject instanceof Spell) {
|
||||
game.rememberLKI(objectId, Zone.STACK, stackObject);
|
||||
spell = true;
|
||||
}
|
||||
game.getStack().remove(stackObject);
|
||||
if (spell && !((Spell) stackObject).isCopiedSpell()) {
|
||||
MageObject mageObject = game.getObject(stackObject.getSourceId());
|
||||
if (mageObject instanceof Card) {
|
||||
Card card = (Card) mageObject;
|
||||
switch (targetZone) {
|
||||
case LIBRARY:
|
||||
controller.moveCardToLibraryWithInfo(card, sourceId, game, Zone.STACK, flag, true);
|
||||
break;
|
||||
case EXILED:
|
||||
controller.moveCardToExileWithInfo(card, null, "", sourceId, game, Zone.STACK, true);
|
||||
break;
|
||||
default:
|
||||
controller.moveCards(card, Zone.STACK, targetZone, source, game);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
controller.moveCards((Card) stackObject, null, targetZone, source, game);
|
||||
} else {
|
||||
game.getStack().remove(stackObject);
|
||||
}
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERED, objectId, sourceId, stackObject.getControllerId()));
|
||||
return true;
|
||||
|
|
|
@ -40,6 +40,7 @@ import mage.constants.Zone;
|
|||
import mage.counters.Counter;
|
||||
import mage.counters.Counters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
public interface Card extends MageObject {
|
||||
|
||||
|
@ -65,6 +66,8 @@ public interface Card extends MageObject {
|
|||
|
||||
String getTokenSetCode();
|
||||
|
||||
void checkForCountersToAdd(Permanent permanent, Game game);
|
||||
|
||||
void setFaceDown(boolean value, Game game);
|
||||
|
||||
boolean isFaceDown(Game game);
|
||||
|
@ -125,6 +128,8 @@ public interface Card extends MageObject {
|
|||
|
||||
boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId);
|
||||
|
||||
boolean removeFromZone(Game game, Zone fromZone, UUID sourceId);
|
||||
|
||||
boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId);
|
||||
|
||||
boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped);
|
||||
|
|
|
@ -54,8 +54,6 @@ import static mage.constants.Zone.EXILED;
|
|||
import static mage.constants.Zone.GRAVEYARD;
|
||||
import static mage.constants.Zone.HAND;
|
||||
import static mage.constants.Zone.LIBRARY;
|
||||
import static mage.constants.Zone.OUTSIDE;
|
||||
import static mage.constants.Zone.PICK;
|
||||
import static mage.constants.Zone.STACK;
|
||||
import mage.counters.Counter;
|
||||
import mage.counters.Counters;
|
||||
|
@ -65,6 +63,7 @@ import mage.game.Game;
|
|||
import mage.game.command.Commander;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
|
@ -342,55 +341,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
Zone fromZone = game.getState().getZone(objectId);
|
||||
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, toZone, appliedEffects);
|
||||
if (!game.replaceEvent(event)) {
|
||||
if (event.getFromZone() != null) {
|
||||
switch (event.getFromZone()) {
|
||||
case GRAVEYARD:
|
||||
game.getPlayer(ownerId).removeFromGraveyard(this, game);
|
||||
break;
|
||||
case HAND:
|
||||
game.getPlayer(ownerId).removeFromHand(this, game);
|
||||
break;
|
||||
case LIBRARY:
|
||||
game.getPlayer(ownerId).removeFromLibrary(this, game);
|
||||
break;
|
||||
case EXILED:
|
||||
game.getExile().removeCard(this, game);
|
||||
break;
|
||||
case OUTSIDE:
|
||||
game.getPlayer(ownerId).getSideboard().remove(this);
|
||||
break;
|
||||
case COMMAND:
|
||||
game.getState().getCommand().remove((Commander) game.getObject(objectId));
|
||||
break;
|
||||
case STACK:
|
||||
StackObject stackObject = game.getStack().getSpell(getSpellAbility().getId());
|
||||
if (stackObject == null && (this instanceof SplitCard)) { // handle if half of Split cast is on the stack
|
||||
stackObject = game.getStack().getSpell(((SplitCard) this).getLeftHalfCard().getId());
|
||||
if (stackObject == null) {
|
||||
stackObject = game.getStack().getSpell(((SplitCard) this).getRightHalfCard().getId());
|
||||
}
|
||||
}
|
||||
if (stackObject == null) {
|
||||
stackObject = game.getStack().getSpell(getId());
|
||||
}
|
||||
if (stackObject != null) {
|
||||
game.getStack().remove(stackObject);
|
||||
}
|
||||
break;
|
||||
case PICK:
|
||||
case BATTLEFIELD: // for sacrificing permanents or putting to library
|
||||
break;
|
||||
default:
|
||||
Card sourceCard = game.getCard(sourceId);
|
||||
logger.fatal(new StringBuilder("Invalid from zone [").append(fromZone)
|
||||
.append("] for card [").append(this.getName())
|
||||
.append("] to zone [").append(toZone)
|
||||
.append("] source [").append(sourceCard != null ? sourceCard.getName() : "null").append("]").toString());
|
||||
break;
|
||||
}
|
||||
game.rememberLKI(objectId, event.getFromZone(), this);
|
||||
}
|
||||
|
||||
removeFromZone(game, fromZone, sourceId);
|
||||
setFaceDown(false, game);
|
||||
updateZoneChangeCounter(game);
|
||||
switch (event.getToZone()) {
|
||||
|
@ -454,32 +405,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
Card mainCard = getMainCard();
|
||||
ZoneChangeEvent event = new ZoneChangeEvent(mainCard.getId(), ability.getId(), controllerId, fromZone, Zone.STACK);
|
||||
if (!game.replaceEvent(event)) {
|
||||
if (event.getFromZone() != null) {
|
||||
switch (event.getFromZone()) {
|
||||
case GRAVEYARD:
|
||||
game.getPlayer(ownerId).removeFromGraveyard(mainCard, game);
|
||||
break;
|
||||
case HAND:
|
||||
game.getPlayer(ownerId).removeFromHand(mainCard, game);
|
||||
break;
|
||||
case LIBRARY:
|
||||
game.getPlayer(ownerId).removeFromLibrary(mainCard, game);
|
||||
break;
|
||||
case EXILED:
|
||||
game.getExile().removeCard(mainCard, game);
|
||||
break;
|
||||
case OUTSIDE:
|
||||
game.getPlayer(ownerId).getSideboard().remove(mainCard);
|
||||
break;
|
||||
|
||||
case COMMAND:
|
||||
game.getState().getCommand().remove((Commander) game.getObject(mainCard.getId()));
|
||||
break;
|
||||
default:
|
||||
//logger.warning("moveToZone, not fully implemented: from="+event.getFromZone() + ", to="+event.getToZone());
|
||||
}
|
||||
game.rememberLKI(mainCard.getId(), event.getFromZone(), this);
|
||||
}
|
||||
mainCard.removeFromZone(game, fromZone, ability.getSourceId());
|
||||
game.getStack().push(new Spell(this, ability.copy(), controllerId, event.getFromZone()));
|
||||
updateZoneChangeCounter(game);
|
||||
setZone(event.getToZone(), game);
|
||||
|
@ -499,36 +425,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
Zone fromZone = game.getState().getZone(objectId);
|
||||
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects);
|
||||
if (!game.replaceEvent(event)) {
|
||||
if (fromZone != null) {
|
||||
switch (fromZone) {
|
||||
case GRAVEYARD:
|
||||
game.getPlayer(ownerId).removeFromGraveyard(this, game);
|
||||
break;
|
||||
case HAND:
|
||||
game.getPlayer(ownerId).removeFromHand(this, game);
|
||||
break;
|
||||
case LIBRARY:
|
||||
game.getPlayer(ownerId).removeFromLibrary(this, game);
|
||||
break;
|
||||
case EXILED:
|
||||
game.getExile().removeCard(this, game);
|
||||
break;
|
||||
case STACK:
|
||||
StackObject stackObject = game.getStack().getSpell(getId());
|
||||
if (stackObject != null) {
|
||||
game.getStack().remove(stackObject);
|
||||
}
|
||||
break;
|
||||
case PICK:
|
||||
// nothing to do
|
||||
break;
|
||||
default:
|
||||
MageObject object = game.getObject(sourceId);
|
||||
logger.warn(new StringBuilder("moveToExile, not fully implemented: from = ").append(fromZone).append(" - ").append(object != null ? object.getName() : "null"));
|
||||
}
|
||||
game.rememberLKI(objectId, event.getFromZone(), this);
|
||||
}
|
||||
|
||||
removeFromZone(game, fromZone, sourceId);
|
||||
if (exileId == null) {
|
||||
game.getExile().getPermanentExile().add(this);
|
||||
} else {
|
||||
|
@ -568,37 +465,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
if (facedown) {
|
||||
this.setFaceDown(false, game);
|
||||
}
|
||||
if (fromZone != null) {
|
||||
boolean removed = false;
|
||||
switch (fromZone) {
|
||||
case GRAVEYARD:
|
||||
removed = game.getPlayer(ownerId).removeFromGraveyard(this, game);
|
||||
break;
|
||||
case HAND:
|
||||
removed = game.getPlayer(ownerId).removeFromHand(this, game);
|
||||
break;
|
||||
case LIBRARY:
|
||||
removed = game.getPlayer(ownerId).removeFromLibrary(this, game);
|
||||
break;
|
||||
case EXILED:
|
||||
game.getExile().removeCard(this, game);
|
||||
removed = true;
|
||||
break;
|
||||
case COMMAND:
|
||||
// command object (commander) is only on the stack, so no removing neccessary here
|
||||
removed = true;
|
||||
break;
|
||||
case PICK:
|
||||
removed = true;
|
||||
break;
|
||||
default:
|
||||
logger.warn("putOntoBattlefield, not fully implemented: fromZone=" + fromZone);
|
||||
}
|
||||
game.rememberLKI(objectId, event.getFromZone(), this);
|
||||
if (!removed) {
|
||||
logger.warn("Couldn't find card in fromZone, card=" + getName() + ", fromZone=" + fromZone);
|
||||
}
|
||||
}
|
||||
removeFromZone(game, fromZone, sourceId);
|
||||
updateZoneChangeCounter(game);
|
||||
PermanentCard permanent = new PermanentCard(this, event.getPlayerId(), game);
|
||||
// make sure the controller of all continuous effects of this card are switched to the current controller
|
||||
|
@ -624,7 +491,76 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void checkForCountersToAdd(PermanentCard permanent, Game game) {
|
||||
@Override
|
||||
public boolean removeFromZone(Game game, Zone fromZone, UUID sourceId) {
|
||||
boolean removed = false;
|
||||
MageObject lkiObject = null;
|
||||
switch (fromZone) {
|
||||
case GRAVEYARD:
|
||||
removed = game.getPlayer(ownerId).removeFromGraveyard(this, game);
|
||||
break;
|
||||
case HAND:
|
||||
removed = game.getPlayer(ownerId).removeFromHand(this, game);
|
||||
break;
|
||||
case LIBRARY:
|
||||
removed = game.getPlayer(ownerId).removeFromLibrary(this, game);
|
||||
break;
|
||||
case EXILED:
|
||||
if (game.getExile().getCard(getId(), game) != null) {
|
||||
game.getExile().removeCard(this, game);
|
||||
removed = true;
|
||||
}
|
||||
break;
|
||||
case STACK:
|
||||
StackObject stackObject = game.getStack().getSpell(getSpellAbility().getId());
|
||||
if (stackObject == null && (this instanceof SplitCard)) { // handle if half of Split cast is on the stack
|
||||
stackObject = game.getStack().getSpell(((SplitCard) this).getLeftHalfCard().getId());
|
||||
if (stackObject == null) {
|
||||
stackObject = game.getStack().getSpell(((SplitCard) this).getRightHalfCard().getId());
|
||||
}
|
||||
}
|
||||
if (stackObject == null) {
|
||||
stackObject = game.getStack().getSpell(getId());
|
||||
}
|
||||
if (stackObject != null) {
|
||||
removed = game.getStack().remove(stackObject);
|
||||
lkiObject = stackObject;
|
||||
}
|
||||
break;
|
||||
case COMMAND:
|
||||
lkiObject = (Commander) game.getObject(objectId);
|
||||
if (lkiObject != null) {
|
||||
removed = game.getState().getCommand().remove((Commander) game.getObject(objectId));
|
||||
}
|
||||
break;
|
||||
case OUTSIDE:
|
||||
if (isCopy()) { // copied cards have no need to be removed from a previous zone
|
||||
removed = true;
|
||||
} else if (game.getPlayer(ownerId).getSideboard().contains(this.getId())) {
|
||||
game.getPlayer(ownerId).getSideboard().remove(this.getId());
|
||||
removed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case PICK: // Pick should no longer be used
|
||||
case BATTLEFIELD: // for sacrificing permanents or putting to library
|
||||
removed = true;
|
||||
break;
|
||||
default:
|
||||
MageObject sourceObject = game.getObject(sourceId);
|
||||
logger.fatal("Invalid from zone [" + fromZone + "] for card [" + this.getIdName()
|
||||
+ "] source [" + (sourceObject != null ? sourceObject.getName() : "null") + "]");
|
||||
break;
|
||||
}
|
||||
game.rememberLKI(objectId, fromZone, lkiObject != null ? lkiObject : this);
|
||||
if (!removed) {
|
||||
logger.warn("Couldn't find card in fromZone, card=" + getIdName() + ", fromZone=" + fromZone);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkForCountersToAdd(Permanent permanent, Game game) {
|
||||
Counters countersToAdd = game.getEnterWithCounters(permanent.getId());
|
||||
if (countersToAdd != null) {
|
||||
for (Counter counter : countersToAdd.values()) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import mage.abilities.Abilities;
|
|||
import mage.abilities.AbilitiesImpl;
|
||||
import mage.abilities.Ability;
|
||||
import mage.counters.Counters;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
|
@ -34,7 +35,7 @@ public class CardState implements Serializable {
|
|||
counters = state.counters.copy();
|
||||
if (state.abilities != null) {
|
||||
abilities = new AbilitiesImpl<>();
|
||||
for (Ability ability: state.abilities) {
|
||||
for (Ability ability : state.abilities) {
|
||||
abilities.add(ability.copy());
|
||||
}
|
||||
}
|
||||
|
@ -86,17 +87,17 @@ public class CardState implements Serializable {
|
|||
abilities = new AbilitiesImpl<>();
|
||||
}
|
||||
abilities.add(ability);
|
||||
for (Ability sub: ability.getSubAbilities()) {
|
||||
for (Ability sub : ability.getSubAbilities()) {
|
||||
abilities.add(sub);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAbilities() {
|
||||
if (abilities != null) {
|
||||
for (Ability ability: abilities) {
|
||||
ability.setSourceId(null);
|
||||
ability.setControllerId(null);
|
||||
}
|
||||
// for (Ability ability: abilities) { // Causes problems if temporary (gained) continuous effects are removed
|
||||
// ability.setSourceId(null);
|
||||
// ability.setControllerId(null);
|
||||
// }
|
||||
abilities = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -364,14 +364,14 @@ public interface Game extends MageItem, Serializable {
|
|||
* This version supports copying of copies of any depth.
|
||||
*
|
||||
* @param copyFromPermanent
|
||||
* @param copyToPermanent
|
||||
* @param copyToPermanentId
|
||||
* @param source
|
||||
* @param applier
|
||||
* @return
|
||||
*/
|
||||
Permanent copyPermanent(Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier);
|
||||
Permanent copyPermanent(Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier);
|
||||
|
||||
Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier);
|
||||
Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier);
|
||||
|
||||
Card copyCard(Card cardToCopy, Ability source, UUID newController);
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ import mage.MageObject;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.DelayedTriggeredAbility;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.common.ChancellorAbility;
|
||||
import mage.abilities.common.GemstoneCavernsAbility;
|
||||
|
@ -77,6 +78,7 @@ import mage.constants.Outcome;
|
|||
import mage.constants.PhaseStep;
|
||||
import mage.constants.PlayerAction;
|
||||
import mage.constants.RangeOfInfluence;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.counters.Counters;
|
||||
|
@ -1402,12 +1404,12 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Permanent copyPermanent(Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier) {
|
||||
return copyPermanent(Duration.Custom, copyFromPermanent, copyToPermanent, source, applier);
|
||||
public Permanent copyPermanent(Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier) {
|
||||
return copyPermanent(Duration.Custom, copyFromPermanent, copyToPermanentId, source, applier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier) {
|
||||
public Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier) {
|
||||
Permanent newBluePrint = null;
|
||||
// handle copies of copies
|
||||
for (Effect effect : getState().getContinuousEffects().getLayeredEffects(this)) {
|
||||
|
@ -1440,7 +1442,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
applier.apply(this, newBluePrint);
|
||||
}
|
||||
|
||||
CopyEffect newEffect = new CopyEffect(duration, newBluePrint, copyToPermanent.getId());
|
||||
CopyEffect newEffect = new CopyEffect(duration, newBluePrint, copyToPermanentId);
|
||||
newEffect.newId();
|
||||
newEffect.setApplier(applier);
|
||||
Ability newAbility = source.copy();
|
||||
|
@ -1686,11 +1688,22 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
SpellAbility spellAbility = perm.getSpellAbility();
|
||||
if (perm.getSpellAbility().getTargets().isEmpty()) {
|
||||
for (Ability ability : perm.getAbilities(this)) {
|
||||
if ((ability instanceof SpellAbility)
|
||||
&& SpellAbilityType.BASE_ALTERNATE.equals(((SpellAbility) ability).getSpellAbilityType())
|
||||
&& !ability.getTargets().isEmpty()) {
|
||||
spellAbility = (SpellAbility) ability;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (spellAbility.getTargets().isEmpty()) {
|
||||
Permanent enchanted = this.getPermanent(perm.getAttachedTo());
|
||||
logger.error("Aura without target: " + perm.getName() + " attached to " + (enchanted == null ? " null" : enchanted.getName()));
|
||||
} else {
|
||||
Target target = perm.getSpellAbility().getTargets().get(0);
|
||||
Target target = spellAbility.getTargets().get(0);
|
||||
if (target instanceof TargetPermanent) {
|
||||
Permanent attachedTo = getPermanent(perm.getAttachedTo());
|
||||
if (attachedTo == null || !attachedTo.getAttachments().contains(perm.getId())) {
|
||||
|
@ -1706,7 +1719,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter();
|
||||
Filter auraFilter = spellAbility.getTargets().get(0).getFilter();
|
||||
if (auraFilter instanceof FilterControlledCreaturePermanent) {
|
||||
if (!((FilterControlledCreaturePermanent) auraFilter).match(attachedTo, perm.getId(), perm.getControllerId(), this)
|
||||
|| attachedTo.cantBeEnchantedBy(perm, this)) {
|
||||
|
@ -1737,7 +1750,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
somethingHappened = true;
|
||||
}
|
||||
} else {
|
||||
Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter();
|
||||
Filter auraFilter = spellAbility.getTargets().get(0).getFilter();
|
||||
if (!auraFilter.match(attachedToPlayer, this) || attachedToPlayer.hasProtectionFrom(perm, this)) {
|
||||
if (movePermanentToGraveyardWithInfo(perm)) {
|
||||
somethingHappened = true;
|
||||
|
|
|
@ -624,7 +624,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
public Permanent getPermanent(UUID permanentId) {
|
||||
if (permanentId != null && battlefield.containsPermanent(permanentId)) {
|
||||
Permanent permanent = battlefield.getPermanent(permanentId);
|
||||
setZone(permanent.getId(), Zone.BATTLEFIELD); // shouldn't this be set anyway? (LevelX2)
|
||||
// setZone(permanent.getId(), Zone.BATTLEFIELD); // shouldn't this be set anyway? (LevelX2)
|
||||
return permanent;
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -1,31 +1,30 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.game.permanent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -49,20 +48,21 @@ public class PermanentCard extends PermanentImpl {
|
|||
|
||||
protected int maxLevelCounters;
|
||||
protected Card card;
|
||||
protected int zoneChangeCounter;
|
||||
// protected int zoneChangeCounter;
|
||||
|
||||
public PermanentCard(Card card, UUID controllerId, Game game) {
|
||||
super(card.getId(), card.getOwnerId(), controllerId, card.getName());
|
||||
this.card = card.copy();
|
||||
// this.card = card.copy();
|
||||
this.card = card;
|
||||
init(card, game);
|
||||
}
|
||||
|
||||
private void init(Card card, Game game) {
|
||||
copyFromCard(card);
|
||||
this.zoneChangeCounter = card.getZoneChangeCounter(game);
|
||||
// this.zoneChangeCounter = card.getZoneChangeCounter(game);
|
||||
/*if (card.getCardType().contains(CardType.PLANESWALKER)) {
|
||||
this.loyalty = new MageInt(card.getLoyalty().getValue());
|
||||
}*/
|
||||
this.loyalty = new MageInt(card.getLoyalty().getValue());
|
||||
}*/
|
||||
if (card instanceof LevelerCard) {
|
||||
maxLevelCounters = ((LevelerCard) card).getMaxLevelCounters();
|
||||
}
|
||||
|
@ -79,7 +79,6 @@ public class PermanentCard extends PermanentImpl {
|
|||
super(permanent);
|
||||
this.card = permanent.card.copy();
|
||||
this.maxLevelCounters = permanent.maxLevelCounters;
|
||||
this.zoneChangeCounter = permanent.zoneChangeCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,13 +93,12 @@ public class PermanentCard extends PermanentImpl {
|
|||
this.name = card.getName();
|
||||
this.abilities.clear();
|
||||
if (this.faceDown) {
|
||||
for (Ability ability: card.getAbilities()) {
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability.getWorksFaceDown()) {
|
||||
this.abilities.add(ability.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.abilities = card.getAbilities().copy();
|
||||
}
|
||||
this.abilities.setControllerId(this.controllerId);
|
||||
|
@ -135,6 +133,7 @@ public class PermanentCard extends PermanentImpl {
|
|||
public Card getCard() {
|
||||
return card;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag) {
|
||||
return moveToZone(toZone, sourceId, game, flag, null);
|
||||
|
@ -258,17 +257,17 @@ public class PermanentCard extends PermanentImpl {
|
|||
|
||||
@Override
|
||||
public int getZoneChangeCounter(Game game) {
|
||||
return this.zoneChangeCounter;
|
||||
return card.getZoneChangeCounter(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateZoneChangeCounter(Game game) {
|
||||
this.zoneChangeCounter++;
|
||||
card.updateZoneChangeCounter(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setZoneChangeCounter(int value, Game game) {
|
||||
this.zoneChangeCounter = value;
|
||||
card.setZoneChangeCounter(value, game);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -221,14 +221,14 @@ public class Spell extends StackObjImpl implements Card {
|
|||
} else if (this.getCardType().contains(CardType.ENCHANTMENT) && this.getSubtype().contains("Aura")) {
|
||||
if (ability.getTargets().stillLegal(ability, game)) {
|
||||
updateOptionalCosts(0);
|
||||
boolean bestow = this.getSpellAbility() instanceof BestowAbility;
|
||||
boolean bestow = ability instanceof BestowAbility;
|
||||
if (bestow) {
|
||||
// Must be removed first time, after that will be removed by continous effect
|
||||
// Otherwise effects like evolve trigger from creature comes into play event
|
||||
card.getCardType().remove(CardType.CREATURE);
|
||||
card.getSubtype().add("Aura");
|
||||
}
|
||||
if (card.putOntoBattlefield(game, fromZone, ability.getSourceId(), controllerId)) {
|
||||
if (card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId)) {
|
||||
if (bestow) {
|
||||
// card will be copied during putOntoBattlefield, so the card of CardPermanent has to be changed
|
||||
// TODO: Find a better way to prevent bestow creatures from being effected by creature affecting abilities
|
||||
|
@ -238,8 +238,6 @@ public class Spell extends StackObjImpl implements Card {
|
|||
((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE);
|
||||
((PermanentCard) permanent).getCard().getSubtype().remove("Aura");
|
||||
}
|
||||
card.getCardType().add(CardType.CREATURE);
|
||||
card.getSubtype().remove("Aura");
|
||||
}
|
||||
return ability.resolve(game);
|
||||
}
|
||||
|
@ -251,7 +249,7 @@ public class Spell extends StackObjImpl implements Card {
|
|||
// Aura has no legal target and its a bestow enchantment -> Add it to battlefield as creature
|
||||
if (this.getSpellAbility() instanceof BestowAbility) {
|
||||
updateOptionalCosts(0);
|
||||
result = card.putOntoBattlefield(game, fromZone, ability.getSourceId(), controllerId);
|
||||
result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId);
|
||||
return result;
|
||||
} else {
|
||||
//20091005 - 608.2b
|
||||
|
@ -263,7 +261,7 @@ public class Spell extends StackObjImpl implements Card {
|
|||
}
|
||||
} else {
|
||||
updateOptionalCosts(0);
|
||||
result = card.putOntoBattlefield(game, fromZone, ability.getSourceId(), controllerId, false, faceDown);
|
||||
result = card.putOntoBattlefield(game, Zone.STACK, ability.getSourceId(), controllerId, false, faceDown);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -646,6 +644,11 @@ public class Spell extends StackObjImpl implements Card {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeFromZone(Game game, Zone fromZone, UUID sourceId) {
|
||||
return card.removeFromZone(game, fromZone, sourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag) {
|
||||
return moveToZone(zone, sourceId, game, flag, null);
|
||||
|
@ -847,4 +850,9 @@ public class Spell extends StackObjImpl implements Card {
|
|||
return countered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkForCountersToAdd(Permanent permanent, Game game) {
|
||||
throw new UnsupportedOperationException("Not supported for Spell");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import mage.MageObject;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -41,6 +42,8 @@ import mage.game.events.GameEvent;
|
|||
*/
|
||||
public class SpellStack extends ArrayDeque<StackObject> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SpellStack.class);
|
||||
|
||||
protected Date dateLastAdded;
|
||||
|
||||
public SpellStack() {
|
||||
|
@ -61,18 +64,21 @@ public class SpellStack extends ArrayDeque<StackObject> {
|
|||
top.resolve(game);
|
||||
} finally {
|
||||
if (top != null) {
|
||||
this.remove(top);
|
||||
if (contains(top)) {
|
||||
logger.warn("StackObject was still on the stack after resoving" + top.getName());
|
||||
this.remove(top);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(StackObject object) {
|
||||
public boolean remove(StackObject object) {
|
||||
for (StackObject spell : this) {
|
||||
if (spell.getId().equals(object.getId())) {
|
||||
super.remove(spell);
|
||||
return;
|
||||
return super.remove(spell);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean counter(UUID objectId, UUID sourceId, Game game) {
|
||||
|
|
|
@ -104,12 +104,15 @@ public class StackAbility extends StackObjImpl implements Ability {
|
|||
@Override
|
||||
public boolean resolve(Game game) {
|
||||
if (ability.getTargets().stillLegal(ability, game)) {
|
||||
return ability.resolve(game);
|
||||
boolean result = ability.resolve(game);
|
||||
game.getStack().remove(this);
|
||||
return result;
|
||||
}
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers("Ability has been fizzled: " + getRule());
|
||||
}
|
||||
counter(null, game);
|
||||
game.getStack().remove(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -635,6 +635,20 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
|
||||
boolean moveCards(Set<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cards
|
||||
* @param toZone
|
||||
* @param source
|
||||
* @param game
|
||||
* @param tapped tha cards are tapped on the battlefield
|
||||
* @param faceDown the cards are face down in the to zone
|
||||
* @param byOwner the card is moved (or put onto battlefield) by the owner
|
||||
* of the card (instead of the controller of the source)
|
||||
* @return
|
||||
*/
|
||||
boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects);
|
||||
|
||||
boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName);
|
||||
|
||||
boolean moveCardsToExile(Set<Card> cards, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName);
|
||||
|
|
|
@ -113,6 +113,7 @@ import mage.game.events.DamagePlayerEvent;
|
|||
import mage.game.events.DamagedPlayerEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.events.ZoneChangeGroupEvent;
|
||||
import mage.game.match.MatchPlayer;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
@ -671,8 +672,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean removeFromHand(Card card, Game game) {
|
||||
hand.remove(card);
|
||||
return true;
|
||||
return hand.remove(card.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3000,13 +3000,13 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
case HAND:
|
||||
for (Card card : cards) {
|
||||
fromZone = game.getState().getZone(card.getId());
|
||||
if (fromZone == Zone.STACK) {
|
||||
// If a spell is returned to its owner's hand, it's removed from the stack and thus will not resolve
|
||||
Spell spell = game.getStack().getSpell(card.getId());
|
||||
if (spell != null) {
|
||||
game.getStack().remove(spell);
|
||||
}
|
||||
}
|
||||
// if (fromZone == Zone.STACK) {
|
||||
// // If a spell is returned to its owner's hand, it's removed from the stack and thus will not resolve
|
||||
// Spell spell = game.getStack().getSpell(card.getId());
|
||||
// if (spell != null) {
|
||||
// game.getStack().remove(spell);
|
||||
// }
|
||||
// }
|
||||
boolean hideCard = fromZone.equals(Zone.LIBRARY)
|
||||
|| (card.isFaceDown(game) && !fromZone.equals(Zone.STACK) && !fromZone.equals(Zone.BATTLEFIELD));
|
||||
if (moveCardToHandWithInfo(card, source == null ? null : source.getSourceId(), game, !hideCard)) {
|
||||
|
@ -3038,6 +3038,69 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return successfulMovedCards.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects) {
|
||||
if (cards.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
Set<Card> successfulMovedCards = new LinkedHashSet<>();
|
||||
Zone fromZone = null;
|
||||
switch (toZone) {
|
||||
case BATTLEFIELD:
|
||||
List<Permanent> permanents = new ArrayList<>();
|
||||
List<Permanent> permanentsEntered = new ArrayList<>();
|
||||
for (Card card : cards) {
|
||||
UUID controllingPlayerId = byOwner ? card.getOwnerId() : source.getControllerId();
|
||||
fromZone = game.getState().getZone(card.getId());
|
||||
if (faceDown) {
|
||||
card.setFaceDown(true, game);
|
||||
}
|
||||
ZoneChangeEvent event = new ZoneChangeEvent(card.getId(), source.getSourceId(), controllingPlayerId, fromZone, Zone.BATTLEFIELD, appliedEffects, tapped);
|
||||
if (!game.replaceEvent(event)) {
|
||||
// get permanent
|
||||
Permanent permanent = new PermanentCard(card, controllingPlayerId, game);
|
||||
permanents.add(permanent);
|
||||
card.checkForCountersToAdd(permanent, game);
|
||||
permanent.setTapped(tapped);
|
||||
permanent.setFaceDown(faceDown, game);
|
||||
}
|
||||
if (faceDown) {
|
||||
card.setFaceDown(false, game);
|
||||
}
|
||||
}
|
||||
game.setScopeRelevant(true);
|
||||
for (Permanent permanent : permanents) {
|
||||
fromZone = game.getState().getZone(permanent.getId());
|
||||
if (permanent.entersBattlefield(source.getSourceId(), game, fromZone, true)) {
|
||||
permanentsEntered.add(permanent);
|
||||
}
|
||||
}
|
||||
game.setScopeRelevant(false);
|
||||
game.applyEffects();
|
||||
for (Permanent permanent : permanentsEntered) {
|
||||
fromZone = game.getState().getZone(permanent.getId());
|
||||
if (((Card) permanent).removeFromZone(game, fromZone, source.getSourceId())) {
|
||||
permanent.updateZoneChangeCounter(game);
|
||||
// make sure the controller of all continuous effects of this card are switched to the current controller
|
||||
game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId());
|
||||
game.addPermanent(permanent);
|
||||
permanent.setZone(Zone.BATTLEFIELD, game);
|
||||
// check if there are counters to add to the permanent (e.g. from non replacement effects like Persist)
|
||||
|
||||
game.setScopeRelevant(true);
|
||||
successfulMovedCards.add(permanent);
|
||||
game.addSimultaneousEvent(new ZoneChangeEvent(permanent, permanent.getControllerId(), fromZone, Zone.BATTLEFIELD));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("to Zone not supported yet");
|
||||
}
|
||||
|
||||
game.fireEvent(new ZoneChangeGroupEvent(successfulMovedCards, source == null ? null : source.getSourceId(), this.getId(), fromZone, toZone));
|
||||
return successfulMovedCards.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) {
|
||||
Set<Card> cards = new HashSet<>();
|
||||
|
|
|
@ -483,23 +483,6 @@ public class CardUtil {
|
|||
return getExileZoneId(getCardZoneString(SOURCE_EXILE_ZONE_TEXT, sourceId, game, previous), game);
|
||||
}
|
||||
|
||||
public static UUID getObjectExileZoneId(Game game, MageObject mageObject) {
|
||||
return getObjectExileZoneId(game, mageObject, false);
|
||||
}
|
||||
|
||||
public static UUID getObjectExileZoneId(Game game, MageObject mageObject, boolean previous) {
|
||||
int zoneChangeCounter = 0;
|
||||
if (mageObject instanceof Permanent) {
|
||||
zoneChangeCounter = ((Permanent) mageObject).getZoneChangeCounter(game);
|
||||
} else if (mageObject instanceof Card) {
|
||||
zoneChangeCounter = ((Card) mageObject).getZoneChangeCounter(game);
|
||||
}
|
||||
if (zoneChangeCounter > 0 && previous) {
|
||||
zoneChangeCounter--;
|
||||
}
|
||||
return getExileZoneId(getObjectZoneString(SOURCE_EXILE_ZONE_TEXT, mageObject.getId(), game, zoneChangeCounter, false), game);
|
||||
}
|
||||
|
||||
public static UUID getExileZoneId(Game game, UUID objectId, int zoneChangeCounter) {
|
||||
return getExileZoneId(getObjectZoneString(SOURCE_EXILE_ZONE_TEXT, objectId, game, zoneChangeCounter, false), game);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue