mirror of
https://github.com/correl/mage.git
synced 2024-12-26 11:09:27 +00:00
[EMN] Implemented basic Meld functionality.
This commit is contained in:
parent
cb91282f9e
commit
e1b3428a39
14 changed files with 1053 additions and 136 deletions
|
@ -40,12 +40,15 @@ import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
import mage.cards.CardsImpl;
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.PermanentCard;
|
||||||
|
import mage.game.permanent.PermanentMeld;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.common.TargetControlledCreaturePermanent;
|
import mage.target.common.TargetControlledCreaturePermanent;
|
||||||
import mage.target.targetpointer.FixedTargets;
|
import mage.target.targetpointer.FixedTargets;
|
||||||
|
@ -105,7 +108,18 @@ class EerieInterludeEffect extends OneShotEffect {
|
||||||
|
|
||||||
Cards cardsToReturn = new CardsImpl();
|
Cards cardsToReturn = new CardsImpl();
|
||||||
for (Card exiled : toExile) {
|
for (Card exiled : toExile) {
|
||||||
if (((Permanent) exiled).getZoneChangeCounter(game) == game.getState().getZoneChangeCounter(exiled.getId()) - 1) {
|
if (exiled instanceof PermanentMeld) {
|
||||||
|
MeldCard meldCard = (MeldCard) ((PermanentCard) exiled).getCard();
|
||||||
|
Card topCard = meldCard.getTopHalfCard();
|
||||||
|
Card bottomCard = meldCard.getBottomHalfCard();
|
||||||
|
if (topCard.getZoneChangeCounter(game) == meldCard.getTopLastZoneChangeCounter()) {
|
||||||
|
cardsToReturn.add(topCard);
|
||||||
|
}
|
||||||
|
if (bottomCard.getZoneChangeCounter(game) == meldCard.getBottomLastZoneChangeCounter()) {
|
||||||
|
cardsToReturn.add(bottomCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (exiled.getZoneChangeCounter(game) == game.getState().getZoneChangeCounter(exiled.getId()) - 1) {
|
||||||
cardsToReturn.add(exiled);
|
cardsToReturn.add(exiled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import mage.abilities.effects.common.continuous.BoostControlledEffect;
|
||||||
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
|
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
|
||||||
import mage.abilities.keyword.HasteAbility;
|
import mage.abilities.keyword.HasteAbility;
|
||||||
import mage.abilities.keyword.MenaceAbility;
|
import mage.abilities.keyword.MenaceAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.MeldCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
|
@ -46,7 +46,7 @@ import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class ChitteringHost extends CardImpl {
|
public class ChitteringHost extends MeldCard {
|
||||||
|
|
||||||
public ChitteringHost(UUID ownerId) {
|
public ChitteringHost(UUID ownerId) {
|
||||||
super(ownerId, 96, "Chittering Host", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "");
|
super(ownerId, 96, "Chittering Host", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "");
|
||||||
|
@ -57,10 +57,13 @@ public class ChitteringHost extends CardImpl {
|
||||||
this.toughness = new MageInt(6);
|
this.toughness = new MageInt(6);
|
||||||
|
|
||||||
this.nightCard = true; // Meld card
|
this.nightCard = true; // Meld card
|
||||||
|
|
||||||
// Haste
|
// Haste
|
||||||
this.addAbility(HasteAbility.getInstance());
|
this.addAbility(HasteAbility.getInstance());
|
||||||
|
|
||||||
// Menace <i>(This creature can't be blocked except by two or more creatures.
|
// Menace <i>(This creature can't be blocked except by two or more creatures.
|
||||||
this.addAbility(new MenaceAbility());
|
this.addAbility(new MenaceAbility());
|
||||||
|
|
||||||
// When Chittering Host enters the battlefield, other creatures you control get +1/+0 and gain menace until end of turn.
|
// When Chittering Host enters the battlefield, other creatures you control get +1/+0 and gain menace until end of turn.
|
||||||
Effect effect = new BoostControlledEffect(1, 0, Duration.EndOfTurn, true);
|
Effect effect = new BoostControlledEffect(1, 0, Duration.EndOfTurn, true);
|
||||||
effect.setText("other creatures you control get +1/+0");
|
effect.setText("other creatures you control get +1/+0");
|
||||||
|
@ -68,7 +71,6 @@ public class ChitteringHost extends CardImpl {
|
||||||
effect = new GainAbilityAllEffect(new MenaceAbility(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("other creatures"), true);
|
effect = new GainAbilityAllEffect(new MenaceAbility(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("other creatures"), true);
|
||||||
effect.setText("and gain menace until end of turn");
|
effect.setText("and gain menace until end of turn");
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChitteringHost(final ChitteringHost card) {
|
public ChitteringHost(final ChitteringHost card) {
|
||||||
|
|
|
@ -29,16 +29,18 @@ package mage.sets.eldritchmoon;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.BeginningOfCombatTriggeredAbility;
|
||||||
import mage.abilities.effects.common.InfoEffect;
|
import mage.abilities.condition.common.MeldCondition;
|
||||||
|
import mage.abilities.decorator.ConditionalTriggeredAbility;
|
||||||
|
import mage.abilities.effects.common.MeldEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
import mage.constants.Zone;
|
import mage.constants.TargetController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author emerald000
|
||||||
*/
|
*/
|
||||||
public class GrafRats extends CardImpl {
|
public class GrafRats extends CardImpl {
|
||||||
|
|
||||||
|
@ -50,7 +52,10 @@ public class GrafRats extends CardImpl {
|
||||||
this.toughness = new MageInt(1);
|
this.toughness = new MageInt(1);
|
||||||
|
|
||||||
// At the beginning of combat on your turn, if you both own and control Graf Rats and a creature named Midnight Scavengers, exile them, then meld them into Chittering Host.
|
// At the beginning of combat on your turn, if you both own and control Graf Rats and a creature named Midnight Scavengers, exile them, then meld them into Chittering Host.
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Meld ability not implemeted yet.")));
|
this.addAbility(new ConditionalTriggeredAbility(
|
||||||
|
new BeginningOfCombatTriggeredAbility(new MeldEffect("Midnight Scavengers", new ChitteringHost(ownerId)), TargetController.YOU, false),
|
||||||
|
new MeldCondition("Midnight Scavengers"),
|
||||||
|
"At the beginning of combat on your turn, if you both own and control {this} and a creature named Midnight Scavengers, exile them, then meld them into Chittering Host."));
|
||||||
}
|
}
|
||||||
|
|
||||||
public GrafRats(final GrafRats card) {
|
public GrafRats(final GrafRats card) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.ReplacementEffectImpl;
|
import mage.abilities.effects.ReplacementEffectImpl;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
@ -93,7 +94,7 @@ class LongRoadHomeEffect extends OneShotEffect {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(source.getFirstTarget());
|
Permanent permanent = game.getPermanent(source.getFirstTarget());
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
if (permanent.moveToExile(source.getSourceId(), "Otherworldly Journey", source.getSourceId(), game)) {
|
if (permanent.moveToExile(source.getSourceId(), "Long Road Home", source.getSourceId(), game)) {
|
||||||
ExileZone exile = game.getExile().getExileZone(source.getSourceId());
|
ExileZone exile = game.getExile().getExileZone(source.getSourceId());
|
||||||
// only if permanent is in exile (tokens would be stop to exist)
|
// only if permanent is in exile (tokens would be stop to exist)
|
||||||
if (exile != null && !exile.isEmpty()) {
|
if (exile != null && !exile.isEmpty()) {
|
||||||
|
@ -147,7 +148,14 @@ class LongRoadHomeReturnFromExileEffect extends OneShotEffect {
|
||||||
if (card != null && objectToReturn.refersTo(card, game)) {
|
if (card != null && objectToReturn.refersTo(card, game)) {
|
||||||
Player owner = game.getPlayer(card.getOwnerId());
|
Player owner = game.getPlayer(card.getOwnerId());
|
||||||
if (owner != null) {
|
if (owner != null) {
|
||||||
|
if (card instanceof MeldCard) {
|
||||||
|
MeldCard meldCard = (MeldCard) card;
|
||||||
|
game.addEffect(new LongRoadHomeEntersBattlefieldEffect(new MageObjectReference(meldCard.getTopHalfCard(), game)), source);
|
||||||
|
game.addEffect(new LongRoadHomeEntersBattlefieldEffect(new MageObjectReference(meldCard.getBottomHalfCard(), game)), source);
|
||||||
|
}
|
||||||
|
else {
|
||||||
game.addEffect(new LongRoadHomeEntersBattlefieldEffect(objectToReturn), source);
|
game.addEffect(new LongRoadHomeEntersBattlefieldEffect(objectToReturn), source);
|
||||||
|
}
|
||||||
owner.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null);
|
owner.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,17 +30,23 @@ package mage.sets.shadowsoverinnistrad;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.ExileTargetForSourceEffect;
|
import mage.abilities.effects.common.ExileTargetForSourceEffect;
|
||||||
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
|
|
||||||
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
|
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.Cards;
|
||||||
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
import mage.game.ExileZone;
|
import mage.game.ExileZone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.players.Player;
|
||||||
import mage.target.common.TargetControlledCreaturePermanent;
|
import mage.target.common.TargetControlledCreaturePermanent;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
@ -60,7 +66,7 @@ public class EssenceFlux extends CardImpl {
|
||||||
Effect effect = new ExileTargetForSourceEffect();
|
Effect effect = new ExileTargetForSourceEffect();
|
||||||
effect.setApplyEffectsAfter();
|
effect.setApplyEffectsAfter();
|
||||||
this.getSpellAbility().addEffect(effect);
|
this.getSpellAbility().addEffect(effect);
|
||||||
this.getSpellAbility().addEffect(new EssenceFluxEffect(false, true));
|
this.getSpellAbility().addEffect(new EssenceFluxEffect());
|
||||||
}
|
}
|
||||||
|
|
||||||
public EssenceFlux(final EssenceFlux card) {
|
public EssenceFlux(final EssenceFlux card) {
|
||||||
|
@ -73,14 +79,14 @@ public class EssenceFlux extends CardImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EssenceFluxEffect extends ReturnToBattlefieldUnderOwnerControlTargetEffect {
|
class EssenceFluxEffect extends OneShotEffect {
|
||||||
|
|
||||||
public EssenceFluxEffect(boolean tapped, boolean fromExileZone) {
|
EssenceFluxEffect() {
|
||||||
super(tapped, fromExileZone);
|
super(Outcome.Benefit);
|
||||||
staticText = ", then return that card to the battlefield under its owner's control. If it's a Spirit, put a +1/+1 counter on it";
|
staticText = "return that card to the battlefield under its owner's control";
|
||||||
}
|
}
|
||||||
|
|
||||||
public EssenceFluxEffect(final EssenceFluxEffect effect) {
|
EssenceFluxEffect(final EssenceFluxEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,24 +97,45 @@ class EssenceFluxEffect extends ReturnToBattlefieldUnderOwnerControlTargetEffect
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Card card = null;
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
UUID exilZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
if (controller != null) {
|
||||||
if (exilZoneId != null) {
|
Cards cardsToBattlefield = new CardsImpl();
|
||||||
ExileZone exileZone = game.getExile().getExileZone(exilZoneId);
|
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||||
if (exileZone != null && getTargetPointer().getFirst(game, source) != null) {
|
if (exileZoneId != null) {
|
||||||
card = exileZone.get(getTargetPointer().getFirst(game, source), game);
|
ExileZone exileZone = game.getExile().getExileZone(exileZoneId);
|
||||||
|
if (exileZone != null) {
|
||||||
|
for (UUID targetId : this.getTargetPointer().getTargets(game, source)) {
|
||||||
|
if (exileZone.contains(targetId)) {
|
||||||
|
cardsToBattlefield.add(targetId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Card card = game.getCard(targetId);
|
||||||
|
if (card != null && card instanceof MeldCard) {
|
||||||
|
MeldCard meldCard = (MeldCard) card;
|
||||||
|
Card topCard = meldCard.getTopHalfCard();
|
||||||
|
Card bottomCard = meldCard.getBottomHalfCard();
|
||||||
|
if (topCard.getZoneChangeCounter(game) == meldCard.getTopLastZoneChangeCounter() && exileZone.contains(topCard.getId())) {
|
||||||
|
cardsToBattlefield.add(topCard);
|
||||||
|
}
|
||||||
|
if (bottomCard.getZoneChangeCounter(game) == meldCard.getBottomLastZoneChangeCounter() && exileZone.contains(bottomCard.getId())) {
|
||||||
|
cardsToBattlefield.add(bottomCard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (super.apply(game, source)) {
|
}
|
||||||
if (card != null) {
|
}
|
||||||
|
}
|
||||||
Permanent permanent = game.getPermanent(card.getId());
|
}
|
||||||
|
if (!cardsToBattlefield.isEmpty()) {
|
||||||
|
controller.moveCards(cardsToBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null);
|
||||||
|
for (UUID cardId : cardsToBattlefield) {
|
||||||
|
Permanent permanent = game.getPermanent(cardId);
|
||||||
if (permanent != null && permanent.getSubtype().contains("Spirit")) {
|
if (permanent != null && permanent.getSubtype().contains("Spirit")) {
|
||||||
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance());
|
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance());
|
||||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||||
return effect.apply(game, source);
|
return effect.apply(game, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* 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.condition.common;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.condition.Condition;
|
||||||
|
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author emerald000
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MeldCondition implements Condition {
|
||||||
|
|
||||||
|
private final String meldWithName;
|
||||||
|
|
||||||
|
public MeldCondition(String meldWithName) {
|
||||||
|
this.meldWithName = meldWithName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
MageObject sourceMageObject = source.getSourceObjectIfItStillExists(game);
|
||||||
|
if (sourceMageObject != null && sourceMageObject instanceof Permanent) {
|
||||||
|
Permanent sourcePermanent = (Permanent) sourceMageObject;
|
||||||
|
if (sourcePermanent.getControllerId().equals(source.getControllerId())
|
||||||
|
&& sourcePermanent.getOwnerId().equals(source.getControllerId())) {
|
||||||
|
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(this.meldWithName);
|
||||||
|
for (Permanent meldWithPermanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
|
||||||
|
if (meldWithPermanent.getOwnerId().equals(source.getControllerId())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
111
Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java
Normal file
111
Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* 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.common;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
|
import mage.filter.predicate.mageobject.NamePredicate;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.TargetPermanent;
|
||||||
|
import mage.target.common.TargetControlledCreaturePermanent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author emerald000
|
||||||
|
*/
|
||||||
|
public class MeldEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
private final String meldWithName;
|
||||||
|
private final MeldCard meldCard;
|
||||||
|
|
||||||
|
public MeldEffect(String meldWithName, MeldCard meldCard) {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
this.meldWithName = meldWithName;
|
||||||
|
this.meldCard = meldCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MeldEffect(final MeldEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
this.meldWithName = effect.meldWithName;
|
||||||
|
this.meldCard = effect.meldCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MeldEffect copy() {
|
||||||
|
return new MeldEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
if (controller != null) {
|
||||||
|
// Find the two permanents to meld.
|
||||||
|
UUID sourceId = source.getSourceId();
|
||||||
|
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature named " + meldWithName);
|
||||||
|
filter.add(new NamePredicate(meldWithName));
|
||||||
|
TargetPermanent target = new TargetControlledCreaturePermanent(filter);
|
||||||
|
Set<UUID> meldWithList = target.possibleTargets(sourceId, source.getControllerId(), game);
|
||||||
|
UUID meldWithId;
|
||||||
|
if (meldWithList.size() == 1) {
|
||||||
|
meldWithId = meldWithList.iterator().next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
controller.choose(Outcome.BoostCreature, target, sourceId, game);
|
||||||
|
meldWithId = target.getFirstTarget();
|
||||||
|
}
|
||||||
|
// Exile the two permanents to meld.
|
||||||
|
Permanent sourcePermanent = game.getPermanent(sourceId);
|
||||||
|
Permanent meldWithPermanent = game.getPermanent(meldWithId);
|
||||||
|
sourcePermanent.moveToExile(null, "", sourceId, game);
|
||||||
|
meldWithPermanent.moveToExile(null, "", sourceId, game);
|
||||||
|
// Create the meld card and move it to the battlefield.
|
||||||
|
Card sourceCard = game.getExile().getCard(sourceId, game);
|
||||||
|
Card meldWithCard = game.getExile().getCard(meldWithId, game);
|
||||||
|
if (!sourceCard.isCopy() && !meldWithCard.isCopy()) {
|
||||||
|
meldCard.setOwnerId(controller.getId());
|
||||||
|
meldCard.setTopHalfCard(meldWithCard, game);
|
||||||
|
meldCard.setbottomHalfCard(sourceCard, game);
|
||||||
|
meldCard.setMelded(true);
|
||||||
|
game.addMeldCard(meldCard.getId(), meldCard);
|
||||||
|
game.getState().addCard(meldCard);
|
||||||
|
meldCard.moveToZone(Zone.BATTLEFIELD, sourceId, game, false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
import mage.cards.CardsImpl;
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.ExileZone;
|
import mage.game.ExileZone;
|
||||||
|
@ -79,34 +80,41 @@ public class ReturnToBattlefieldUnderOwnerControlTargetEffect extends OneShotEff
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
Cards cardsToMove = new CardsImpl();
|
Cards cardsToBattlefield = new CardsImpl();
|
||||||
if (fromExileZone) {
|
if (fromExileZone) {
|
||||||
UUID exilZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||||
if (exilZoneId != null) {
|
if (exileZoneId != null) {
|
||||||
ExileZone exileZone = game.getExile().getExileZone(exilZoneId);
|
ExileZone exileZone = game.getExile().getExileZone(exileZoneId);
|
||||||
if (exileZone != null) {
|
if (exileZone != null) {
|
||||||
for (UUID cardId : getTargetPointer().getTargets(game, source)) {
|
for (UUID targetId : this.getTargetPointer().getTargets(game, source)) {
|
||||||
Card card = exileZone.get(cardId, game);
|
if (exileZone.contains(targetId)) {
|
||||||
if (card != null) {
|
cardsToBattlefield.add(targetId);
|
||||||
cardsToMove.add(card);
|
}
|
||||||
|
else {
|
||||||
|
Card card = game.getCard(targetId);
|
||||||
|
if (card != null && card instanceof MeldCard) {
|
||||||
|
MeldCard meldCard = (MeldCard) card;
|
||||||
|
Card topCard = meldCard.getTopHalfCard();
|
||||||
|
Card bottomCard = meldCard.getBottomHalfCard();
|
||||||
|
if (topCard.getZoneChangeCounter(game) == meldCard.getTopLastZoneChangeCounter() && exileZone.contains(topCard.getId())) {
|
||||||
|
cardsToBattlefield.add(topCard);
|
||||||
|
}
|
||||||
|
if (bottomCard.getZoneChangeCounter(game) == meldCard.getBottomLastZoneChangeCounter() && exileZone.contains(bottomCard.getId())) {
|
||||||
|
cardsToBattlefield.add(bottomCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (UUID cardId : getTargetPointer().getTargets(game, source)) {
|
cardsToBattlefield.addAll(getTargetPointer().getTargets(game, source));
|
||||||
Card card = game.getCard(cardId);
|
|
||||||
if (card != null) {
|
|
||||||
cardsToMove.add(card);
|
|
||||||
}
|
}
|
||||||
|
if (!cardsToBattlefield.isEmpty()) {
|
||||||
|
controller.moveCards(cardsToBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, tapped, false, true, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!cardsToMove.isEmpty()) {
|
|
||||||
controller.moveCards(cardsToMove.getCards(game),
|
|
||||||
Zone.BATTLEFIELD, source, game, tapped, false, true, null);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
import mage.cards.CardsImpl;
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.ExileZone;
|
import mage.game.ExileZone;
|
||||||
|
@ -79,13 +80,27 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
Cards cardsToBattlefield = new CardsImpl();
|
Cards cardsToBattlefield = new CardsImpl();
|
||||||
if (fromExileZone) {
|
if (fromExileZone) {
|
||||||
UUID exilZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
||||||
if (exilZoneId != null) {
|
if (exileZoneId != null) {
|
||||||
ExileZone exileZone = game.getExile().getExileZone(exilZoneId);
|
ExileZone exileZone = game.getExile().getExileZone(exileZoneId);
|
||||||
if (exileZone != null) {
|
if (exileZone != null) {
|
||||||
for (Card card : exileZone.getCards(game)) {
|
for (UUID targetId : this.getTargetPointer().getTargets(game, source)) {
|
||||||
if (getTargetPointer().getTargets(game, source).contains(card.getId())) {
|
if (exileZone.contains(targetId)) {
|
||||||
cardsToBattlefield.add(card);
|
cardsToBattlefield.add(targetId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Card card = game.getCard(targetId);
|
||||||
|
if (card != null && card instanceof MeldCard) {
|
||||||
|
MeldCard meldCard = (MeldCard) card;
|
||||||
|
Card topCard = meldCard.getTopHalfCard();
|
||||||
|
Card bottomCard = meldCard.getBottomHalfCard();
|
||||||
|
if (topCard.getZoneChangeCounter(game) == meldCard.getTopLastZoneChangeCounter() && exileZone.contains(topCard.getId())) {
|
||||||
|
cardsToBattlefield.add(topCard);
|
||||||
|
}
|
||||||
|
if (bottomCard.getZoneChangeCounter(game) == meldCard.getBottomLastZoneChangeCounter() && exileZone.contains(bottomCard.getId())) {
|
||||||
|
cardsToBattlefield.add(bottomCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
373
Mage/src/main/java/mage/cards/MeldCard.java
Normal file
373
Mage/src/main/java/mage/cards/MeldCard.java
Normal file
|
@ -0,0 +1,373 @@
|
||||||
|
/*
|
||||||
|
* 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.cards;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
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 mage.counters.Counter;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
import mage.game.permanent.PermanentMeld;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author emerald000
|
||||||
|
*/
|
||||||
|
public abstract class MeldCard extends CardImpl {
|
||||||
|
|
||||||
|
protected Card topHalfCard;
|
||||||
|
protected Card bottomHalfCard;
|
||||||
|
protected int topLastZoneChangeCounter;
|
||||||
|
protected int bottomLastZoneChangeCounter;
|
||||||
|
protected boolean isMelded;
|
||||||
|
|
||||||
|
public MeldCard(UUID ownerId, int cardNumber, String name, Rarity rarity, CardType[] cardTypes, String costs) {
|
||||||
|
super(ownerId, cardNumber, name, rarity, cardTypes, costs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MeldCard(MeldCard card) {
|
||||||
|
super(card);
|
||||||
|
this.topHalfCard = card.topHalfCard;
|
||||||
|
this.bottomHalfCard = card.bottomHalfCard;
|
||||||
|
this.topLastZoneChangeCounter = card.topLastZoneChangeCounter;
|
||||||
|
this.bottomLastZoneChangeCounter = card.bottomLastZoneChangeCounter;
|
||||||
|
this.isMelded = card.isMelded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMelded(boolean isMelded) {
|
||||||
|
this.isMelded = isMelded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMelded() {
|
||||||
|
return isMelded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Card getTopHalfCard() {
|
||||||
|
return topHalfCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopHalfCard(Card topHalfCard, Game game) {
|
||||||
|
this.topHalfCard = topHalfCard;
|
||||||
|
this.topLastZoneChangeCounter = topHalfCard.getZoneChangeCounter(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTopLastZoneChangeCounter() {
|
||||||
|
return topLastZoneChangeCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopLastZoneChangeCounter(int topLastZoneChangeCounter) {
|
||||||
|
this.topLastZoneChangeCounter = topLastZoneChangeCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Card getBottomHalfCard() {
|
||||||
|
return bottomHalfCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setbottomHalfCard(Card bottomHalfCard, Game game) {
|
||||||
|
this.bottomHalfCard = bottomHalfCard;
|
||||||
|
this.bottomLastZoneChangeCounter = bottomHalfCard.getZoneChangeCounter(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBottomLastZoneChangeCounter() {
|
||||||
|
return bottomLastZoneChangeCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBottomLastZoneChangeCounter(int bottomLastZoneChangeCounter) {
|
||||||
|
this.bottomLastZoneChangeCounter = bottomLastZoneChangeCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assignNewId() {
|
||||||
|
super.assignNewId();
|
||||||
|
topHalfCard.assignNewId();
|
||||||
|
bottomHalfCard.assignNewId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCopy(boolean isCopy) {
|
||||||
|
super.setCopy(isCopy);
|
||||||
|
topHalfCard.setCopy(isCopy);
|
||||||
|
bottomHalfCard.setCopy(isCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, ArrayList<UUID> appliedEffects) {
|
||||||
|
if (this.isMelded()) {
|
||||||
|
// Initial move to battlefield
|
||||||
|
if (toZone == Zone.BATTLEFIELD) {
|
||||||
|
return this.putOntoBattlefield(game, Zone.EXILED, sourceId, this.getOwnerId(), false, false, appliedEffects);
|
||||||
|
}
|
||||||
|
// Move when melded from the battlefield to elsewhere
|
||||||
|
else {
|
||||||
|
ZoneChangeEvent event = new ZoneChangeEvent(this.getId(), sourceId, this.getOwnerId(), Zone.BATTLEFIELD, toZone, appliedEffects);
|
||||||
|
if (!game.replaceEvent(event)) {
|
||||||
|
updateZoneChangeCounter(game);
|
||||||
|
switch (event.getToZone()) {
|
||||||
|
case GRAVEYARD:
|
||||||
|
game.getPlayer(this.getOwnerId()).putInGraveyard(topHalfCard, game, true);
|
||||||
|
game.getPlayer(this.getOwnerId()).putInGraveyard(bottomHalfCard, game, true);
|
||||||
|
break;
|
||||||
|
case HAND:
|
||||||
|
game.getPlayer(this.getOwnerId()).getHand().add(topHalfCard);
|
||||||
|
game.getPlayer(this.getOwnerId()).getHand().add(bottomHalfCard);
|
||||||
|
break;
|
||||||
|
case EXILED:
|
||||||
|
game.getExile().getPermanentExile().add(topHalfCard);
|
||||||
|
game.getExile().getPermanentExile().add(bottomHalfCard);
|
||||||
|
break;
|
||||||
|
case LIBRARY:
|
||||||
|
Player controller = game.getPlayer(this.getOwnerId());
|
||||||
|
if (controller != null) {
|
||||||
|
CardsImpl cardsToMove = new CardsImpl();
|
||||||
|
cardsToMove.add(topHalfCard);
|
||||||
|
cardsToMove.add(bottomHalfCard);
|
||||||
|
if (flag) {
|
||||||
|
controller.putCardsOnTopOfLibrary(cardsToMove, game, null, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
controller.putCardsOnBottomOfLibrary(cardsToMove, game, null, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.setMelded(false);
|
||||||
|
game.setZone(topHalfCard.getId(), event.getToZone());
|
||||||
|
game.setZone(bottomHalfCard.getId(), event.getToZone());
|
||||||
|
this.topLastZoneChangeCounter = topHalfCard.getZoneChangeCounter(game);
|
||||||
|
this.bottomLastZoneChangeCounter = bottomHalfCard.getZoneChangeCounter(game);
|
||||||
|
game.addSimultaneousEvent(event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Try to move the former meld cards after it has already left the battlefield.
|
||||||
|
// If the meld parts didn't move from that zone, move them instead of the meld card.
|
||||||
|
// Reset the local zcc so the meld card lose track of them.
|
||||||
|
boolean returnValue = false;
|
||||||
|
if (topLastZoneChangeCounter == topHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
topHalfCard.moveToZone(toZone, sourceId, game, flag, appliedEffects);
|
||||||
|
topLastZoneChangeCounter = topHalfCard.getZoneChangeCounter(game);
|
||||||
|
returnValue = true;
|
||||||
|
}
|
||||||
|
if (bottomLastZoneChangeCounter == bottomHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
bottomHalfCard.moveToZone(toZone, sourceId, game, flag, appliedEffects);
|
||||||
|
bottomLastZoneChangeCounter = bottomHalfCard.getZoneChangeCounter(game);
|
||||||
|
returnValue = true;
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList<UUID> appliedEffects) {
|
||||||
|
if (this.isMelded()) {
|
||||||
|
// Move when melded from the battlefield to exile
|
||||||
|
ZoneChangeEvent event = new ZoneChangeEvent(this.getId(), sourceId, this.getOwnerId(), Zone.BATTLEFIELD, Zone.EXILED, appliedEffects);
|
||||||
|
if (!game.replaceEvent(event)) {
|
||||||
|
updateZoneChangeCounter(game);
|
||||||
|
switch (event.getToZone()) {
|
||||||
|
case GRAVEYARD:
|
||||||
|
game.getPlayer(this.getOwnerId()).putInGraveyard(topHalfCard, game, true);
|
||||||
|
game.getPlayer(this.getOwnerId()).putInGraveyard(bottomHalfCard, game, true);
|
||||||
|
break;
|
||||||
|
case HAND:
|
||||||
|
game.getPlayer(this.getOwnerId()).getHand().add(topHalfCard);
|
||||||
|
game.getPlayer(this.getOwnerId()).getHand().add(bottomHalfCard);
|
||||||
|
break;
|
||||||
|
case EXILED:
|
||||||
|
if (exileId == null) {
|
||||||
|
game.getExile().getPermanentExile().add(topHalfCard);
|
||||||
|
game.getExile().getPermanentExile().add(bottomHalfCard);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
game.getExile().createZone(exileId, name).add(topHalfCard);
|
||||||
|
game.getExile().getExileZone(exileId).add(bottomHalfCard);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIBRARY:
|
||||||
|
Player controller = game.getPlayer(this.getOwnerId());
|
||||||
|
if (controller != null) {
|
||||||
|
CardsImpl cardsToMove = new CardsImpl();
|
||||||
|
cardsToMove.add(topHalfCard);
|
||||||
|
cardsToMove.add(bottomHalfCard);
|
||||||
|
if (event.getFlag()) {
|
||||||
|
controller.putCardsOnTopOfLibrary(cardsToMove, game, null, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
controller.putCardsOnBottomOfLibrary(cardsToMove, game, null, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.setMelded(false);
|
||||||
|
game.setZone(topHalfCard.getId(), event.getToZone());
|
||||||
|
game.setZone(bottomHalfCard.getId(), event.getToZone());
|
||||||
|
this.topLastZoneChangeCounter = topHalfCard.getZoneChangeCounter(game);
|
||||||
|
this.bottomLastZoneChangeCounter = bottomHalfCard.getZoneChangeCounter(game);
|
||||||
|
game.addSimultaneousEvent(event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Try to move the former meld cards after it has already left the battlefield.
|
||||||
|
// If the meld parts didn't move from that zone, move them instead of the meld card.
|
||||||
|
// Reset the local zcc so the meld card lose track of them.
|
||||||
|
boolean returnValue = false;
|
||||||
|
if (topLastZoneChangeCounter == topHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
topHalfCard.moveToExile(exileId, name, sourceId, game, appliedEffects);
|
||||||
|
topLastZoneChangeCounter = topHalfCard.getZoneChangeCounter(game);
|
||||||
|
returnValue = true;
|
||||||
|
}
|
||||||
|
if (bottomLastZoneChangeCounter == bottomHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
bottomHalfCard.moveToExile(exileId, name, sourceId, game, appliedEffects);
|
||||||
|
bottomLastZoneChangeCounter = bottomHalfCard.getZoneChangeCounter(game);
|
||||||
|
returnValue = true;
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown, ArrayList<UUID> appliedEffects) {
|
||||||
|
// Initial move to battlefield
|
||||||
|
if (this.isMelded()) {
|
||||||
|
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, controllerId, Zone.EXILED, Zone.BATTLEFIELD, appliedEffects);
|
||||||
|
if (!game.replaceEvent(event) && event.getToZone() == Zone.BATTLEFIELD) {
|
||||||
|
updateZoneChangeCounter(game);
|
||||||
|
PermanentMeld permanent = new PermanentMeld(this, event.getPlayerId(), game); // controller can be replaced (e.g. Gather Specimens)
|
||||||
|
game.addPermanent(permanent);
|
||||||
|
game.setZone(objectId, Zone.BATTLEFIELD);
|
||||||
|
game.setScopeRelevant(true);
|
||||||
|
game.applyEffects();
|
||||||
|
boolean entered = permanent.entersBattlefield(sourceId, game, event.getFromZone(), true);
|
||||||
|
game.setScopeRelevant(false);
|
||||||
|
game.applyEffects();
|
||||||
|
if (entered) {
|
||||||
|
if (event.getFlag()) {
|
||||||
|
permanent.setTapped(true);
|
||||||
|
}
|
||||||
|
event.setTarget(permanent);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
game.setZone(objectId, event.getToZone());
|
||||||
|
game.addSimultaneousEvent(event);
|
||||||
|
game.getExile().removeCard(this.topHalfCard, game);
|
||||||
|
game.getExile().removeCard(this.bottomHalfCard, game);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setMelded(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Try to move the former meld cards after it has already left the battlefield.
|
||||||
|
// If the meld parts didn't move from that zone, move them instead of the meld card.
|
||||||
|
// Reset the local zcc so the meld card lose track of them.
|
||||||
|
boolean returnValue = false;
|
||||||
|
if (topLastZoneChangeCounter == topHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
topHalfCard.moveToZone(Zone.BATTLEFIELD, sourceId, game, tapped, appliedEffects);
|
||||||
|
topLastZoneChangeCounter = topHalfCard.getZoneChangeCounter(game);
|
||||||
|
returnValue = true;
|
||||||
|
}
|
||||||
|
if (bottomLastZoneChangeCounter == bottomHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
bottomHalfCard.moveToZone(Zone.BATTLEFIELD, sourceId, game, tapped, appliedEffects);
|
||||||
|
bottomLastZoneChangeCounter = bottomHalfCard.getZoneChangeCounter(game);
|
||||||
|
returnValue = true;
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOwnerId(UUID ownerId) {
|
||||||
|
super.setOwnerId(ownerId);
|
||||||
|
abilities.setControllerId(ownerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getConvertedManaCost() {
|
||||||
|
if (this.isCopy()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return this.topHalfCard.getConvertedManaCost() + this.bottomHalfCard.getConvertedManaCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCounters(Counter counter, Game game, ArrayList<UUID> appliedEffects) {
|
||||||
|
if (this.isMelded()) {
|
||||||
|
super.addCounters(counter, game, appliedEffects);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (topLastZoneChangeCounter == topHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
topHalfCard.addCounters(counter, game, appliedEffects);
|
||||||
|
}
|
||||||
|
if (bottomLastZoneChangeCounter == bottomHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
bottomHalfCard.addCounters(counter, game, appliedEffects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCounters(String name, int amount, Game game, ArrayList<UUID> appliedEffects) {
|
||||||
|
if (this.isMelded()) {
|
||||||
|
super.addCounters(name, amount, game, appliedEffects);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (topLastZoneChangeCounter == topHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
topHalfCard.addCounters(name, amount, game, appliedEffects);
|
||||||
|
}
|
||||||
|
if (bottomLastZoneChangeCounter == bottomHalfCard.getZoneChangeCounter(game)) {
|
||||||
|
bottomHalfCard.addCounters(name, amount, game, appliedEffects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,6 +47,7 @@ import mage.abilities.effects.PreventionEffectData;
|
||||||
import mage.actions.impl.MageAction;
|
import mage.actions.impl.MageAction;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
import mage.cards.decks.Deck;
|
import mage.cards.decks.Deck;
|
||||||
import mage.choices.Choice;
|
import mage.choices.Choice;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
|
@ -93,6 +94,10 @@ public interface Game extends MageItem, Serializable {
|
||||||
|
|
||||||
Collection<Card> getCards();
|
Collection<Card> getCards();
|
||||||
|
|
||||||
|
MeldCard getMeldCard(UUID meldId);
|
||||||
|
|
||||||
|
void addMeldCard(UUID meldId, MeldCard meldCard);
|
||||||
|
|
||||||
Object getCustomData();
|
Object getCustomData();
|
||||||
|
|
||||||
void setCustomData(Object data);
|
void setCustomData(Object data);
|
||||||
|
|
|
@ -67,6 +67,7 @@ import mage.actions.impl.MageAction;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
import mage.cards.CardsImpl;
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCard;
|
||||||
import mage.cards.SplitCardHalf;
|
import mage.cards.SplitCardHalf;
|
||||||
import mage.cards.decks.Deck;
|
import mage.cards.decks.Deck;
|
||||||
|
@ -169,6 +170,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource();
|
protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource();
|
||||||
|
|
||||||
protected Map<UUID, Card> gameCards = new HashMap<>();
|
protected Map<UUID, Card> gameCards = new HashMap<>();
|
||||||
|
protected Map<UUID, MeldCard> meldCards = new HashMap<>(0);
|
||||||
|
|
||||||
protected Map<Zone, HashMap<UUID, MageObject>> lki = new EnumMap<>(Zone.class);
|
protected Map<Zone, HashMap<UUID, MageObject>> lki = new EnumMap<>(Zone.class);
|
||||||
protected Map<UUID, Map<Integer, MageObject>> lkiExtended = new HashMap<>();
|
protected Map<UUID, Map<Integer, MageObject>> lkiExtended = new HashMap<>();
|
||||||
|
@ -320,6 +322,16 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
return gameCards.values();
|
return gameCards.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addMeldCard(UUID meldId, MeldCard meldCard) {
|
||||||
|
meldCards.put(meldId, meldCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MeldCard getMeldCard(UUID meldId) {
|
||||||
|
return meldCards.get(meldId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPlayer(Player player, Deck deck) throws GameException {
|
public void addPlayer(Player player, Deck deck) throws GameException {
|
||||||
player.useDeck(deck, this);
|
player.useDeck(deck, this);
|
||||||
|
@ -521,7 +533,10 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
}
|
}
|
||||||
Card card = gameCards.get(cardId);
|
Card card = gameCards.get(cardId);
|
||||||
if (card == null) {
|
if (card == null) {
|
||||||
return state.getCopiedCard(cardId);
|
card = state.getCopiedCard(cardId);
|
||||||
|
}
|
||||||
|
if (card == null) {
|
||||||
|
card = this.getMeldCard(cardId);
|
||||||
}
|
}
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
@ -706,6 +721,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
@Override
|
@Override
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
gameCards.clear();
|
gameCards.clear();
|
||||||
|
meldCards.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
177
Mage/src/main/java/mage/game/permanent/PermanentMeld.java
Normal file
177
Mage/src/main/java/mage/game/permanent/PermanentMeld.java
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author emerald000
|
||||||
|
*/
|
||||||
|
public class PermanentMeld extends PermanentCard {
|
||||||
|
|
||||||
|
public PermanentMeld(Card card, UUID controllerId, Game game) {
|
||||||
|
super(card, controllerId, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getConvertedManaCost() {
|
||||||
|
if (this.isCopy()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return this.getCard().getConvertedManaCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, ArrayList<UUID> appliedEffects) {
|
||||||
|
ZoneChangeEvent event = new ZoneChangeEvent(this.getId(), sourceId, this.getOwnerId(), Zone.BATTLEFIELD, toZone, appliedEffects);
|
||||||
|
if (!game.replaceEvent(event)) {
|
||||||
|
Player controller = game.getPlayer(this.getControllerId());
|
||||||
|
if (controller != null) {
|
||||||
|
controller.removeFromBattlefield(this, game);
|
||||||
|
updateZoneChangeCounter(game);
|
||||||
|
MeldCard meldCard = (MeldCard) this.getCard();
|
||||||
|
Card topHalfCard = meldCard.getTopHalfCard();
|
||||||
|
Card bottomHalfCard = meldCard.getBottomHalfCard();
|
||||||
|
switch (event.getToZone()) {
|
||||||
|
case GRAVEYARD:
|
||||||
|
game.getPlayer(this.getOwnerId()).putInGraveyard(topHalfCard, game, true);
|
||||||
|
game.getPlayer(this.getOwnerId()).putInGraveyard(bottomHalfCard, game, true);
|
||||||
|
break;
|
||||||
|
case HAND:
|
||||||
|
game.getPlayer(this.getOwnerId()).getHand().add(topHalfCard);
|
||||||
|
game.getPlayer(this.getOwnerId()).getHand().add(bottomHalfCard);
|
||||||
|
break;
|
||||||
|
case EXILED:
|
||||||
|
game.getExile().getPermanentExile().add(topHalfCard);
|
||||||
|
game.getExile().getPermanentExile().add(bottomHalfCard);
|
||||||
|
break;
|
||||||
|
case LIBRARY:
|
||||||
|
CardsImpl cardsToMove = new CardsImpl();
|
||||||
|
cardsToMove.add(topHalfCard);
|
||||||
|
cardsToMove.add(bottomHalfCard);
|
||||||
|
if (flag) {
|
||||||
|
controller.putCardsOnTopOfLibrary(cardsToMove, game, null, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
controller.putCardsOnBottomOfLibrary(cardsToMove, game, null, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
meldCard.setMelded(false);
|
||||||
|
game.setZone(topHalfCard.getId(), event.getToZone());
|
||||||
|
game.setZone(bottomHalfCard.getId(), event.getToZone());
|
||||||
|
meldCard.setTopLastZoneChangeCounter(topHalfCard.getZoneChangeCounter(game));
|
||||||
|
meldCard.setBottomLastZoneChangeCounter(bottomHalfCard.getZoneChangeCounter(game));
|
||||||
|
game.addSimultaneousEvent(event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList<UUID> appliedEffects) {
|
||||||
|
ZoneChangeEvent event = new ZoneChangeEvent(this.getId(), sourceId, this.getOwnerId(), Zone.BATTLEFIELD, Zone.EXILED, appliedEffects);
|
||||||
|
if (!game.replaceEvent(event)) {
|
||||||
|
Player controller = game.getPlayer(this.getControllerId());
|
||||||
|
if (controller != null) {
|
||||||
|
controller.removeFromBattlefield(this, game);
|
||||||
|
updateZoneChangeCounter(game);
|
||||||
|
MeldCard meldCard = (MeldCard) this.getCard();
|
||||||
|
Card topHalfCard = meldCard.getTopHalfCard();
|
||||||
|
Card bottomHalfCard = meldCard.getBottomHalfCard();
|
||||||
|
switch (event.getToZone()) {
|
||||||
|
case GRAVEYARD:
|
||||||
|
game.getPlayer(this.getOwnerId()).putInGraveyard(topHalfCard, game, true);
|
||||||
|
game.getPlayer(this.getOwnerId()).putInGraveyard(bottomHalfCard, game, true);
|
||||||
|
break;
|
||||||
|
case HAND:
|
||||||
|
game.getPlayer(this.getOwnerId()).getHand().add(topHalfCard);
|
||||||
|
game.getPlayer(this.getOwnerId()).getHand().add(bottomHalfCard);
|
||||||
|
break;
|
||||||
|
case EXILED:
|
||||||
|
if (exileId == null) {
|
||||||
|
game.getExile().getPermanentExile().add(topHalfCard);
|
||||||
|
game.getExile().getPermanentExile().add(bottomHalfCard);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
game.getExile().createZone(exileId, name).add(topHalfCard);
|
||||||
|
game.getExile().getExileZone(exileId).add(bottomHalfCard);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIBRARY:
|
||||||
|
CardsImpl cardsToMove = new CardsImpl();
|
||||||
|
cardsToMove.add(topHalfCard);
|
||||||
|
cardsToMove.add(bottomHalfCard);
|
||||||
|
if (event.getFlag()) {
|
||||||
|
controller.putCardsOnTopOfLibrary(cardsToMove, game, null, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
controller.putCardsOnBottomOfLibrary(cardsToMove, game, null, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
meldCard.setMelded(false);
|
||||||
|
game.setZone(topHalfCard.getId(), event.getToZone());
|
||||||
|
game.setZone(bottomHalfCard.getId(), event.getToZone());
|
||||||
|
meldCard.setTopLastZoneChangeCounter(topHalfCard.getZoneChangeCounter(game));
|
||||||
|
meldCard.setBottomLastZoneChangeCounter(bottomHalfCard.getZoneChangeCounter(game));
|
||||||
|
game.addSimultaneousEvent(event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCounters(String name, int amount, Game game, ArrayList<UUID> appliedEffects) {
|
||||||
|
MeldCard meldCard = (MeldCard) this.getCard();
|
||||||
|
if (meldCard.isMelded()) {
|
||||||
|
super.addCounters(name, amount, game, appliedEffects);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
meldCard.getTopHalfCard().addCounters(name, amount, game, appliedEffects);
|
||||||
|
meldCard.getBottomHalfCard().addCounters(name, amount, game, appliedEffects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,6 +83,7 @@ import mage.actions.MageDrawAction;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
import mage.cards.CardsImpl;
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.cards.MeldCard;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCard;
|
||||||
import mage.cards.decks.Deck;
|
import mage.cards.decks.Deck;
|
||||||
import mage.constants.AbilityType;
|
import mage.constants.AbilityType;
|
||||||
|
@ -120,6 +121,7 @@ import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.game.match.MatchPlayer;
|
import mage.game.match.MatchPlayer;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.PermanentCard;
|
import mage.game.permanent.PermanentCard;
|
||||||
|
import mage.game.permanent.PermanentMeld;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
import mage.game.stack.StackAbility;
|
import mage.game.stack.StackAbility;
|
||||||
import mage.game.stack.StackObject;
|
import mage.game.stack.StackObject;
|
||||||
|
@ -177,9 +179,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
protected Date dateLastAddedToStack; // F10
|
protected Date dateLastAddedToStack; // F10
|
||||||
protected boolean skippedAtLeastOnce; // used to track if passed started in specific phase
|
protected boolean skippedAtLeastOnce; // used to track if passed started in specific phase
|
||||||
/**
|
/**
|
||||||
* This indicates that player passed all turns until his own turn starts
|
* This indicates that player passed all turns until his own turn starts (F9). Note! This differs from passedTurn as it doesn't care about spells and abilities in the stack and will pass them as well.
|
||||||
* (F9). Note! This differs from passedTurn as it doesn't care about spells
|
|
||||||
* and abilities in the stack and will pass them as well.
|
|
||||||
*/
|
*/
|
||||||
protected boolean passedAllTurns; // F9
|
protected boolean passedAllTurns; // F9
|
||||||
protected AbilityType justActivatedType; // used to check if priority can be passed automatically
|
protected AbilityType justActivatedType; // used to check if priority can be passed automatically
|
||||||
|
@ -524,13 +524,15 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
inRange.add(player.getId());
|
inRange.add(player.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((range.getRange() * 2) + 1 >= game.getPlayers().size()) {
|
}
|
||||||
|
else if ((range.getRange() * 2) + 1 >= game.getPlayers().size()) {
|
||||||
for (Player player : game.getPlayers().values()) {
|
for (Player player : game.getPlayers().values()) {
|
||||||
if (!player.hasLeft()) {
|
if (!player.hasLeft()) {
|
||||||
inRange.add(player.getId());
|
inRange.add(player.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
inRange.add(playerId);
|
inRange.add(playerId);
|
||||||
PlayerList players = game.getState().getPlayerList(playerId);
|
PlayerList players = game.getState().getPlayerList(playerId);
|
||||||
for (int i = 0; i < range.getRange(); i++) {
|
for (int i = 0; i < range.getRange(); i++) {
|
||||||
|
@ -593,8 +595,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns true if the player has the control itself - false if the player
|
* returns true if the player has the control itself - false if the player is controlled by another player
|
||||||
* is controlled by another player
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@ -678,7 +679,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (card.getOwnerId().equals(playerId)) {
|
if (card.getOwnerId().equals(playerId)) {
|
||||||
card.setZone(Zone.HAND, game);
|
card.setZone(Zone.HAND, game);
|
||||||
this.hand.add(card);
|
this.hand.add(card);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return game.getPlayer(card.getOwnerId()).putInHand(card, game);
|
return game.getPlayer(card.getOwnerId()).putInHand(card, game);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -736,7 +738,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
discard(card, source, game);
|
discard(card, source, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
int possibleAmount = Math.min(getHand().size(), amount);
|
int possibleAmount = Math.min(getHand().size(), amount);
|
||||||
TargetDiscard target = new TargetDiscard(possibleAmount, possibleAmount, new FilterCard(CardUtil.numberToText(possibleAmount, "a") + " card" + (possibleAmount > 1 ? "s" : "")), playerId);
|
TargetDiscard target = new TargetDiscard(possibleAmount, possibleAmount, new FilterCard(CardUtil.numberToText(possibleAmount, "a") + " card" + (possibleAmount > 1 ? "s" : "")), playerId);
|
||||||
choose(Outcome.Discard, target, source == null ? null : source.getSourceId(), game);
|
choose(Outcome.Discard, target, source == null ? null : source.getSourceId(), game);
|
||||||
|
@ -830,7 +833,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
Permanent attachedTo = game.getPermanent(permanent.getAttachedTo());
|
Permanent attachedTo = game.getPermanent(permanent.getAttachedTo());
|
||||||
if (attachedTo != null) {
|
if (attachedTo != null) {
|
||||||
attachedTo.removeAttachment(permanent.getId(), game);
|
attachedTo.removeAttachment(permanent.getId(), game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Player attachedToPlayer = game.getPlayer(permanent.getAttachedTo());
|
Player attachedToPlayer = game.getPlayer(permanent.getAttachedTo());
|
||||||
if (attachedToPlayer != null) {
|
if (attachedToPlayer != null) {
|
||||||
attachedToPlayer.removeAttachment(permanent, game);
|
attachedToPlayer.removeAttachment(permanent, game);
|
||||||
|
@ -851,7 +855,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
public boolean putInGraveyard(Card card, Game game, boolean fromBattlefield) {
|
public boolean putInGraveyard(Card card, Game game, boolean fromBattlefield) {
|
||||||
if (card.getOwnerId().equals(playerId)) {
|
if (card.getOwnerId().equals(playerId)) {
|
||||||
this.graveyard.add(card);
|
this.graveyard.add(card);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return game.getPlayer(card.getOwnerId()).putInGraveyard(card, game, fromBattlefield);
|
return game.getPlayer(card.getOwnerId()).putInGraveyard(card, game, fromBattlefield);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -870,7 +875,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
for (UUID objectId : cards) {
|
for (UUID objectId : cards) {
|
||||||
moveObjectToLibrary(objectId, source == null ? null : source.getSourceId(), game, false, false);
|
moveObjectToLibrary(objectId, source == null ? null : source.getSourceId(), game, false, false);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
TargetCard target = new TargetCard(Zone.ALL, new FilterCard("card to put on the bottom of your library (last one chosen will be bottommost)"));
|
TargetCard target = new TargetCard(Zone.ALL, new FilterCard("card to put on the bottom of your library (last one chosen will be bottommost)"));
|
||||||
target.setRequired(true);
|
target.setRequired(true);
|
||||||
while (isInGame() && cards.size() > 1) {
|
while (isInGame() && cards.size() > 1) {
|
||||||
|
@ -906,7 +912,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
for (UUID cardId : cards) {
|
for (UUID cardId : cards) {
|
||||||
moveObjectToLibrary(cardId, sourceId, game, true, false);
|
moveObjectToLibrary(cardId, sourceId, game, true, false);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of your library (last one chosen will be topmost)"));
|
TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of your library (last one chosen will be topmost)"));
|
||||||
target.setRequired(true);
|
target.setRequired(true);
|
||||||
while (isInGame() && cards.size() > 1) {
|
while (isInGame() && cards.size() > 1) {
|
||||||
|
@ -930,7 +937,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
Zone fromZone = game.getState().getZone(objectId);
|
Zone fromZone = game.getState().getZone(objectId);
|
||||||
if ((mageObject instanceof Permanent)) {
|
if ((mageObject instanceof Permanent)) {
|
||||||
return this.moveCardToLibraryWithInfo((Permanent) mageObject, sourceId, game, fromZone, toTop, withName);
|
return this.moveCardToLibraryWithInfo((Permanent) mageObject, sourceId, game, fromZone, toTop, withName);
|
||||||
} else if (mageObject instanceof Card) {
|
}
|
||||||
|
else if (mageObject instanceof Card) {
|
||||||
return this.moveCardToLibraryWithInfo((Card) mageObject, sourceId, game, fromZone, toTop, withName);
|
return this.moveCardToLibraryWithInfo((Card) mageObject, sourceId, game, fromZone, toTop, withName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -972,7 +980,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
boolean result;
|
boolean result;
|
||||||
if (card.getCardType().contains(CardType.LAND)) {
|
if (card.getCardType().contains(CardType.LAND)) {
|
||||||
result = playLand(card, game, ignoreTiming);
|
result = playLand(card, game, ignoreTiming);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
result = cast(card.getSpellAbility(), game, noMana);
|
result = cast(card.getSpellAbility(), game, noMana);
|
||||||
}
|
}
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
|
@ -1004,7 +1013,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
Costs<Cost> costs = getCastSourceIdCosts();
|
Costs<Cost> costs = getCastSourceIdCosts();
|
||||||
if (alternateCosts == null) {
|
if (alternateCosts == null) {
|
||||||
noMana = true;
|
noMana = true;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
spellAbility.getManaCosts().clear();
|
spellAbility.getManaCosts().clear();
|
||||||
spellAbility.getManaCostsToPay().clear();
|
spellAbility.getManaCostsToPay().clear();
|
||||||
spellAbility.getManaCosts().add(alternateCosts.copy());
|
spellAbility.getManaCosts().add(alternateCosts.copy());
|
||||||
|
@ -1098,7 +1108,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (storedBookmark == -1 || storedBookmark > bookmark) { // e.g. usefull for undo Nykthos, Shrine to Nyx
|
if (storedBookmark == -1 || storedBookmark > bookmark) { // e.g. usefull for undo Nykthos, Shrine to Nyx
|
||||||
setStoredBookmark(bookmark);
|
setStoredBookmark(bookmark);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
resetStoredBookmark(game);
|
resetStoredBookmark(game);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1127,7 +1138,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
restoreState(bookmark, ability.getRule(), game);
|
restoreState(bookmark, ability.getRule(), game);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
int bookmark = game.bookmarkState();
|
int bookmark = game.bookmarkState();
|
||||||
if (ability.activate(game, false)) {
|
if (ability.activate(game, false)) {
|
||||||
ability.resolve(game);
|
ability.resolve(game);
|
||||||
|
@ -1177,7 +1189,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (ability instanceof PlayLandAbility) {
|
if (ability instanceof PlayLandAbility) {
|
||||||
Card card = game.getCard(ability.getSourceId());
|
Card card = game.getCard(ability.getSourceId());
|
||||||
result = playLand(card, game, false);
|
result = playLand(card, game, false);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (!ability.canActivate(this.playerId, game)) {
|
if (!ability.canActivate(this.playerId, game)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1192,7 +1205,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
case SPELL:
|
case SPELL:
|
||||||
if (ability instanceof FlashbackAbility) {
|
if (ability instanceof FlashbackAbility) {
|
||||||
result = playAbility(ability.copy(), game);
|
result = playAbility(ability.copy(), game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
result = cast((SpellAbility) ability, game, false);
|
result = cast((SpellAbility) ability, game, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1238,7 +1252,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
if (!ability.isUsesStack()) {
|
if (!ability.isUsesStack()) {
|
||||||
ability.resolve(game);
|
ability.resolve(game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
game.fireEvent(new GameEvent(EventType.TRIGGERED_ABILITY, ability.getId(), ability.getSourceId(), ability.getControllerId()));
|
game.fireEvent(new GameEvent(EventType.TRIGGERED_ABILITY, ability.getId(), ability.getSourceId(), ability.getControllerId()));
|
||||||
}
|
}
|
||||||
game.removeBookmark(bookmark);
|
game.removeBookmark(bookmark);
|
||||||
|
@ -1259,7 +1274,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
useable.clear();
|
useable.clear();
|
||||||
useable.put(ability.getId(), (SpellAbility) ability);
|
useable.put(ability.getId(), (SpellAbility) ability);
|
||||||
return useable;
|
return useable;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// Fuse only allowed from hand
|
// Fuse only allowed from hand
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1288,10 +1304,12 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (((ActivatedAbility) ability).canActivate(playerId, game)) {
|
if (((ActivatedAbility) ability).canActivate(playerId, game)) {
|
||||||
useable.put(ability.getId(), (ActivatedAbility) ability);
|
useable.put(ability.getId(), (ActivatedAbility) ability);
|
||||||
}
|
}
|
||||||
} else if (canPlay(((ActivatedAbility) ability), availableMana, object, game)) {
|
}
|
||||||
|
else if (canPlay(((ActivatedAbility) ability), availableMana, object, game)) {
|
||||||
useable.put(ability.getId(), (ActivatedAbility) ability);
|
useable.put(ability.getId(), (ActivatedAbility) ability);
|
||||||
}
|
}
|
||||||
} else if (ability instanceof AlternativeSourceCosts) {
|
}
|
||||||
|
else if (ability instanceof AlternativeSourceCosts) {
|
||||||
if (object.getCardType().contains(CardType.LAND)) {
|
if (object.getCardType().contains(CardType.LAND)) {
|
||||||
for (Ability ability2 : object.getAbilities().copy()) {
|
for (Ability ability2 : object.getAbilities().copy()) {
|
||||||
if (ability2 instanceof PlayLandAbility) {
|
if (ability2 instanceof PlayLandAbility) {
|
||||||
|
@ -1349,7 +1367,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
// Left Half
|
// Left Half
|
||||||
if (card.getCardType().contains(CardType.INSTANT)) {
|
if (card.getCardType().contains(CardType.INSTANT)) {
|
||||||
flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.INSTANT);
|
flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.INSTANT);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.SORCERY);
|
flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.SORCERY);
|
||||||
}
|
}
|
||||||
flashbackAbility.setSourceId(card.getId());
|
flashbackAbility.setSourceId(card.getId());
|
||||||
|
@ -1362,7 +1381,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
// Right Half
|
// Right Half
|
||||||
if (card.getCardType().contains(CardType.INSTANT)) {
|
if (card.getCardType().contains(CardType.INSTANT)) {
|
||||||
flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.INSTANT);
|
flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.INSTANT);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.SORCERY);
|
flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.SORCERY);
|
||||||
}
|
}
|
||||||
flashbackAbility.setSourceId(card.getId());
|
flashbackAbility.setSourceId(card.getId());
|
||||||
|
@ -1373,7 +1393,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
useable.put(flashbackAbility.getId(), flashbackAbility);
|
useable.put(flashbackAbility.getId(), flashbackAbility);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
useable.put(ability.getId(), ability);
|
useable.put(ability.getId(), ability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1429,7 +1450,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
public void revealCards(String name, Cards cards, Game game, boolean postToLog) {
|
public void revealCards(String name, Cards cards, Game game, boolean postToLog) {
|
||||||
if (postToLog) {
|
if (postToLog) {
|
||||||
game.getState().getRevealed().add(name, cards);
|
game.getState().getRevealed().add(name, cards);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
game.getState().getRevealed().update(name, cards);
|
game.getState().getRevealed().update(name, cards);
|
||||||
}
|
}
|
||||||
if (postToLog && !game.isSimulation()) {
|
if (postToLog && !game.isSimulation()) {
|
||||||
|
@ -1561,7 +1583,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// player selected an permanent that is restricted by another effect, disallow it (so AI can select another one)
|
// player selected an permanent that is restricted by another effect, disallow it (so AI can select another one)
|
||||||
filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId())));
|
filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId())));
|
||||||
if (this.isHuman() && !game.isSimulation()) {
|
if (this.isHuman() && !game.isSimulation()) {
|
||||||
|
@ -1599,7 +1622,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
//20091005 - 502.2
|
//20091005 - 502.2
|
||||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {
|
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {
|
||||||
boolean untap = true;
|
boolean untap = true;
|
||||||
|
@ -1694,7 +1718,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
// rule 118.5
|
// rule 118.5
|
||||||
if (life > this.life) {
|
if (life > this.life) {
|
||||||
gainLife(life - this.life, game);
|
gainLife(life - this.life, game);
|
||||||
} else if (life < this.life) {
|
}
|
||||||
|
else if (life < this.life) {
|
||||||
loseLife(this.life - life, game);
|
loseLife(this.life - life, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1794,26 +1819,31 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
StackObject stackObject = game.getStack().getStackObject(sourceId);
|
StackObject stackObject = game.getStack().getStackObject(sourceId);
|
||||||
if (stackObject != null) {
|
if (stackObject != null) {
|
||||||
source = stackObject.getStackAbility().getSourceObject(game);
|
source = stackObject.getStackAbility().getSourceObject(game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
source = game.getObject(sourceId);
|
source = game.getObject(sourceId);
|
||||||
}
|
}
|
||||||
if (source instanceof Spell) {
|
if (source instanceof Spell) {
|
||||||
sourceAbilities = ((Spell) source).getAbilities(game);
|
sourceAbilities = ((Spell) source).getAbilities(game);
|
||||||
sourceControllerId = ((Spell) source).getControllerId();
|
sourceControllerId = ((Spell) source).getControllerId();
|
||||||
} else if (source instanceof Card) {
|
}
|
||||||
|
else if (source instanceof Card) {
|
||||||
sourceAbilities = ((Card) source).getAbilities(game);
|
sourceAbilities = ((Card) source).getAbilities(game);
|
||||||
sourceControllerId = ((Card) source).getOwnerId();
|
sourceControllerId = ((Card) source).getOwnerId();
|
||||||
} else if (source instanceof CommandObject) {
|
}
|
||||||
|
else if (source instanceof CommandObject) {
|
||||||
sourceControllerId = ((CommandObject) source).getControllerId();
|
sourceControllerId = ((CommandObject) source).getControllerId();
|
||||||
sourceAbilities = ((CommandObject) source).getAbilities();
|
sourceAbilities = ((CommandObject) source).getAbilities();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
sourceAbilities = ((Permanent) source).getAbilities(game);
|
sourceAbilities = ((Permanent) source).getAbilities(game);
|
||||||
sourceControllerId = ((Permanent) source).getControllerId();
|
sourceControllerId = ((Permanent) source).getControllerId();
|
||||||
}
|
}
|
||||||
if (sourceAbilities != null && sourceAbilities.containsKey(InfectAbility.getInstance().getId())) {
|
if (sourceAbilities != null && sourceAbilities.containsKey(InfectAbility.getInstance().getId())) {
|
||||||
addCounters(CounterType.POISON.createInstance(actualDamage), game);
|
addCounters(CounterType.POISON.createInstance(actualDamage), game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
GameEvent damageToLifeLossEvent = new GameEvent(EventType.DAMAGE_CAUSES_LIFE_LOSS, playerId, sourceId, playerId, actualDamage, combatDamage);
|
GameEvent damageToLifeLossEvent = new GameEvent(EventType.DAMAGE_CAUSES_LIFE_LOSS, playerId, sourceId, playerId, actualDamage, combatDamage);
|
||||||
if (!game.replaceEvent(damageToLifeLossEvent)) {
|
if (!game.replaceEvent(damageToLifeLossEvent)) {
|
||||||
this.loseLife(damageToLifeLossEvent.getAmount(), game);
|
this.loseLife(damageToLifeLossEvent.getAmount(), game);
|
||||||
|
@ -2130,7 +2160,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
this.loses = true;
|
this.loses = true;
|
||||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId));
|
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId));
|
||||||
game.informPlayers(this.getLogName() + " has lost the game.");
|
game.informPlayers(this.getLogName() + " has lost the game.");
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
logger.debug(this.getName() + " has already won - stop lost");
|
logger.debug(this.getName() + " has already won - stop lost");
|
||||||
}
|
}
|
||||||
// for draw - first all players that have lost have to be set to lost
|
// for draw - first all players that have lost have to be set to lost
|
||||||
|
@ -2185,7 +2216,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
this.wins = true;
|
this.wins = true;
|
||||||
game.end();
|
game.end();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
logger.debug("player won -> but already lost before: " + this.getName());
|
logger.debug("player won -> but already lost before: " + this.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2210,7 +2242,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
public boolean hasWon() {
|
public boolean hasWon() {
|
||||||
if (!this.loses) {
|
if (!this.loses) {
|
||||||
return this.wins;
|
return this.wins;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2238,7 +2271,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (blocker != null && group != null && group.canBlock(blocker, game)) {
|
if (blocker != null && group != null && group.canBlock(blocker, game)) {
|
||||||
group.addBlocker(blockerId, playerId, game);
|
group.addBlocker(blockerId, playerId, game);
|
||||||
game.getCombat().addBlockingGroup(blockerId, attackerId, playerId, game);
|
game.getCombat().addBlockingGroup(blockerId, attackerId, playerId, game);
|
||||||
} else if (this.isHuman() && !game.isSimulation()) {
|
}
|
||||||
|
else if (this.isHuman() && !game.isSimulation()) {
|
||||||
game.informPlayer(this, "You can't block this creature.");
|
game.informPlayer(this, "You can't block this creature.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2256,7 +2290,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (targetPlayerId.equals(playerId)) {
|
if (targetPlayerId.equals(playerId)) {
|
||||||
searchInfo = getLogName() + " searches his or her library";
|
searchInfo = getLogName() + " searches his or her library";
|
||||||
searchedLibrary = library;
|
searchedLibrary = library;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Player targetPlayer = game.getPlayer(targetPlayerId);
|
Player targetPlayer = game.getPlayer(targetPlayerId);
|
||||||
if (targetPlayer != null) {
|
if (targetPlayer != null) {
|
||||||
searchInfo = getLogName() + " searches the library of " + targetPlayer.getLogName();
|
searchInfo = getLogName() + " searches the library of " + targetPlayer.getLogName();
|
||||||
|
@ -2276,7 +2311,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
int librarySearchLimit = event.getAmount();
|
int librarySearchLimit = event.getAmount();
|
||||||
if (librarySearchLimit == Integer.MAX_VALUE) {
|
if (librarySearchLimit == Integer.MAX_VALUE) {
|
||||||
count = searchedLibrary.count(target.getFilter(), game);
|
count = searchedLibrary.count(target.getFilter(), game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
newTarget.setCardLimit(librarySearchLimit);
|
newTarget.setCardLimit(librarySearchLimit);
|
||||||
count = Math.min(searchedLibrary.count(target.getFilter(), game), librarySearchLimit);
|
count = Math.min(searchedLibrary.count(target.getFilter(), game), librarySearchLimit);
|
||||||
}
|
}
|
||||||
|
@ -2369,7 +2405,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (canAdd) {
|
if (canAdd) {
|
||||||
if (withCost) {
|
if (withCost) {
|
||||||
sourceWithCosts.add(manaAbilities);
|
sourceWithCosts.add(manaAbilities);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
sourceWithoutManaCosts.add(manaAbilities);
|
sourceWithoutManaCosts.add(manaAbilities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2473,7 +2510,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
ManaOptions abilityOptions = copy.getManaCostsToPay().getOptions();
|
ManaOptions abilityOptions = copy.getManaCostsToPay().getOptions();
|
||||||
if (abilityOptions.isEmpty()) {
|
if (abilityOptions.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (available == null) {
|
if (available == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2521,7 +2559,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
if (manaCosts.size() == 0) {
|
if (manaCosts.size() == 0) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (available == null) {
|
if (available == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2552,7 +2591,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
if (manaCosts.size() == 0) {
|
if (manaCosts.size() == 0) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
for (Mana mana : manaCosts.getOptions()) {
|
for (Mana mana : manaCosts.getOptions()) {
|
||||||
for (Mana avail : available) {
|
for (Mana avail : available) {
|
||||||
if (mana.enough(avail)) {
|
if (mana.enough(avail)) {
|
||||||
|
@ -2589,7 +2629,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
if (manaCosts.size() == 0) {
|
if (manaCosts.size() == 0) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
for (Mana mana : manaCosts.getOptions()) {
|
for (Mana mana : manaCosts.getOptions()) {
|
||||||
for (Mana avail : available) {
|
for (Mana avail : available) {
|
||||||
if (mana.enough(avail)) {
|
if (mana.enough(avail)) {
|
||||||
|
@ -2626,12 +2667,14 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
playable.add(ability);
|
playable.add(ability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ability instanceof AlternativeSourceCosts) {
|
}
|
||||||
|
else if (ability instanceof AlternativeSourceCosts) {
|
||||||
if (card.getCardType().contains(CardType.LAND)) {
|
if (card.getCardType().contains(CardType.LAND)) {
|
||||||
if (canLandPlayAlternateSourceCostsAbility(card, availableMana, ability, game)) { // e.g. Land with Morph
|
if (canLandPlayAlternateSourceCostsAbility(card, availableMana, ability, game)) { // e.g. Land with Morph
|
||||||
playable.add(ability);
|
playable.add(ability);
|
||||||
}
|
}
|
||||||
} else if (card.getCardType().contains(CardType.CREATURE)) { // e.g. makes a card available for play by Morph if the card may not be cast normally
|
}
|
||||||
|
else if (card.getCardType().contains(CardType.CREATURE)) { // e.g. makes a card available for play by Morph if the card may not be cast normally
|
||||||
if (!playable.contains(card.getSpellAbility())) {
|
if (!playable.contains(card.getSpellAbility())) {
|
||||||
if (((AlternativeSourceCosts) ability).isAvailable(card.getSpellAbility(), game)) {
|
if (((AlternativeSourceCosts) ability).isAvailable(card.getSpellAbility(), game)) {
|
||||||
playable.add(card.getSpellAbility());
|
playable.add(card.getSpellAbility());
|
||||||
|
@ -2649,7 +2692,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
boolean possible = false;
|
boolean possible = false;
|
||||||
if (ability.getZone().match(Zone.GRAVEYARD)) {
|
if (ability.getZone().match(Zone.GRAVEYARD)) {
|
||||||
possible = true;
|
possible = true;
|
||||||
} else if (ability.getZone().match(Zone.HAND) && (ability instanceof SpellAbility || ability instanceof PlayLandAbility)) {
|
}
|
||||||
|
else if (ability.getZone().match(Zone.HAND) && (ability instanceof SpellAbility || ability instanceof PlayLandAbility)) {
|
||||||
if (asThoughtCast || canPlayCardsFromGraveyard()) {
|
if (asThoughtCast || canPlayCardsFromGraveyard()) {
|
||||||
possible = true;
|
possible = true;
|
||||||
}
|
}
|
||||||
|
@ -2800,8 +2844,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skip "silent" phase step when players are not allowed to cast anything.
|
* Skip "silent" phase step when players are not allowed to cast anything. E.g. players can't play or cast anything during declaring attackers.
|
||||||
* E.g. players can't play or cast anything during declaring attackers.
|
|
||||||
*
|
*
|
||||||
* @param game
|
* @param game
|
||||||
* @return
|
* @return
|
||||||
|
@ -2833,14 +2876,17 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
if (ability.isModal()) {
|
if (ability.isModal()) {
|
||||||
addModeOptions(options, ability, game);
|
addModeOptions(options, ability, game);
|
||||||
} else if (ability.getTargets().getUnchosen().size() > 0) {
|
}
|
||||||
|
else if (ability.getTargets().getUnchosen().size() > 0) {
|
||||||
// TODO: Handle other variable costs than mana costs
|
// TODO: Handle other variable costs than mana costs
|
||||||
if (ability.getManaCosts().getVariableCosts().size() > 0) {
|
if (ability.getManaCosts().getVariableCosts().size() > 0) {
|
||||||
addVariableXOptions(options, ability, 0, game);
|
addVariableXOptions(options, ability, 0, game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
addTargetOptions(options, ability, 0, game);
|
addTargetOptions(options, ability, 0, game);
|
||||||
}
|
}
|
||||||
} else if (ability.getCosts().getTargets().getUnchosen().size() > 0) {
|
}
|
||||||
|
else if (ability.getCosts().getTargets().getUnchosen().size() > 0) {
|
||||||
addCostTargetOptions(options, ability, 0, game);
|
addCostTargetOptions(options, ability, 0, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2857,12 +2903,15 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (newOption.getTargets().getUnchosen().size() > 0) {
|
if (newOption.getTargets().getUnchosen().size() > 0) {
|
||||||
if (newOption.getManaCosts().getVariableCosts().size() > 0) {
|
if (newOption.getManaCosts().getVariableCosts().size() > 0) {
|
||||||
addVariableXOptions(options, newOption, 0, game);
|
addVariableXOptions(options, newOption, 0, game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
addTargetOptions(options, newOption, 0, game);
|
addTargetOptions(options, newOption, 0, game);
|
||||||
}
|
}
|
||||||
} else if (newOption.getCosts().getTargets().getUnchosen().size() > 0) {
|
}
|
||||||
|
else if (newOption.getCosts().getTargets().getUnchosen().size() > 0) {
|
||||||
addCostTargetOptions(options, newOption, 0, game);
|
addCostTargetOptions(options, newOption, 0, game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
options.add(newOption);
|
options.add(newOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2880,16 +2929,19 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
int amount = target.getTargetAmount(targetId);
|
int amount = target.getTargetAmount(targetId);
|
||||||
newOption.getTargets().get(targetNum).addTarget(targetId, amount, newOption, game, true);
|
newOption.getTargets().get(targetNum).addTarget(targetId, amount, newOption, game, true);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
for (UUID targetId : target.getTargets()) {
|
for (UUID targetId : target.getTargets()) {
|
||||||
newOption.getTargets().get(targetNum).addTarget(targetId, newOption, game, true);
|
newOption.getTargets().get(targetNum).addTarget(targetId, newOption, game, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (targetNum < option.getTargets().size() - 2) {
|
if (targetNum < option.getTargets().size() - 2) {
|
||||||
addTargetOptions(options, newOption, targetNum + 1, game);
|
addTargetOptions(options, newOption, targetNum + 1, game);
|
||||||
} else if (option.getCosts().getTargets().size() > 0) {
|
}
|
||||||
|
else if (option.getCosts().getTargets().size() > 0) {
|
||||||
addCostTargetOptions(options, newOption, 0, game);
|
addCostTargetOptions(options, newOption, 0, game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
options.add(newOption);
|
options.add(newOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2901,7 +2953,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
newOption.getCosts().getTargets().get(targetNum).addTarget(targetId, option, game, true);
|
newOption.getCosts().getTargets().get(targetNum).addTarget(targetId, option, game, true);
|
||||||
if (targetNum < option.getCosts().getTargets().size() - 1) {
|
if (targetNum < option.getCosts().getTargets().size() - 1) {
|
||||||
addCostTargetOptions(options, newOption, targetNum + 1, game);
|
addCostTargetOptions(options, newOption, targetNum + 1, game);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
options.add(newOption);
|
options.add(newOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3109,14 +3162,16 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
cardList.add(permanent);
|
cardList.add(permanent);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Card card = game.getCard(cardId);
|
Card card = game.getCard(cardId);
|
||||||
if (card == null) {
|
if (card == null) {
|
||||||
Spell spell = game.getState().getStack().getSpell(cardId);
|
Spell spell = game.getState().getStack().getSpell(cardId);
|
||||||
if (spell != null) {
|
if (spell != null) {
|
||||||
if (!spell.isCopy()) {
|
if (!spell.isCopy()) {
|
||||||
card = spell.getCard();
|
card = spell.getCard();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// If a spell is returned to its owner's hand, it's removed from the stack and thus will not resolve
|
// If a spell is returned to its owner's hand, it's removed from the stack and thus will not resolve
|
||||||
game.getStack().remove(spell);
|
game.getStack().remove(spell);
|
||||||
game.informPlayers(spell.getLogName() + " was removed from the stack");
|
game.informPlayers(spell.getLogName() + " was removed from the stack");
|
||||||
|
@ -3184,6 +3239,24 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
case BATTLEFIELD: // new logic that does not yet add the permanents to battlefield while replacement effects are handled
|
case BATTLEFIELD: // new logic that does not yet add the permanents to battlefield while replacement effects are handled
|
||||||
List<Permanent> permanents = new ArrayList<>();
|
List<Permanent> permanents = new ArrayList<>();
|
||||||
List<Permanent> permanentsEntered = new ArrayList<>();
|
List<Permanent> permanentsEntered = new ArrayList<>();
|
||||||
|
// Move meld pieces instead of the meld card if unmelded
|
||||||
|
Set<Card> meldPiecesToAdd = new HashSet<>(0);
|
||||||
|
Set<MeldCard> meldCardsRemoved = new HashSet<>(0);
|
||||||
|
for (Iterator<Card> it = cards.iterator(); it.hasNext();) {
|
||||||
|
Card card = it.next();
|
||||||
|
if (card instanceof MeldCard && !((MeldCard) card).isMelded()) {
|
||||||
|
MeldCard meldCard = (MeldCard) card;
|
||||||
|
if (meldCard.getTopLastZoneChangeCounter() == meldCard.getTopHalfCard().getZoneChangeCounter(game)) {
|
||||||
|
meldPiecesToAdd.add(meldCard.getTopHalfCard());
|
||||||
|
}
|
||||||
|
if (meldCard.getBottomLastZoneChangeCounter() == meldCard.getBottomHalfCard().getZoneChangeCounter(game)) {
|
||||||
|
meldPiecesToAdd.add(meldCard.getBottomHalfCard());
|
||||||
|
}
|
||||||
|
meldCardsRemoved.add(meldCard);
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cards.addAll(meldPiecesToAdd);
|
||||||
for (Card card : cards) {
|
for (Card card : cards) {
|
||||||
UUID controllingPlayerId = byOwner ? card.getOwnerId() : getId();
|
UUID controllingPlayerId = byOwner ? card.getOwnerId() : getId();
|
||||||
fromZone = game.getState().getZone(card.getId());
|
fromZone = game.getState().getZone(card.getId());
|
||||||
|
@ -3193,7 +3266,13 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
ZoneChangeEvent event = new ZoneChangeEvent(card.getId(), source.getSourceId(), controllingPlayerId, fromZone, Zone.BATTLEFIELD, appliedEffects, tapped);
|
ZoneChangeEvent event = new ZoneChangeEvent(card.getId(), source.getSourceId(), controllingPlayerId, fromZone, Zone.BATTLEFIELD, appliedEffects, tapped);
|
||||||
if (!game.replaceEvent(event)) {
|
if (!game.replaceEvent(event)) {
|
||||||
// get permanent
|
// get permanent
|
||||||
Permanent permanent = new PermanentCard(card, event.getPlayerId(), game);// controlling player can be replaced so use event player now
|
Permanent permanent;
|
||||||
|
if (card instanceof MeldCard) {
|
||||||
|
permanent = new PermanentMeld(card, event.getPlayerId(), game);// controlling player can be replaced so use event player now
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
permanent = new PermanentCard(card, event.getPlayerId(), game);// controlling player can be replaced so use event player now
|
||||||
|
}
|
||||||
permanents.add(permanent);
|
permanents.add(permanent);
|
||||||
game.getPermanentsEntering().put(permanent.getId(), permanent);
|
game.getPermanentsEntering().put(permanent.getId(), permanent);
|
||||||
card.checkForCountersToAdd(permanent, game);
|
card.checkForCountersToAdd(permanent, game);
|
||||||
|
@ -3211,7 +3290,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId());
|
game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId());
|
||||||
if (permanent.entersBattlefield(source.getSourceId(), game, fromZone, true)) {
|
if (permanent.entersBattlefield(source.getSourceId(), game, fromZone, true)) {
|
||||||
permanentsEntered.add(permanent);
|
permanentsEntered.add(permanent);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// revert controller to owner if permanent does not enter
|
// revert controller to owner if permanent does not enter
|
||||||
game.getContinuousEffects().setController(permanent.getId(), permanent.getOwnerId());
|
game.getContinuousEffects().setController(permanent.getId(), permanent.getOwnerId());
|
||||||
game.getPermanentsEntering().remove(permanent.getId());
|
game.getPermanentsEntering().remove(permanent.getId());
|
||||||
|
@ -3231,10 +3311,16 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
game.informPlayers(this.getLogName() + " puts " + (faceDown ? "a card face down " : permanent.getLogName())
|
game.informPlayers(this.getLogName() + " puts " + (faceDown ? "a card face down " : permanent.getLogName())
|
||||||
+ " from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " onto the Battlefield");
|
+ " from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " onto the Battlefield");
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
game.getPermanentsEntering().remove(permanent.getId());
|
game.getPermanentsEntering().remove(permanent.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Update the lastZoneChangeCounter of meld pieces that were moved
|
||||||
|
for (MeldCard meldCard : meldCardsRemoved) {
|
||||||
|
meldCard.setTopLastZoneChangeCounter(meldCard.getTopHalfCard().getZoneChangeCounter(game));
|
||||||
|
meldCard.setBottomLastZoneChangeCounter(meldCard.getBottomHalfCard().getZoneChangeCounter(game));
|
||||||
|
}
|
||||||
game.applyEffects();
|
game.applyEffects();
|
||||||
break;
|
break;
|
||||||
case HAND:
|
case HAND:
|
||||||
|
@ -3260,7 +3346,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
for (Card card : cards) {
|
for (Card card : cards) {
|
||||||
if (card instanceof Spell) {
|
if (card instanceof Spell) {
|
||||||
fromZone = game.getState().getZone(((Spell) card).getSourceId());
|
fromZone = game.getState().getZone(((Spell) card).getSourceId());
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
fromZone = game.getState().getZone(card.getId());
|
fromZone = game.getState().getZone(card.getId());
|
||||||
}
|
}
|
||||||
boolean hideCard = fromZone.equals(Zone.HAND) || fromZone.equals(Zone.LIBRARY);
|
boolean hideCard = fromZone.equals(Zone.HAND) || fromZone.equals(Zone.LIBRARY);
|
||||||
|
@ -3308,7 +3395,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
card = game.getPermanent(card.getId());
|
card = game.getPermanent(card.getId());
|
||||||
}
|
}
|
||||||
if (card.moveToZone(Zone.HAND, sourceId, game, false)) {
|
if (card.moveToZone(Zone.HAND, sourceId, game, false)) {
|
||||||
if (card instanceof PermanentCard) {
|
if (card instanceof PermanentCard && game.getCard(card.getId()) != null) {
|
||||||
card = game.getCard(card.getId());
|
card = game.getCard(card.getId());
|
||||||
}
|
}
|
||||||
if (!game.isSimulation()) {
|
if (!game.isSimulation()) {
|
||||||
|
@ -3378,7 +3465,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
movedCards.add(card);
|
movedCards.add(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
for (Card card : cards.getCards(game)) {
|
for (Card card : cards.getCards(game)) {
|
||||||
if (choosingPlayer.moveCardToGraveyardWithInfo(card, sourceId, game, fromZone)) {
|
if (choosingPlayer.moveCardToGraveyardWithInfo(card, sourceId, game, fromZone)) {
|
||||||
movedCards.add(card);
|
movedCards.add(card);
|
||||||
|
@ -3396,7 +3484,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
// Zone fromZone = game.getState().getZone(card.getId());
|
// Zone fromZone = game.getState().getZone(card.getId());
|
||||||
if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null ? fromZone.equals(Zone.BATTLEFIELD) : false)) {
|
if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null ? fromZone.equals(Zone.BATTLEFIELD) : false)) {
|
||||||
if (!game.isSimulation()) {
|
if (!game.isSimulation()) {
|
||||||
if (card instanceof PermanentCard) {
|
if (card instanceof PermanentCard && game.getCard(card.getId()) != null) {
|
||||||
card = game.getCard(card.getId());
|
card = game.getCard(card.getId());
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder(this.getLogName())
|
StringBuilder sb = new StringBuilder(this.getLogName())
|
||||||
|
@ -3404,7 +3492,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
.append(fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " " : "");
|
.append(fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " " : "");
|
||||||
if (card.getOwnerId().equals(getId())) {
|
if (card.getOwnerId().equals(getId())) {
|
||||||
sb.append("into his or her graveyard");
|
sb.append("into his or her graveyard");
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
sb.append("it into its owner's graveyard");
|
sb.append("it into its owner's graveyard");
|
||||||
}
|
}
|
||||||
game.informPlayers(sb.toString());
|
game.informPlayers(sb.toString());
|
||||||
|
@ -3419,7 +3508,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
if (card.moveToZone(Zone.LIBRARY, sourceId, game, toTop)) {
|
if (card.moveToZone(Zone.LIBRARY, sourceId, game, toTop)) {
|
||||||
if (!game.isSimulation()) {
|
if (!game.isSimulation()) {
|
||||||
if (card instanceof PermanentCard) {
|
if (card instanceof PermanentCard && game.getCard(card.getId()) != null) {
|
||||||
card = game.getCard(card.getId());
|
card = game.getCard(card.getId());
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder(this.getLogName())
|
StringBuilder sb = new StringBuilder(this.getLogName())
|
||||||
|
@ -3430,7 +3519,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
sb.append("to the ").append(toTop ? "top" : "bottom");
|
sb.append("to the ").append(toTop ? "top" : "bottom");
|
||||||
if (card.getOwnerId().equals(getId())) {
|
if (card.getOwnerId().equals(getId())) {
|
||||||
sb.append(" of his or her library");
|
sb.append(" of his or her library");
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Player player = game.getPlayer(card.getOwnerId());
|
Player player = game.getPlayer(card.getOwnerId());
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
sb.append(" of ").append(player.getLogName()).append("'s library");
|
sb.append(" of ").append(player.getLogName()).append("'s library");
|
||||||
|
@ -3453,8 +3543,6 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
Card basicCard = game.getCard(card.getId());
|
Card basicCard = game.getCard(card.getId());
|
||||||
if (basicCard != null) {
|
if (basicCard != null) {
|
||||||
card = basicCard;
|
card = basicCard;
|
||||||
} else {
|
|
||||||
logger.error("Couldn't get the card object for the PermanenCard named " + card.getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() : "a card face down") + " "
|
game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() : "a card face down") + " "
|
||||||
|
@ -3564,7 +3652,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
String text;
|
String text;
|
||||||
if (cards.size() == 1) {
|
if (cards.size() == 1) {
|
||||||
text = "card if you want to put it to the bottom of your library (Scry)";
|
text = "card if you want to put it to the bottom of your library (Scry)";
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
text = "cards you want to put on the bottom of your library (Scry)";
|
text = "cards you want to put on the bottom of your library (Scry)";
|
||||||
}
|
}
|
||||||
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard(text));
|
TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard(text));
|
||||||
|
|
Loading…
Reference in a new issue