mirror of
https://github.com/correl/mage.git
synced 2025-04-05 09:12:29 -09:00
* MorphAbility - Fixed copying a face-down creature (fixes #566). Morph cards are indicated as playable now if you have the needed mana to play it by Morph. Cast of Morph spell is now colorless (fixes #569).
This commit is contained in:
parent
f9afd91209
commit
5b5344a1a0
9 changed files with 340 additions and 49 deletions
Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords
Mage/src/mage
abilities
condition/common
costs
keyword
game
players
watchers/common
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* 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 org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author levelX2
|
||||
*/
|
||||
|
||||
public class MorphTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Tests if a creature with Morph is cast normal, it behaves as normal creature
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testCastMoprhCreatureWithoutMorph() {
|
||||
/*
|
||||
Pine Walker
|
||||
Creature - Elemental
|
||||
5/5
|
||||
Morph {4}{G} (You may cast this card face down as a 2/2 creature for . Turn it face up any time for its morph cost.)
|
||||
Whenever Pine Walker or another creature you control is turned face up, untap that creature.
|
||||
*/
|
||||
addCard(Zone.HAND, playerA, "Pine Walker");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker");
|
||||
setChoice(playerA, "No"); // cast it normal as 5/5
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Pine Walker", 1);
|
||||
assertPowerToughness(playerA, "Pine Walker", 5, 5);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cast the creature face down as a 2/2
|
||||
*/
|
||||
@Test
|
||||
public void testCastFaceDown() {
|
||||
addCard(Zone.HAND, playerA, "Pine Walker");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker");
|
||||
setChoice(playerA, "Yes"); // cast it face down as 2/2 creature
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "", 1);
|
||||
assertPowerToughness(playerA, "", 2, 2);
|
||||
|
||||
}
|
||||
/**
|
||||
* Test triggered turn face up ability of Pine Walker
|
||||
*/
|
||||
@Test
|
||||
public void testCopyFaceDwonMorphCreature() {
|
||||
addCard(Zone.HAND, playerA, "Pine Walker");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker");
|
||||
setChoice(playerA, "Yes"); // cast it face down as 2/2 creature
|
||||
|
||||
attack(3, playerA, "");
|
||||
|
||||
activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "{4}{G}: Turn this face-down permanent face up.");
|
||||
setStopAt(3, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 18);
|
||||
|
||||
assertPermanentCount(playerA, "", 0);
|
||||
assertPermanentCount(playerA, "Pine Walker", 1);
|
||||
assertPowerToughness(playerA, "Pine Walker", 5, 5);
|
||||
assertTapped("Pine Walker", false);
|
||||
|
||||
}
|
||||
/**
|
||||
* Test that Morph creature do not trigger abilities with their face up attributes
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testMorphedRemovesAttributesCreature() {
|
||||
// Ponyback Brigade {3}{R}{W}{B}
|
||||
// Creature - Goblin Warrior
|
||||
// 2/2
|
||||
// When Ponyback Brigade enters the battlefield or is turned face up, put three 1/1 red Goblin creature tokens onto the battlefield.
|
||||
// Morph {2}{R}{W}{B}(You may cast this card face down as a 2/2 creature for . Turn it face up any time for its morph cost.)
|
||||
addCard(Zone.HAND, playerA, "Ponyback Brigade");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Soldier of the Pantheon", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ponyback Brigade");
|
||||
setChoice(playerA, "Yes"); // cast it face down as 2/2 creature
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20); // and not 21
|
||||
|
||||
assertPermanentCount(playerA, "", 1);
|
||||
assertPermanentCount(playerB, "Soldier of the Pantheon", 1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to copy a morphed 2/2 creature
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testCopyAMorphedCreature() {
|
||||
addCard(Zone.HAND, playerA, "Pine Walker");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
|
||||
// Clever Impersonator {2}{U}{U}
|
||||
// Creature - Shapeshifter
|
||||
// 0/0
|
||||
// You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield.
|
||||
addCard(Zone.HAND, playerB, "Clever Impersonator", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 4);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker");
|
||||
setChoice(playerA, "Yes"); // cast it face down as 2/2 creature
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Clever Impersonator");
|
||||
setChoice(playerB, "Yes"); // use to copy a nonland permanent
|
||||
addTarget(playerB, ""); // Morphed creature
|
||||
|
||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20);
|
||||
|
||||
assertPermanentCount(playerA, "", 1);
|
||||
assertPowerToughness(playerA, "", 2,2);
|
||||
assertPermanentCount(playerB, "", 1);
|
||||
assertPowerToughness(playerB, "", 2,2);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.cards.Card;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class FaceDownSourceCondition implements Condition {
|
||||
|
||||
private final static FaceDownSourceCondition fInstance = new FaceDownSourceCondition();
|
||||
|
||||
public static Condition getInstance() {
|
||||
return fInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject mageObject = game.getObject(source.getSourceId());
|
||||
if (mageObject != null) {
|
||||
if (mageObject instanceof Permanent) {
|
||||
return ((Permanent)mageObject).isFaceDown();
|
||||
}
|
||||
if (mageObject instanceof Card) {
|
||||
return ((Card)mageObject).isFaceDown();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ public class TwoOrMoreSpellsWereCastLastTurnCondition implements Condition {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
// no one cast two or more spells this turn
|
||||
// no one cast two or more spells last turn
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,6 @@ public interface AlternativeSourceCosts {
|
|||
* @param game
|
||||
* @return
|
||||
*/
|
||||
String getCastMessageSuffix(Game game);
|
||||
|
||||
String getCastMessageSuffix(Game game);
|
||||
|
||||
}
|
|
@ -41,6 +41,7 @@ import mage.abilities.costs.AlternativeCost2Impl;
|
|||
import mage.abilities.costs.AlternativeSourceCosts;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
import mage.abilities.costs.CostsImpl;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.decorator.ConditionalTriggeredAbility;
|
||||
import mage.abilities.effects.common.SacrificeSourceEffect;
|
||||
|
@ -190,4 +191,11 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost
|
|||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Costs<Cost> getCosts() {
|
||||
Costs<Cost> alterCosts = new CostsImpl<>();
|
||||
alterCosts.addAll(evokeCosts);
|
||||
return alterCosts;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ package mage.abilities.keyword;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
|
@ -38,13 +37,13 @@ import mage.abilities.SpellAbility;
|
|||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.common.TurnFaceUpAbility;
|
||||
import mage.abilities.costs.AlternativeCost2;
|
||||
import mage.abilities.costs.AlternativeCost2Impl;
|
||||
import mage.abilities.costs.AlternativeSourceCosts;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
import mage.abilities.costs.CostsImpl;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
|
@ -54,6 +53,7 @@ import mage.constants.CardType;
|
|||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
@ -105,7 +105,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
|||
protected static final String ABILITY_KEYWORD = "Morph";
|
||||
protected static final String REMINDER_TEXT = "(You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)";
|
||||
protected String ruleText;
|
||||
protected List<AlternativeCost2> alternateCosts = new LinkedList<>();
|
||||
protected AlternativeCost2Impl alternateCosts = new AlternativeCost2Impl(ABILITY_KEYWORD, REMINDER_TEXT, new GenericManaCost(3));
|
||||
|
||||
// needed to check activation status, if card changes zone after casting it
|
||||
private int zoneChangeCounter = 0;
|
||||
|
@ -131,8 +131,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
|||
sb.append(REMINDER_TEXT);
|
||||
ruleText = sb.toString();
|
||||
|
||||
alternateCosts.add(new AlternativeCost2Impl(ABILITY_KEYWORD, REMINDER_TEXT, new GenericManaCost(3)));
|
||||
|
||||
// alternateCosts.add(new AlternativeCost2Impl(ABILITY_KEYWORD, REMINDER_TEXT, new GenericManaCost(3)));
|
||||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesFaceDownCreatureEffect(morphCosts));
|
||||
ability.setRuleVisible(false);
|
||||
card.addAbility(ability);
|
||||
|
@ -141,13 +140,13 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
|||
|
||||
public MorphAbility(final MorphAbility ability) {
|
||||
super(ability);
|
||||
this.alternateCosts.addAll(ability.alternateCosts);
|
||||
this.zoneChangeCounter = ability.zoneChangeCounter;
|
||||
this.ruleText = ability.ruleText;
|
||||
this.alternateCosts = ability.alternateCosts.copy();
|
||||
}
|
||||
|
||||
private static Costs createCosts(Cost cost) {
|
||||
Costs costs = new CostsImpl();
|
||||
private static Costs<Cost> createCosts(Cost cost) {
|
||||
Costs<Cost> costs = new CostsImpl<>();
|
||||
costs.add(cost);
|
||||
return costs;
|
||||
}
|
||||
|
@ -158,9 +157,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
|||
}
|
||||
|
||||
public void resetMorph() {
|
||||
for (AlternativeCost2 cost: alternateCosts) {
|
||||
cost.reset();
|
||||
}
|
||||
alternateCosts.reset();
|
||||
zoneChangeCounter = 0;
|
||||
}
|
||||
|
||||
|
@ -168,11 +165,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
|||
public boolean isActivated(Ability ability, Game game) {
|
||||
Card card = game.getCard(sourceId);
|
||||
if (card != null && card.getZoneChangeCounter() <= zoneChangeCounter +1) {
|
||||
for (AlternativeCost2 cost: alternateCosts) {
|
||||
if(cost.isActivated(game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return alternateCosts.isActivated(game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -190,20 +183,27 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
|||
if (player != null && spell != null) {
|
||||
this.resetMorph();
|
||||
spell.setFaceDown(true); // so only the back is visible
|
||||
for (AlternativeCost2 alternateCastingCost: alternateCosts) {
|
||||
if (alternateCastingCost.canPay(ability, sourceId, controllerId, game) &&
|
||||
player.chooseUse(Outcome.Benefit, new StringBuilder("Cast this card as a 2/2 face-down creature for ").append(alternateCastingCost.getText(true)).append(" ?").toString(), game)) {
|
||||
activateMorph(alternateCastingCost, game);
|
||||
if (alternateCosts.canPay(ability, sourceId, controllerId, game)) {
|
||||
if (player.chooseUse(Outcome.Benefit, new StringBuilder("Cast this card as a 2/2 face-down creature for ").append(getCosts().getText()).append(" ?").toString(), game)) {
|
||||
activateMorph(game);
|
||||
// change mana costs
|
||||
ability.getManaCostsToPay().clear();
|
||||
ability.getCosts().clear();
|
||||
for (Iterator it = ((Costs) alternateCastingCost).iterator(); it.hasNext();) {
|
||||
for (Iterator it = this.alternateCosts.iterator(); it.hasNext();) {
|
||||
Cost cost = (Cost) it.next();
|
||||
if (cost instanceof ManaCosts) {
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
if (cost instanceof ManaCost) {
|
||||
ability.getManaCostsToPay().add((ManaCost)cost.copy());
|
||||
} else {
|
||||
ability.getCosts().add(cost.copy());
|
||||
}
|
||||
}
|
||||
// change spell colors
|
||||
ObjectColor spellColor = spell.getColor();
|
||||
spellColor.setBlack(false);
|
||||
spellColor.setRed(false);
|
||||
spellColor.setGreen(false);
|
||||
spellColor.setWhite(false);
|
||||
spellColor.setBlue(false);
|
||||
} else {
|
||||
spell.setFaceDown(false);
|
||||
}
|
||||
|
@ -213,8 +213,8 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
|||
return isActivated(ability, game);
|
||||
}
|
||||
|
||||
private void activateMorph(AlternativeCost2 cost, Game game) {
|
||||
cost.activate();
|
||||
private void activateMorph(Game game) {
|
||||
alternateCosts.activate();
|
||||
// remember zone change counter
|
||||
if (zoneChangeCounter == 0) {
|
||||
Card card = game.getCard(getSourceId());
|
||||
|
@ -240,14 +240,31 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
|||
public String getCastMessageSuffix(Game game) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int position = 0;
|
||||
for (AlternativeCost2 cost : alternateCosts) {
|
||||
if (cost.isActivated(game)) {
|
||||
sb.append(cost.getCastSuffixMessage(position));
|
||||
++position;
|
||||
}
|
||||
}
|
||||
sb.append(alternateCosts.getCastSuffixMessage(position));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public Costs<Cost> getCosts() {
|
||||
return alternateCosts;
|
||||
}
|
||||
|
||||
public static void setPermanentToMorph(Permanent permanent) {
|
||||
permanent.getPower().initValue(2);
|
||||
permanent.getToughness().initValue(2);
|
||||
permanent.getAbilities().clear();
|
||||
permanent.getColor().setColor(new ObjectColor());
|
||||
permanent.setName("");
|
||||
permanent.getCardType().clear();
|
||||
permanent.getCardType().add(CardType.CREATURE);
|
||||
permanent.getSubtype().clear();
|
||||
permanent.getSupertype().clear();
|
||||
permanent.getManaCost().clear();
|
||||
permanent.setExpansionSetCode("KTK");
|
||||
permanent.setRarity(Rarity.NA);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -348,3 +365,4 @@ class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl implements Sour
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ import java.io.IOException;
|
|||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import mage.abilities.keyword.MorphAbility;
|
||||
|
||||
public abstract class GameImpl implements Game, Serializable {
|
||||
|
||||
|
@ -1237,6 +1238,9 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
|
||||
//getState().addCard(permanent);
|
||||
permanent.reset(this);
|
||||
if (copyFromPermanent.isMorphCard()) {
|
||||
MorphAbility.setPermanentToMorph(permanent);
|
||||
}
|
||||
permanent.assignNewId();
|
||||
if (copyFromPermanent.isTransformed()) {
|
||||
TransformAbility.transform(permanent, copyFromPermanent.getSecondCardFace(), this);
|
||||
|
|
|
@ -1907,7 +1907,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return result;
|
||||
}
|
||||
|
||||
protected boolean canPlay(ActivatedAbility ability, ManaOptions available, Game game) {
|
||||
protected boolean canPlay(ActivatedAbility ability, ManaOptions available, MageObject sourceObject, Game game) {
|
||||
if (!(ability instanceof ManaAbility)) {
|
||||
ActivatedAbility copy = ability.copy();
|
||||
copy.setCheckPlayableMode(); // prevents from endless loops for asking player to use effects by checking this mode
|
||||
|
@ -1956,6 +1956,20 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(sourceObject instanceof Permanent)) {
|
||||
for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) {
|
||||
// if cast for noMana no Alternative costs are allowed
|
||||
if (alternateSourceCostsAbility instanceof AlternativeSourceCosts) {
|
||||
if (((AlternativeSourceCosts)alternateSourceCostsAbility).isAvailable(ability, game)) {
|
||||
if (alternateSourceCostsAbility.getCosts().canPay(ability, playerId, playerId, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1971,14 +1985,19 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
if (hidden) {
|
||||
for (Card card : hand.getUniqueCards(game)) {
|
||||
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
|
||||
if (ability instanceof PlayLandAbility) {
|
||||
if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) {
|
||||
break;
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability instanceof ActivatedAbility) {
|
||||
if (ability instanceof PlayLandAbility) {
|
||||
if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canPlay((ActivatedAbility) ability, availableMana, card, game)) {
|
||||
playable.add(ability);
|
||||
}
|
||||
}
|
||||
if (canPlay(ability, availableMana, game)) {
|
||||
playable.add(ability);
|
||||
if (ability instanceof AlternativeSourceCosts) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1994,7 +2013,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
possible = true;
|
||||
}
|
||||
}
|
||||
if (possible && canPlay(ability, availableMana, game)) {
|
||||
if (possible && canPlay(ability, availableMana, card, game)) {
|
||||
playable.add(ability);
|
||||
}
|
||||
}
|
||||
|
@ -2036,7 +2055,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {
|
||||
for (ActivatedAbility ability : permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) {
|
||||
if (!playableActivated.containsKey(ability.toString())) {
|
||||
if (canPlay(ability, availableMana, game)) {
|
||||
if (canPlay(ability, availableMana, permanent, game)) {
|
||||
playableActivated.put(ability.toString(), ability);
|
||||
}
|
||||
}
|
||||
|
@ -2049,7 +2068,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
MageObject object = game.getObject(this.getCommanderId());
|
||||
if (object != null) {
|
||||
for (ActivatedAbility ability : ((Commander) object).getAbilities().getActivatedAbilities(Zone.COMMAND)) {
|
||||
if (canPlay(ability, availableMana, game)) {
|
||||
if (canPlay(ability, availableMana, object, game)) {
|
||||
playableActivated.put(ability.toString(), ability);
|
||||
}
|
||||
}
|
||||
|
@ -2082,13 +2101,13 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (canPlay(ability, available, game)) {
|
||||
if (canPlay(ability, available, card, game)) {
|
||||
playable.add(card.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
|
||||
if (!playable.contains(ability.getSourceId()) && canPlay(ability, available, game)) {
|
||||
if (!playable.contains(ability.getSourceId()) && canPlay(ability, available, card, game)) {
|
||||
playable.add(card.getId());
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -70,9 +70,9 @@ public class CastSpellLastTurnWatcher extends Watcher {
|
|||
if (playerId != null) {
|
||||
Integer amount = amountOfSpellsCastOnCurrentTurn.get(playerId);
|
||||
if (amount == null) {
|
||||
amount = Integer.valueOf(1);
|
||||
amount = 1;
|
||||
} else {
|
||||
amount = Integer.valueOf(amount+1);
|
||||
amount = amount+1;
|
||||
}
|
||||
amountOfSpellsCastOnCurrentTurn.put(playerId, amount);
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public class CastSpellLastTurnWatcher extends Watcher {
|
|||
public int getAmountOfSpellsPlayerCastOnCurrentTurn(UUID playerId) {
|
||||
Integer value = amountOfSpellsCastOnCurrentTurn.get(playerId);
|
||||
if (value != null) {
|
||||
return value.intValue();
|
||||
return value;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue