mirror of
https://github.com/correl/mage.git
synced 2025-04-13 09:11:06 -09:00
- Fixed #6919. Fixed other cards with the same issue.
This commit is contained in:
parent
2a7ac3fc9e
commit
c3de6bf8a0
8 changed files with 136 additions and 83 deletions
Mage.Sets/src/mage/cards/p
Mage/src/main/java/mage/abilities/keyword
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.cards.p;
|
package mage.cards.p;
|
||||||
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
|
@ -26,7 +25,8 @@ public final class PraetorsGrasp extends CardImpl {
|
||||||
public PraetorsGrasp(UUID ownerId, CardSetInfo setInfo) {
|
public PraetorsGrasp(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}");
|
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}");
|
||||||
|
|
||||||
// Search target opponent's library for a card and exile it face down. Then that player shuffles their library. You may look at and play that card for as long as it remains exiled.
|
// Search target opponent's library for a card and exile it face down. Then that player
|
||||||
|
//shuffles their library. You may look at and play that card for as long as it remains exiled.
|
||||||
this.getSpellAbility().addEffect(new PraetorsGraspEffect());
|
this.getSpellAbility().addEffect(new PraetorsGraspEffect());
|
||||||
this.getSpellAbility().addTarget(new TargetOpponent());
|
this.getSpellAbility().addTarget(new TargetOpponent());
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,9 @@ class PraetorsGraspEffect extends OneShotEffect {
|
||||||
|
|
||||||
public PraetorsGraspEffect() {
|
public PraetorsGraspEffect() {
|
||||||
super(Outcome.PlayForFree);
|
super(Outcome.PlayForFree);
|
||||||
staticText = "Search target opponent's library for a card and exile it face down. Then that player shuffles their library. You may look at and play that card for as long as it remains exiled";
|
staticText = "Search target opponent's library for a card and exile it "
|
||||||
|
+ "face down. Then that player shuffles their library. You may "
|
||||||
|
+ "look at and play that card for as long as it remains exiled";
|
||||||
}
|
}
|
||||||
|
|
||||||
public PraetorsGraspEffect(final PraetorsGraspEffect effect) {
|
public PraetorsGraspEffect(final PraetorsGraspEffect effect) {
|
||||||
|
@ -62,15 +64,21 @@ class PraetorsGraspEffect extends OneShotEffect {
|
||||||
Player opponent = game.getPlayer(source.getFirstTarget());
|
Player opponent = game.getPlayer(source.getFirstTarget());
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
MageObject sourceObject = source.getSourceObject(game);
|
MageObject sourceObject = source.getSourceObject(game);
|
||||||
if (controller != null && opponent != null && sourceObject != null) {
|
if (controller != null
|
||||||
|
&& opponent != null
|
||||||
|
&& sourceObject != null) {
|
||||||
TargetCardInLibrary target = new TargetCardInLibrary();
|
TargetCardInLibrary target = new TargetCardInLibrary();
|
||||||
if (controller.searchLibrary(target, source, game, opponent.getId())) {
|
if (controller.searchLibrary(target, source, game, opponent.getId())) {
|
||||||
UUID targetId = target.getFirstTarget();
|
UUID targetId = target.getFirstTarget();
|
||||||
Card card = opponent.getLibrary().getCard(targetId, game);
|
Card card = opponent.getLibrary().getCard(targetId, game);
|
||||||
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(),
|
||||||
if (card != null && exileId != null) {
|
source.getSourceObjectZoneChangeCounter());
|
||||||
game.informPlayers(controller.getLogName() + " moves the searched card face down to exile");
|
if (card != null
|
||||||
card.moveToExile(exileId, sourceObject.getIdName(), source.getSourceId(), game);
|
&& exileId != null) {
|
||||||
|
game.informPlayers(controller.getLogName() + " moves the searched "
|
||||||
|
+ "card face down to exile");
|
||||||
|
card.moveToExile(exileId, sourceObject.getIdName(),
|
||||||
|
source.getSourceId(), game);
|
||||||
card.setFaceDown(true, game);
|
card.setFaceDown(true, game);
|
||||||
game.addEffect(new PraetorsGraspPlayEffect(card.getId()), source);
|
game.addEffect(new PraetorsGraspPlayEffect(card.getId()), source);
|
||||||
game.addEffect(new PraetorsGraspRevealEffect(card.getId()), source);
|
game.addEffect(new PraetorsGraspRevealEffect(card.getId()), source);
|
||||||
|
@ -110,12 +118,16 @@ class PraetorsGraspPlayEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||||
if (objectId.equals(cardId) && affectedControllerId.equals(source.getControllerId())) {
|
if (objectId.equals(cardId)
|
||||||
|
&& affectedControllerId.equals(source.getControllerId())) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(),
|
||||||
if (exileId != null && controller != null) {
|
source.getSourceObjectZoneChangeCounter());
|
||||||
|
if (exileId != null
|
||||||
|
&& controller != null) {
|
||||||
ExileZone exileZone = game.getExile().getExileZone(exileId);
|
ExileZone exileZone = game.getExile().getExileZone(exileId);
|
||||||
if (exileZone != null && exileZone.contains(cardId)) {
|
if (exileZone != null
|
||||||
|
&& exileZone.contains(cardId)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,15 +164,21 @@ class PraetorsGraspRevealEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||||
if (objectId.equals(cardId) && affectedControllerId.equals(source.getControllerId())) {
|
if (objectId.equals(cardId)
|
||||||
|
&& affectedControllerId.equals(source.getControllerId())) {
|
||||||
MageObject sourceObject = source.getSourceObject(game);
|
MageObject sourceObject = source.getSourceObject(game);
|
||||||
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
|
UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(),
|
||||||
if (exileId != null && sourceObject != null) {
|
source.getSourceObjectZoneChangeCounter());
|
||||||
|
if (exileId != null
|
||||||
|
&& sourceObject != null) {
|
||||||
ExileZone exileZone = game.getExile().getExileZone(exileId);
|
ExileZone exileZone = game.getExile().getExileZone(exileId);
|
||||||
if (exileZone != null && exileZone.contains(cardId)) {
|
if (exileZone != null
|
||||||
|
&& exileZone.contains(cardId)) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Card card = game.getCard(cardId);
|
Card card = game.getCard(cardId);
|
||||||
if (controller != null && card != null && game.getState().getZone(cardId) == Zone.EXILED) {
|
if (controller != null
|
||||||
|
&& card != null
|
||||||
|
&& game.getState().getZone(cardId) == Zone.EXILED) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.abilities.keyword;
|
package mage.abilities.keyword;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
@ -83,7 +82,7 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM
|
||||||
if (!(ability instanceof SpellAbility)) {
|
if (!(ability instanceof SpellAbility)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Player player = game.getPlayer(controllerId);
|
Player player = game.getPlayer(ability.getControllerId());
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +104,7 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM
|
||||||
@Override
|
@Override
|
||||||
public void addOptionalAdditionalModeCosts(Ability ability, Game game) {
|
public void addOptionalAdditionalModeCosts(Ability ability, Game game) {
|
||||||
if (additionalCost.isActivated()) {
|
if (additionalCost.isActivated()) {
|
||||||
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext(); ) {
|
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) {
|
||||||
Cost cost = (Cost) it.next();
|
Cost cost = (Cost) it.next();
|
||||||
if (cost instanceof ManaCostsImpl) {
|
if (cost instanceof ManaCostsImpl) {
|
||||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||||
|
|
|
@ -50,8 +50,10 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
public class KickerAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
|
public class KickerAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
|
||||||
|
|
||||||
protected static final String KICKER_KEYWORD = "Kicker";
|
protected static final String KICKER_KEYWORD = "Kicker";
|
||||||
protected static final String KICKER_REMINDER_MANA = "You may pay an additional {cost} as you cast this spell.";
|
protected static final String KICKER_REMINDER_MANA = "You may pay an additional "
|
||||||
protected static final String KICKER_REMINDER_COST = "You may {cost} in addition to any other costs as you cast this spell.";
|
+ "{cost} as you cast this spell.";
|
||||||
|
protected static final String KICKER_REMINDER_COST = "You may {cost} in addition "
|
||||||
|
+ "to any other costs as you cast this spell.";
|
||||||
|
|
||||||
protected Map<String, Integer> activations = new ConcurrentHashMap<>(); // zoneChangeCounter, activations
|
protected Map<String, Integer> activations = new ConcurrentHashMap<>(); // zoneChangeCounter, activations
|
||||||
|
|
||||||
|
@ -93,13 +95,15 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
||||||
}
|
}
|
||||||
|
|
||||||
public final OptionalAdditionalCost addKickerCost(String manaString) {
|
public final OptionalAdditionalCost addKickerCost(String manaString) {
|
||||||
OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new ManaCostsImpl(manaString));
|
OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(
|
||||||
|
keywordText, reminderText, new ManaCostsImpl(manaString));
|
||||||
kickerCosts.add(kickerCost);
|
kickerCosts.add(kickerCost);
|
||||||
return kickerCost;
|
return kickerCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final OptionalAdditionalCost addKickerCost(Cost cost) {
|
public final OptionalAdditionalCost addKickerCost(Cost cost) {
|
||||||
OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, cost);
|
OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(
|
||||||
|
keywordText, "-", reminderText, cost);
|
||||||
kickerCosts.add(kickerCost);
|
kickerCosts.add(kickerCost);
|
||||||
return kickerCost;
|
return kickerCost;
|
||||||
}
|
}
|
||||||
|
@ -109,9 +113,10 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
||||||
cost.reset();
|
cost.reset();
|
||||||
}
|
}
|
||||||
String key = getActivationKey(source, "", game);
|
String key = getActivationKey(source, "", game);
|
||||||
for (Iterator<String> iterator = activations.keySet().iterator(); iterator.hasNext(); ) {
|
for (Iterator<String> iterator = activations.keySet().iterator(); iterator.hasNext();) {
|
||||||
String activationKey = iterator.next();
|
String activationKey = iterator.next();
|
||||||
if (activationKey.startsWith(key) && activations.get(activationKey) > 0) {
|
if (activationKey.startsWith(key)
|
||||||
|
&& activations.get(activationKey) > 0) {
|
||||||
activations.put(key, 0);
|
activations.put(key, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +131,8 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
||||||
String key = getActivationKey(source, costText, game);
|
String key = getActivationKey(source, costText, game);
|
||||||
if (kickerCosts.size() > 1) {
|
if (kickerCosts.size() > 1) {
|
||||||
for (String activationKey : activations.keySet()) {
|
for (String activationKey : activations.keySet()) {
|
||||||
if (activationKey.startsWith(key) && activations.get(activationKey) > 0) {
|
if (activationKey.startsWith(key)
|
||||||
|
&& activations.get(activationKey) > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +156,8 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
||||||
amount += activations.get(key);
|
amount += activations.get(key);
|
||||||
}
|
}
|
||||||
activations.put(key, amount);
|
activations.put(key, amount);
|
||||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.KICKED, source.getSourceId(), source.getSourceId(), source.getControllerId()));
|
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.KICKED,
|
||||||
|
source.getSourceId(), source.getSourceId(), source.getControllerId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getActivationKey(Ability source, String costText, Game game) {
|
private String getActivationKey(Ability source, String costText, Game game) {
|
||||||
|
@ -170,7 +177,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
||||||
@Override
|
@Override
|
||||||
public void addOptionalAdditionalCosts(Ability ability, Game game) {
|
public void addOptionalAdditionalCosts(Ability ability, Game game) {
|
||||||
if (ability instanceof SpellAbility) {
|
if (ability instanceof SpellAbility) {
|
||||||
Player player = game.getPlayer(controllerId);
|
Player player = game.getPlayer(ability.getControllerId());
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
this.resetKicker(game, ability);
|
this.resetKicker(game, ability);
|
||||||
for (OptionalAdditionalCost kickerCost : kickerCosts) {
|
for (OptionalAdditionalCost kickerCost : kickerCosts) {
|
||||||
|
@ -183,14 +190,17 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
||||||
}
|
}
|
||||||
// TODO: add AI support to find max number of possible activations (from available mana)
|
// TODO: add AI support to find max number of possible activations (from available mana)
|
||||||
// canPay checks only single mana available, not total mana usage
|
// canPay checks only single mana available, not total mana usage
|
||||||
if (kickerCost.canPay(ability, sourceId, controllerId, game)
|
if (kickerCost.canPay(ability, sourceId, ability.getControllerId(), game)
|
||||||
&& player.chooseUse(/*Outcome.Benefit*/Outcome.AIDontUseIt, "Pay " + times + kickerCost.getText(false) + " ?", ability, game)) {
|
&& player.chooseUse(/*Outcome.Benefit*/Outcome.AIDontUseIt,
|
||||||
|
"Pay " + times + kickerCost.getText(false) + " ?", ability, game)) {
|
||||||
this.activateKicker(kickerCost, ability, game);
|
this.activateKicker(kickerCost, ability, game);
|
||||||
if (kickerCost instanceof Costs) {
|
if (kickerCost instanceof Costs) {
|
||||||
for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext(); ) {
|
for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext();) {
|
||||||
Object kickerCostObject = itKickerCost.next();
|
Object kickerCostObject = itKickerCost.next();
|
||||||
if ((kickerCostObject instanceof Costs) || (kickerCostObject instanceof CostsImpl)) {
|
if ((kickerCostObject instanceof Costs)
|
||||||
for (@SuppressWarnings("unchecked") Iterator<Cost> itDetails = ((Costs) kickerCostObject).iterator(); itDetails.hasNext(); ) {
|
|| (kickerCostObject instanceof CostsImpl)) {
|
||||||
|
for (@SuppressWarnings("unchecked") Iterator<Cost> itDetails
|
||||||
|
= ((Costs) kickerCostObject).iterator(); itDetails.hasNext();) {
|
||||||
addKickerCostsToAbility(itDetails.next(), ability, game);
|
addKickerCostsToAbility(itDetails.next(), ability, game);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.abilities.keyword;
|
package mage.abilities.keyword;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -43,7 +42,7 @@ import mage.players.Player;
|
||||||
* mana cost. Any effects or prohibitions that would apply to casting a card
|
* mana cost. Any effects or prohibitions that would apply to casting a card
|
||||||
* with these characteristics (and not the face-up cards characteristics) are
|
* with these characteristics (and not the face-up cards characteristics) are
|
||||||
* applied to casting this card. These values are the copiable values of that
|
* applied to casting this card. These values are the copiable values of that
|
||||||
* objects characteristics. (See rule 613, "Interaction of Continuous Effects,"
|
* object's characteristics. (See rule 613, "Interaction of Continuous Effects,"
|
||||||
* and rule 706, "Copying Objects.") Put it onto the stack (as a face-down spell
|
* and rule 706, "Copying Objects.") Put it onto the stack (as a face-down spell
|
||||||
* with the same characteristics), and pay {3} rather than pay its mana cost.
|
* with the same characteristics), and pay {3} rather than pay its mana cost.
|
||||||
* This follows the rules for paying alternative costs. You can use morph to
|
* This follows the rules for paying alternative costs. You can use morph to
|
||||||
|
@ -52,13 +51,13 @@ import mage.players.Player;
|
||||||
* spell had. The morph effect applies to the face-down object wherever it is,
|
* spell had. The morph effect applies to the face-down object wherever it is,
|
||||||
* and it ends when the permanent is turned face up. #
|
* and it ends when the permanent is turned face up. #
|
||||||
*
|
*
|
||||||
* 702.36c You cant cast a card face down if it doesnt have morph.
|
* 702.36c You can't cast a card face down if it doesn't have morph.
|
||||||
*
|
*
|
||||||
* 702.36d If you have priority, you may turn a face-down permanent you control
|
* 702.36d If you have priority, you may turn a face-down permanent you control
|
||||||
* face up. This is a special action; it doesnt use the stack (see rule 115).
|
* face up. This is a special action; it doesn't use the stack (see rule 115).
|
||||||
* To do this, show all players what the permanents morph cost would be if it
|
* To do this, show all players what the permanents morph cost would be if it
|
||||||
* were face up, pay that cost, then turn the permanent face up. (If the
|
* were face up, pay that cost, then turn the permanent face up. (If the
|
||||||
* permanent wouldnt have a morph cost if it were face up, it cant be turned
|
* permanent wouldn't have a morph cost if it were face up, it cant be turned
|
||||||
* face up this way.) The morph effect on it ends, and it regains its normal
|
* face up this way.) The morph effect on it ends, and it regains its normal
|
||||||
* characteristics. Any abilities relating to the permanent entering the
|
* characteristics. Any abilities relating to the permanent entering the
|
||||||
* battlefield dont trigger when its turned face up and dont have any effect,
|
* battlefield dont trigger when its turned face up and dont have any effect,
|
||||||
|
@ -73,10 +72,14 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
||||||
|
|
||||||
protected static final String ABILITY_KEYWORD = "Morph";
|
protected static final String ABILITY_KEYWORD = "Morph";
|
||||||
protected static final String ABILITY_KEYWORD_MEGA = "Megamorph";
|
protected static final String ABILITY_KEYWORD_MEGA = "Megamorph";
|
||||||
protected static final String REMINDER_TEXT = "<i>(You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)</i>";
|
protected static final String REMINDER_TEXT = "<i>(You may cast this card face down as a "
|
||||||
protected static final String REMINDER_TEXT_MEGA = "<i>(You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its megamorph cost and put a +1/+1 counter on it.)</i>";
|
+ "2/2 creature for {3}. Turn it face up any time for its morph cost.)</i>";
|
||||||
|
protected static final String REMINDER_TEXT_MEGA = "<i>(You may cast this card face down "
|
||||||
|
+ "as a 2/2 creature for {3}. Turn it face up any time for its megamorph "
|
||||||
|
+ "cost and put a +1/+1 counter on it.)</i>";
|
||||||
protected String ruleText;
|
protected String ruleText;
|
||||||
protected AlternativeCost2Impl alternateCosts = new AlternativeCost2Impl(ABILITY_KEYWORD, REMINDER_TEXT, new GenericManaCost(3));
|
protected AlternativeCost2Impl alternateCosts = new AlternativeCost2Impl(
|
||||||
|
ABILITY_KEYWORD, REMINDER_TEXT, new GenericManaCost(3));
|
||||||
protected Costs<Cost> morphCosts;
|
protected Costs<Cost> morphCosts;
|
||||||
// needed to check activation status, if card changes zone after casting it
|
// needed to check activation status, if card changes zone after casting it
|
||||||
private int zoneChangeCounter = 0;
|
private int zoneChangeCounter = 0;
|
||||||
|
@ -166,7 +169,8 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
||||||
@Override
|
@Override
|
||||||
public boolean isActivated(Ability ability, Game game) {
|
public boolean isActivated(Ability ability, Game game) {
|
||||||
Card card = game.getCard(sourceId);
|
Card card = game.getCard(sourceId);
|
||||||
if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter + 1) {
|
if (card != null
|
||||||
|
&& card.getZoneChangeCounter(game) <= zoneChangeCounter + 1) {
|
||||||
return alternateCosts.isActivated(game);
|
return alternateCosts.isActivated(game);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -180,14 +184,17 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
||||||
@Override
|
@Override
|
||||||
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
|
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
|
||||||
if (ability.getAbilityType() == AbilityType.SPELL) {
|
if (ability.getAbilityType() == AbilityType.SPELL) {
|
||||||
Player player = game.getPlayer(controllerId);
|
Player player = game.getPlayer(ability.getControllerId());
|
||||||
Spell spell = game.getStack().getSpell(ability.getId());
|
Spell spell = game.getStack().getSpell(ability.getId());
|
||||||
if (player != null && spell != null) {
|
if (player != null
|
||||||
|
&& spell != null) {
|
||||||
this.resetMorph();
|
this.resetMorph();
|
||||||
spell.setFaceDown(true, game); // so only the back is visible
|
spell.setFaceDown(true, game); // so only the back is visible
|
||||||
if (alternateCosts.canPay(ability, sourceId, controllerId, game)) {
|
if (alternateCosts.canPay(ability, sourceId, ability.getControllerId(), game)) {
|
||||||
if (player.chooseUse(Outcome.Benefit, "Cast this card as a 2/2 face-down creature for " + getCosts().getText() + " ?", ability, game)) {
|
if (player.chooseUse(Outcome.Benefit, "Cast this card as a 2/2 "
|
||||||
game.getState().setValue("MorphAbility" + ability.getSourceId(), "activated"); // Gift of Doom
|
+ "face-down creature for " + getCosts().getText() + " ?", ability, game)) {
|
||||||
|
game.getState().setValue("MorphAbility"
|
||||||
|
+ ability.getSourceId(), "activated"); // Gift of Doom
|
||||||
activateMorph(game);
|
activateMorph(game);
|
||||||
// change mana costs
|
// change mana costs
|
||||||
ability.getManaCostsToPay().clear();
|
ability.getManaCostsToPay().clear();
|
||||||
|
@ -215,11 +222,12 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ability.getAbilityType() == AbilityType.PLAY_LAND) {
|
if (ability.getAbilityType() == AbilityType.PLAY_LAND) {
|
||||||
Player player = game.getPlayer(controllerId);
|
Player player = game.getPlayer(ability.getControllerId());
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
this.resetMorph();
|
this.resetMorph();
|
||||||
if (alternateCosts.canPay(ability, sourceId, controllerId, game)) {
|
if (alternateCosts.canPay(ability, sourceId, ability.getControllerId(), game)) {
|
||||||
if (player.chooseUse(Outcome.Benefit, "Cast this card as a 2/2 face-down creature for " + getCosts().getText() + " ?", ability, game)) {
|
if (player.chooseUse(Outcome.Benefit, "Cast this card as a 2/2 "
|
||||||
|
+ "face-down creature for " + getCosts().getText() + " ?", ability, game)) {
|
||||||
activateMorph(game);
|
activateMorph(game);
|
||||||
// change mana costs
|
// change mana costs
|
||||||
ability.getManaCostsToPay().clear();
|
ability.getManaCostsToPay().clear();
|
||||||
|
|
|
@ -43,7 +43,8 @@ import mage.target.common.TargetControlledPermanent;
|
||||||
public class NinjutsuAbility extends ActivatedAbilityImpl {
|
public class NinjutsuAbility extends ActivatedAbilityImpl {
|
||||||
|
|
||||||
private final boolean commander;
|
private final boolean commander;
|
||||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("unblocked attacker you control");
|
private static final FilterControlledCreaturePermanent filter =
|
||||||
|
new FilterControlledCreaturePermanent("unblocked attacker you control");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(UnblockedPredicate.instance);
|
filter.add(UnblockedPredicate.instance);
|
||||||
|
@ -149,7 +150,8 @@ class ReturnAttackerToHandTargetCost extends CostImpl {
|
||||||
for (UUID targetId : targets.get(0).getTargets()) {
|
for (UUID targetId : targets.get(0).getTargets()) {
|
||||||
Permanent permanent = game.getPermanent(targetId);
|
Permanent permanent = game.getPermanent(targetId);
|
||||||
Player controller = game.getPlayer(controllerId);
|
Player controller = game.getPlayer(controllerId);
|
||||||
if (permanent == null || controller == null) {
|
if (permanent == null
|
||||||
|
|| controller == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
defendingPlayerId = game.getCombat().getDefenderId(permanent.getId());
|
defendingPlayerId = game.getCombat().getDefenderId(permanent.getId());
|
||||||
|
|
|
@ -58,7 +58,8 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
|
||||||
}
|
}
|
||||||
|
|
||||||
public final AlternativeCost2 addProwlCost(String manaString) {
|
public final AlternativeCost2 addProwlCost(String manaString) {
|
||||||
AlternativeCost2 prowlCost = new AlternativeCost2Impl(PROWL_KEYWORD, reminderText, new ManaCostsImpl(manaString));
|
AlternativeCost2 prowlCost = new AlternativeCost2Impl(PROWL_KEYWORD,
|
||||||
|
reminderText, new ManaCostsImpl(manaString));
|
||||||
prowlCosts.add(prowlCost);
|
prowlCosts.add(prowlCost);
|
||||||
return prowlCost;
|
return prowlCost;
|
||||||
}
|
}
|
||||||
|
@ -87,19 +88,21 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
|
||||||
@Override
|
@Override
|
||||||
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
|
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
|
||||||
if (ability instanceof SpellAbility) {
|
if (ability instanceof SpellAbility) {
|
||||||
Player player = game.getPlayer(controllerId);
|
Player player = game.getPlayer(ability.getControllerId());
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ProwlCondition.instance.apply(game, ability)) {
|
if (ProwlCondition.instance.apply(game, ability)) {
|
||||||
this.resetProwl();
|
this.resetProwl();
|
||||||
for (AlternativeCost2 prowlCost : prowlCosts) {
|
for (AlternativeCost2 prowlCost : prowlCosts) {
|
||||||
if (prowlCost.canPay(ability, sourceId, controllerId, game)
|
if (prowlCost.canPay(ability, sourceId, ability.getControllerId(), game)
|
||||||
&& player.chooseUse(Outcome.Benefit, "Cast for " + PROWL_KEYWORD + " cost " + prowlCost.getText(true) + " ?", ability, game)) {
|
&& player.chooseUse(Outcome.Benefit, "Cast for "
|
||||||
|
+ PROWL_KEYWORD + " cost " + prowlCost.getText(true)
|
||||||
|
+ " ?", ability, game)) {
|
||||||
prowlCost.activate();
|
prowlCost.activate();
|
||||||
ability.getManaCostsToPay().clear();
|
ability.getManaCostsToPay().clear();
|
||||||
ability.getCosts().clear();
|
ability.getCosts().clear();
|
||||||
for (Iterator it = ((Costs) prowlCost).iterator(); it.hasNext(); ) {
|
for (Iterator it = ((Costs) prowlCost).iterator(); it.hasNext();) {
|
||||||
Cost cost = (Cost) it.next();
|
Cost cost = (Cost) it.next();
|
||||||
if (cost instanceof ManaCostsImpl) {
|
if (cost instanceof ManaCostsImpl) {
|
||||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||||
|
@ -149,8 +152,9 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setReminderText(Card card) {
|
private void setReminderText(Card card) {
|
||||||
reminderText =
|
reminderText
|
||||||
"(You may cast this for its prowl cost if you dealt combat damage to a player this turn with a creature that shared a creature type with {this}";
|
= "(You may cast this for its prowl cost if you dealt combat damage to a "
|
||||||
|
+ "player this turn with a creature that shared a creature type with {this}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -161,4 +165,4 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
|
||||||
}
|
}
|
||||||
return alterCosts;
|
return alterCosts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,15 @@ import java.util.Iterator;
|
||||||
public class ReplicateAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
|
public class ReplicateAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
|
||||||
|
|
||||||
private static final String keywordText = "Replicate";
|
private static final String keywordText = "Replicate";
|
||||||
private static final String reminderTextMana = "When you cast this spell, copy it for each time you paid its replicate cost. You may choose new targets for the copies.";
|
private static final String reminderTextMana = "When you cast this spell, "
|
||||||
|
+ "copy it for each time you paid its replicate cost."
|
||||||
|
+ " You may choose new targets for the copies.";
|
||||||
protected OptionalAdditionalCost additionalCost;
|
protected OptionalAdditionalCost additionalCost;
|
||||||
|
|
||||||
public ReplicateAbility(Card card, String manaString) {
|
public ReplicateAbility(Card card, String manaString) {
|
||||||
super(Zone.STACK, null);
|
super(Zone.STACK, null);
|
||||||
this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderTextMana, new ManaCostsImpl(manaString));
|
this.additionalCost = new OptionalAdditionalCostImpl(keywordText,
|
||||||
|
reminderTextMana, new ManaCostsImpl(manaString));
|
||||||
this.additionalCost.setRepeatable(true);
|
this.additionalCost.setRepeatable(true);
|
||||||
setRuleAtTheTop(true);
|
setRuleAtTheTop(true);
|
||||||
addSubAbility(new ReplicateTriggeredAbility());
|
addSubAbility(new ReplicateTriggeredAbility());
|
||||||
|
@ -77,12 +80,12 @@ public class ReplicateAbility extends StaticAbility implements OptionalAdditiona
|
||||||
@Override
|
@Override
|
||||||
public void addOptionalAdditionalCosts(Ability ability, Game game) {
|
public void addOptionalAdditionalCosts(Ability ability, Game game) {
|
||||||
if (ability instanceof SpellAbility) {
|
if (ability instanceof SpellAbility) {
|
||||||
Player player = game.getPlayer(controllerId);
|
Player player = game.getPlayer(ability.getControllerId());
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
this.resetReplicate();
|
this.resetReplicate();
|
||||||
|
|
||||||
boolean again = true;
|
boolean again = true;
|
||||||
while (player.canRespond() && again) {
|
while (player.canRespond()
|
||||||
|
&& again) {
|
||||||
String times = "";
|
String times = "";
|
||||||
if (additionalCost.isRepeatable()) {
|
if (additionalCost.isRepeatable()) {
|
||||||
int numActivations = additionalCost.getActivateCount();
|
int numActivations = additionalCost.getActivateCount();
|
||||||
|
@ -91,10 +94,12 @@ public class ReplicateAbility extends StaticAbility implements OptionalAdditiona
|
||||||
|
|
||||||
// TODO: add AI support to find max number of possible activations (from available mana)
|
// TODO: add AI support to find max number of possible activations (from available mana)
|
||||||
// canPay checks only single mana available, not total mana usage
|
// canPay checks only single mana available, not total mana usage
|
||||||
if (additionalCost.canPay(ability, sourceId, controllerId, game)
|
if (additionalCost.canPay(ability, sourceId, ability.getControllerId(), game)
|
||||||
&& player.chooseUse(/*Outcome.Benefit*/Outcome.AIDontUseIt, new StringBuilder("Pay ").append(times).append(additionalCost.getText(false)).append(" ?").toString(), ability, game)) {
|
&& player.chooseUse(/*Outcome.Benefit*/Outcome.AIDontUseIt,
|
||||||
|
new StringBuilder("Pay ").append(times).append(
|
||||||
|
additionalCost.getText(false)).append(" ?").toString(), ability, game)) {
|
||||||
additionalCost.activate();
|
additionalCost.activate();
|
||||||
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext(); ) {
|
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) {
|
||||||
Cost cost = (Cost) it.next();
|
Cost cost = (Cost) it.next();
|
||||||
if (cost instanceof ManaCostsImpl) {
|
if (cost instanceof ManaCostsImpl) {
|
||||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||||
|
@ -185,7 +190,8 @@ class ReplicateTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return "Replicate <i>(When you cast this spell, copy it for each time you paid its replicate cost. You may choose new targets for the copies.)</i>";
|
return "Replicate <i>(When you cast this spell, copy it for each time you paid "
|
||||||
|
+ "its replicate cost. You may choose new targets for the copies.)</i>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +211,8 @@ class ReplicateCopyEffect extends OneShotEffect {
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
Spell spell = (Spell) this.getValue("ReplicateSpell");
|
Spell spell = (Spell) this.getValue("ReplicateSpell");
|
||||||
int replicateCount = (Integer) this.getValue("ReplicateCount");
|
int replicateCount = (Integer) this.getValue("ReplicateCount");
|
||||||
if (spell != null && replicateCount > 0) {
|
if (spell != null
|
||||||
|
&& replicateCount > 0) {
|
||||||
// reset replicate now so the copies don't report x times Replicate
|
// reset replicate now so the copies don't report x times Replicate
|
||||||
Card card = game.getCard(spell.getSourceId());
|
Card card = game.getCard(spell.getSourceId());
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
|
@ -218,7 +225,8 @@ class ReplicateCopyEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// create the copies
|
// create the copies
|
||||||
StackObject newStackObject = spell.createCopyOnStack(game, source, source.getControllerId(), true, replicateCount);
|
StackObject newStackObject = spell.createCopyOnStack(game, source,
|
||||||
|
source.getControllerId(), true, replicateCount);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,9 +115,9 @@ public class SuspendAbility extends SpecialAction {
|
||||||
* Gives the card the SuspendAbility
|
* Gives the card the SuspendAbility
|
||||||
*
|
*
|
||||||
* @param suspend - amount of time counters, if Integer.MAX_VALUE is set
|
* @param suspend - amount of time counters, if Integer.MAX_VALUE is set
|
||||||
* there will be {X} costs and X counters added
|
* there will be {X} costs and X counters added
|
||||||
* @param cost - null is used for temporary gained suspend ability
|
* @param cost - null is used for temporary gained suspend ability
|
||||||
* @param card - card that has the suspend ability
|
* @param card - card that has the suspend ability
|
||||||
*/
|
*/
|
||||||
public SuspendAbility(int suspend, ManaCost cost, Card card) {
|
public SuspendAbility(int suspend, ManaCost cost, Card card) {
|
||||||
this(suspend, cost, card, false);
|
this(suspend, cost, card, false);
|
||||||
|
@ -136,7 +136,8 @@ public class SuspendAbility extends SpecialAction {
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder("Suspend ");
|
StringBuilder sb = new StringBuilder("Suspend ");
|
||||||
if (cost != null) {
|
if (cost != null) {
|
||||||
sb.append(suspend == Integer.MAX_VALUE ? "X" : suspend).append("—").append(cost.getText()).append(suspend
|
sb.append(suspend == Integer.MAX_VALUE ? "X" : suspend).append("—")
|
||||||
|
.append(cost.getText()).append(suspend
|
||||||
== Integer.MAX_VALUE ? ". X can't be 0" : "");
|
== Integer.MAX_VALUE ? ". X can't be 0" : "");
|
||||||
if (!shortRule) {
|
if (!shortRule) {
|
||||||
sb.append(" <i>(Rather than cast this card from your hand, pay ")
|
sb.append(" <i>(Rather than cast this card from your hand, pay ")
|
||||||
|
@ -174,8 +175,8 @@ public class SuspendAbility extends SpecialAction {
|
||||||
ability.setControllerId(card.getOwnerId());
|
ability.setControllerId(card.getOwnerId());
|
||||||
game.getState().addOtherAbility(card, ability);
|
game.getState().addOtherAbility(card, ability);
|
||||||
|
|
||||||
SuspendBeginningOfUpkeepInterveningIfTriggeredAbility ability1 =
|
SuspendBeginningOfUpkeepInterveningIfTriggeredAbility ability1
|
||||||
new SuspendBeginningOfUpkeepInterveningIfTriggeredAbility();
|
= new SuspendBeginningOfUpkeepInterveningIfTriggeredAbility();
|
||||||
ability1.setSourceId(card.getId());
|
ability1.setSourceId(card.getId());
|
||||||
ability1.setControllerId(card.getOwnerId());
|
ability1.setControllerId(card.getOwnerId());
|
||||||
game.getState().addOtherAbility(card, ability1);
|
game.getState().addOtherAbility(card, ability1);
|
||||||
|
@ -213,7 +214,7 @@ public class SuspendAbility extends SpecialAction {
|
||||||
return new ActivationStatus(object.isInstant()
|
return new ActivationStatus(object.isInstant()
|
||||||
|| object.hasAbility(FlashAbility.getInstance(), game)
|
|| object.hasAbility(FlashAbility.getInstance(), game)
|
||||||
|| null != game.getContinuousEffects().asThough(sourceId,
|
|| null != game.getContinuousEffects().asThough(sourceId,
|
||||||
AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game)
|
AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game)
|
||||||
|| game.canPlaySorcery(playerId), null);
|
|| game.canPlaySorcery(playerId), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +268,8 @@ class SuspendExileEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
card.addCounters(CounterType.TIME.createInstance(suspend), source, game);
|
card.addCounters(CounterType.TIME.createInstance(suspend), source, game);
|
||||||
if (!game.isSimulation()) {
|
if (!game.isSimulation()) {
|
||||||
game.informPlayers(controller.getLogName() + " suspends (" + suspend + ") " + card.getLogName());
|
game.informPlayers(controller.getLogName()
|
||||||
|
+ " suspends (" + suspend + ") " + card.getLogName());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -305,7 +307,8 @@ class SuspendPlayCardAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return "When the last time counter is removed from this card ({this}), if it's removed from the game, " + super.getRule();
|
return "When the last time counter is removed from this card ({this}), "
|
||||||
|
+ "if it's removed from the game, " + super.getRule();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -318,7 +321,8 @@ class SuspendPlayCardEffect extends OneShotEffect {
|
||||||
|
|
||||||
public SuspendPlayCardEffect() {
|
public SuspendPlayCardEffect() {
|
||||||
super(Outcome.PlayForFree);
|
super(Outcome.PlayForFree);
|
||||||
this.staticText = "play it without paying its mana cost if able. If you can't, it remains removed from the game";
|
this.staticText = "play it without paying its mana cost if able. "
|
||||||
|
+ "If you can't, it remains removed from the game";
|
||||||
}
|
}
|
||||||
|
|
||||||
public SuspendPlayCardEffect(final SuspendPlayCardEffect effect) {
|
public SuspendPlayCardEffect(final SuspendPlayCardEffect effect) {
|
||||||
|
@ -426,7 +430,7 @@ class SuspendBeginningOfUpkeepInterveningIfTriggeredAbility extends ConditionalI
|
||||||
|
|
||||||
public SuspendBeginningOfUpkeepInterveningIfTriggeredAbility() {
|
public SuspendBeginningOfUpkeepInterveningIfTriggeredAbility() {
|
||||||
super(new BeginningOfUpkeepTriggeredAbility(Zone.EXILED, new RemoveCounterSourceEffect(CounterType.TIME.createInstance()),
|
super(new BeginningOfUpkeepTriggeredAbility(Zone.EXILED, new RemoveCounterSourceEffect(CounterType.TIME.createInstance()),
|
||||||
TargetController.YOU, false),
|
TargetController.YOU, false),
|
||||||
SuspendedCondition.instance,
|
SuspendedCondition.instance,
|
||||||
"At the beginning of your upkeep, if this card ({this}) is suspended, remove a time counter from it.");
|
"At the beginning of your upkeep, if this card ({this}) is suspended, remove a time counter from it.");
|
||||||
this.setRuleVisible(false);
|
this.setRuleVisible(false);
|
||||||
|
|
Loading…
Add table
Reference in a new issue