mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00:00
Alternative cost - fixed that it doesn't allow to cast cards that was affected by cost modification effects (example: Prowl ability, see #6698);
This commit is contained in:
parent
f9a9a55f7b
commit
1e744a0aae
12 changed files with 218 additions and 114 deletions
|
@ -1,21 +1,19 @@
|
|||
|
||||
package mage.cards.e;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.condition.common.ProwlCondition;
|
||||
import mage.abilities.condition.common.ProwlCostWasPaidCondition;
|
||||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.hint.common.ProwlCostWasPaidHint;
|
||||
import mage.abilities.keyword.ProwlAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
|
@ -23,14 +21,16 @@ import mage.players.Player;
|
|||
import mage.target.common.TargetCardInLibrary;
|
||||
import mage.target.common.TargetOpponent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class EarwigSquad extends CardImpl {
|
||||
|
||||
public EarwigSquad(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
|
||||
this.subtype.add(SubType.GOBLIN);
|
||||
this.subtype.add(SubType.ROGUE);
|
||||
|
||||
|
@ -39,11 +39,13 @@ public final class EarwigSquad extends CardImpl {
|
|||
|
||||
// Prowl {2}{B}
|
||||
this.addAbility(new ProwlAbility(this, "{2}{B}"));
|
||||
|
||||
// When Earwig Squad enters the battlefield, if its prowl cost was paid, search target opponent's library for three cards and exile them. Then that player shuffles their library.
|
||||
EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new EarwigSquadEffect(), false);
|
||||
ability.addTarget(new TargetOpponent());
|
||||
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ProwlCondition.instance,
|
||||
"When {this} enters the battlefield, if its prowl cost was paid, search target opponent's library for three cards and exile them. Then that player shuffles their library."));
|
||||
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ProwlCostWasPaidCondition.instance,
|
||||
"When {this} enters the battlefield, if its prowl cost was paid, search target opponent's library for three cards and exile them. Then that player shuffles their library.")
|
||||
.addHint(ProwlCostWasPaidHint.instance));
|
||||
|
||||
}
|
||||
|
||||
|
@ -78,7 +80,7 @@ class EarwigSquadEffect extends OneShotEffect {
|
|||
Player opponent = game.getPlayer(source.getFirstTarget());
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null && opponent != null) {
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(0, 3, new FilterCard("cards from opponents library to exile"));
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(0, 3, new FilterCard("cards from opponents library to exile"));
|
||||
if (player.searchLibrary(target, source, game, opponent.getId())) {
|
||||
List<UUID> targets = target.getTargets();
|
||||
for (UUID targetId : targets) {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
|
||||
package mage.cards.l;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.condition.common.ProwlCondition;
|
||||
import mage.abilities.condition.common.ProwlCostWasPaidCondition;
|
||||
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.hint.common.ProwlCostWasPaidHint;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.abilities.keyword.ProwlAbility;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -14,14 +13,15 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class LatchkeyFaerie extends CardImpl {
|
||||
|
||||
public LatchkeyFaerie(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}");
|
||||
this.subtype.add(SubType.FAERIE);
|
||||
this.subtype.add(SubType.ROGUE);
|
||||
|
||||
|
@ -36,8 +36,9 @@ public final class LatchkeyFaerie extends CardImpl {
|
|||
|
||||
// When Latchkey Faerie enters the battlefield, if its prowl cost was paid, draw a card.
|
||||
EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false);
|
||||
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ProwlCondition.instance,
|
||||
"When {this} enters the battlefield, if its prowl cost was paid, draw a card."));
|
||||
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ProwlCostWasPaidCondition.instance,
|
||||
"When {this} enters the battlefield, if its prowl cost was paid, draw a card.")
|
||||
.addHint(ProwlCostWasPaidHint.instance));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
package mage.cards.m;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.condition.common.ProwlCondition;
|
||||
import mage.abilities.condition.common.ProwlCostWasPaidCondition;
|
||||
import mage.abilities.decorator.ConditionalOneShotEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.abilities.effects.common.LoseLifeTargetEffect;
|
||||
import mage.abilities.hint.common.ProwlCostWasPaidHint;
|
||||
import mage.abilities.keyword.ProwlAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -15,14 +14,15 @@ import mage.constants.CardType;
|
|||
import mage.constants.SubType;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class MorselTheft extends CardImpl {
|
||||
|
||||
public MorselTheft(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.SORCERY},"{2}{B}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{2}{B}{B}");
|
||||
this.subtype.add(SubType.ROGUE);
|
||||
|
||||
// Prowl {1}{B}
|
||||
|
@ -34,7 +34,8 @@ public final class MorselTheft extends CardImpl {
|
|||
effect.setText("and you gain 3 life");
|
||||
getSpellAbility().addEffect(effect);
|
||||
getSpellAbility().addTarget(new TargetPlayer());
|
||||
getSpellAbility().addEffect(new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), ProwlCondition.instance));
|
||||
getSpellAbility().addEffect(new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), ProwlCostWasPaidCondition.instance));
|
||||
getSpellAbility().addHint(ProwlCostWasPaidHint.instance);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,44 +1,47 @@
|
|||
|
||||
package mage.cards.n;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.common.ProwlCondition;
|
||||
import mage.abilities.condition.common.ProwlCostWasPaidCondition;
|
||||
import mage.abilities.decorator.ConditionalOneShotEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect;
|
||||
import mage.abilities.hint.common.ProwlCostWasPaidHint;
|
||||
import mage.abilities.keyword.ProwlAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.token.FaerieRogueToken;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.AmountOfDamageAPlayerReceivedThisTurnWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LoneFox
|
||||
*/
|
||||
public final class NotoriousThrong extends CardImpl {
|
||||
|
||||
public NotoriousThrong(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.SORCERY},"{3}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{3}{U}");
|
||||
this.subtype.add(SubType.ROGUE);
|
||||
|
||||
// Prowl {5}{U}
|
||||
this.addAbility(new ProwlAbility(this, "{5}{U}"));
|
||||
|
||||
// create X 1/1 black Faerie Rogue creature tokens with flying, where X is the damage dealt to your opponents this turn.
|
||||
this.getSpellAbility().addEffect(new NotoriousThrongEffect());
|
||||
this.getSpellAbility().addWatcher(new AmountOfDamageAPlayerReceivedThisTurnWatcher());
|
||||
|
||||
// If Notorious Throng's prowl cost was paid, take an extra turn after this one.
|
||||
Effect effect = new ConditionalOneShotEffect(new AddExtraTurnControllerEffect(), ProwlCondition.instance);
|
||||
Effect effect = new ConditionalOneShotEffect(new AddExtraTurnControllerEffect(), ProwlCostWasPaidCondition.instance);
|
||||
effect.setText("If {this}'s prowl cost was paid, take an extra turn after this one.");
|
||||
this.getSpellAbility().addEffect(effect);
|
||||
this.getSpellAbility().addHint(ProwlCostWasPaidHint.instance);
|
||||
}
|
||||
|
||||
public NotoriousThrong(final NotoriousThrong card) {
|
||||
|
@ -71,12 +74,12 @@ class NotoriousThrongEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
AmountOfDamageAPlayerReceivedThisTurnWatcher watcher = game.getState().getWatcher(AmountOfDamageAPlayerReceivedThisTurnWatcher.class);
|
||||
if(controller != null && watcher != null) {
|
||||
if (controller != null && watcher != null) {
|
||||
int numTokens = 0;
|
||||
for(UUID opponentId: game.getOpponents(controller.getId())) {
|
||||
for (UUID opponentId : game.getOpponents(controller.getId())) {
|
||||
numTokens += watcher.getAmountOfDamageReceivedThisTurn(opponentId);
|
||||
}
|
||||
if(numTokens > 0) {
|
||||
if (numTokens > 0) {
|
||||
new CreateTokenEffect(new FaerieRogueToken(), numTokens).apply(game, source);
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -1,75 +1,77 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
|
||||
*/
|
||||
public class ProwlTest extends CardTestPlayerBase {
|
||||
|
||||
@Ignore // have not figured out how to have the test API cast a card using Prowl yet
|
||||
|
||||
@Test
|
||||
public void testBasicProwlCasting() {
|
||||
public void test_ProwlNormal() {
|
||||
// Auntie's Snitch {2}{B} Creature — Goblin Rogue (3/1)
|
||||
// Auntie's Snitch can't block.
|
||||
// Prowl {1}{B} (You may cast this for its prowl cost if you dealt combat damage to a player this turn with a Goblin or Rogue.)
|
||||
// Whenever a Goblin or Rogue you control deals combat damage to a player, if Auntie's Snitch is in your graveyard, you may return Auntie's Snitch to your hand.
|
||||
addCard(Zone.HAND, playerA, "Auntie's Snitch");
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||
//
|
||||
// {1}{R} Creature — Goblin Warrior 1/1
|
||||
// Red creatures you control have first strike.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Bloodmark Mentor");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Bloodmark Mentor");
|
||||
|
||||
// prepare prowl condition
|
||||
checkPlayableAbility("can't", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Auntie's Snitch", false);
|
||||
attack(1, playerA, "Bloodmark Mentor");
|
||||
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Auntie's Snitch using prowl");
|
||||
|
||||
checkPlayableAbility("must play", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast Auntie's Snitch", true);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Auntie's Snitch");
|
||||
setChoice(playerA, "Yes"); // choosing to pay prowl cost
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertLife(playerB, 19);
|
||||
assertPermanentCount(playerA, "Bloodmark Mentor", 1);
|
||||
assertPermanentCount(playerA, "Auntie's Snitch", 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reported bug: Prowl is not taking into consideration other cost reducing effects. For instance Goblin Warchief
|
||||
* does not reduce the Prowl cost of other Goblin cards with Prowl ability.
|
||||
*/
|
||||
@Ignore // have not figured out how to have the test API cast a card using Prowl yet
|
||||
*/
|
||||
@Test
|
||||
public void testProwlWithCostDiscount() {
|
||||
|
||||
public void test_ProwlWithCostReduce() {
|
||||
// Auntie's Snitch {2}{B} Creature — Goblin Rogue (3/1)
|
||||
// Auntie's Snitch can't block.
|
||||
// Prowl {1}{B} (You may cast this for its prowl cost if you dealt combat damage to a player this turn with a Goblin or Rogue.)
|
||||
// Whenever a Goblin or Rogue you control deals combat damage to a player, if Auntie's Snitch is in your graveyard, you may return Auntie's Snitch to your hand.
|
||||
addCard(Zone.HAND, playerA, "Auntie's Snitch");
|
||||
|
||||
addCard(Zone.HAND, playerA, "Auntie's Snitch");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
|
||||
// Goblin Warchief {1}{R}{R} Creature — Goblin Warrior (2/2)
|
||||
// Goblin spells you cast cost 1 less to cast.
|
||||
// Goblin creatures you control have haste.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Goblin Warchief");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp");
|
||||
|
||||
|
||||
// prepare prowl condition
|
||||
checkPlayableAbility("can't", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Auntie's Snitch", false);
|
||||
attack(1, playerA, "Goblin Warchief");
|
||||
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Auntie's Snitch using prowl"); // should only cost {B} with Warchief discount
|
||||
|
||||
checkPlayableAbility("must play", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast Auntie's Snitch", true);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Auntie's Snitch"); // should only cost {B} with Warchief discount
|
||||
setChoice(playerA, "Yes"); // choosing to pay prowl cost
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertLife(playerB, 18);
|
||||
assertPermanentCount(playerA, "Goblin Warchief", 1);
|
||||
assertPermanentCount(playerA, "Auntie's Snitch", 1);
|
||||
|
|
|
@ -129,10 +129,15 @@ public class PlayFromNonHandZoneTest extends CardTestPlayerBase {
|
|||
|
||||
attack(2, playerB, "Narset, Enlightened Master");
|
||||
|
||||
checkPlayableAbility("must play", 2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Cast Cathartic Reunion", true);
|
||||
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Cathartic Reunion");
|
||||
setChoice(playerB, "Swamp^Forest");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(2, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
|
||||
assertHandCount(playerB, 3);
|
||||
assertGraveyardCount(playerB, "Forest", 1);
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.keyword.ProwlAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.SubType;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.ProwlWatcher;
|
||||
|
||||
/**
|
||||
* Checks if a the spell was cast with the alternate prowl costs
|
||||
* Is it able to activate prowl cost (damage was made)
|
||||
*
|
||||
* @author LevelX2
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum ProwlCondition implements Condition {
|
||||
|
||||
|
@ -18,22 +18,15 @@ public enum ProwlCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
ProwlWatcher watcher = game.getState().getWatcher(ProwlWatcher.class);
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability instanceof ProwlAbility) {
|
||||
if (((ProwlAbility) ability).isActivated(source, game)) {
|
||||
return true;
|
||||
}
|
||||
if (watcher != null && card != null) {
|
||||
for (SubType subtype : card.getSubtype(game)) {
|
||||
if (watcher.hasSubtypeMadeCombatDamage(source.getControllerId(), subtype)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{source}'s prowl cost was paid";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.keyword.ProwlAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* Checks if a the spell was cast with the alternate prowl costs
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public enum ProwlCostWasPaidCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability instanceof ProwlAbility) {
|
||||
if (((ProwlAbility) ability).isActivated(source, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{source}'s prowl cost was paid";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.common.ProwlCostWasPaidCondition;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum ProwlCostWasPaidHint implements Hint {
|
||||
|
||||
instance;
|
||||
private static final ConditionHint hint = new ConditionHint(ProwlCostWasPaidCondition.instance, "Prowl cost was paid");
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
26
Mage/src/main/java/mage/abilities/hint/common/ProwlHint.java
Normal file
26
Mage/src/main/java/mage/abilities/hint/common/ProwlHint.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.common.ProwlCondition;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum ProwlHint implements Hint {
|
||||
|
||||
instance;
|
||||
private static final ConditionHint hint = new ConditionHint(ProwlCondition.instance, "Prowl cost can be activated");
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
|
@ -1,30 +1,26 @@
|
|||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
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.condition.common.ProwlCondition;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.hint.common.ProwlHint;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.ProwlWatcher;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 702.74. Prowl #
|
||||
*
|
||||
* <p>
|
||||
* 702.74a Prowl is a static ability that functions on the stack. "Prowl [cost]"
|
||||
* means "You may pay [cost] rather than pay this spell's mana cost if a player
|
||||
* was dealt combat damage this turn by a source that, at the time it dealt that
|
||||
|
@ -41,13 +37,13 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
|
|||
private String reminderText;
|
||||
|
||||
public ProwlAbility(Card card, String manaString) {
|
||||
super(Zone.STACK, null);
|
||||
setRuleAtTheTop(true);
|
||||
name = PROWL_KEYWORD;
|
||||
setReminderText(card);
|
||||
super(Zone.ALL, null);
|
||||
this.setRuleAtTheTop(true);
|
||||
this.name = PROWL_KEYWORD;
|
||||
this.setReminderText(card);
|
||||
this.addProwlCost(manaString);
|
||||
addWatcher(new ProwlWatcher());
|
||||
|
||||
this.addWatcher(new ProwlWatcher());
|
||||
this.addHint(ProwlHint.instance);
|
||||
}
|
||||
|
||||
public ProwlAbility(final ProwlAbility ability) {
|
||||
|
@ -85,26 +81,17 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
|
|||
|
||||
@Override
|
||||
public boolean isAvailable(Ability source, Game game) {
|
||||
return true;
|
||||
return ProwlCondition.instance.apply(game, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
|
||||
if (ability instanceof SpellAbility) {
|
||||
Player player = game.getPlayer(controllerId);
|
||||
ProwlWatcher prowlWatcher = game.getState().getWatcher(ProwlWatcher.class);
|
||||
Card card = game.getCard(ability.getSourceId());
|
||||
if (player == null || prowlWatcher == null || card == null) {
|
||||
throw new IllegalArgumentException("Params can't be null");
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
boolean canProwl = false;
|
||||
for (SubType subtype : card.getSubtype(game)) {
|
||||
if (prowlWatcher.hasSubtypeMadeCombatDamage(ability.getControllerId(), subtype)) {
|
||||
canProwl = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canProwl) {
|
||||
if (ProwlCondition.instance.apply(game, ability)) {
|
||||
this.resetProwl();
|
||||
for (AlternativeCost2 prowlCost : prowlCosts) {
|
||||
if (prowlCost.canPay(ability, sourceId, controllerId, game)
|
||||
|
@ -112,7 +99,7 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
|
|||
prowlCost.activate();
|
||||
ability.getManaCostsToPay().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();
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
|
@ -162,7 +149,7 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
|
|||
}
|
||||
|
||||
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}";
|
||||
}
|
||||
|
||||
|
@ -174,4 +161,4 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
|
|||
}
|
||||
return alterCosts;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3046,6 +3046,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions availableMana, Ability ability, Game game) {
|
||||
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
|
||||
Ability copyAbility; // for alternative cost and reduce tries
|
||||
for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) {
|
||||
// if cast for noMana no Alternative costs are allowed
|
||||
if (alternateSourceCostsAbility instanceof AlternativeSourceCosts) {
|
||||
|
@ -3064,7 +3065,15 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (availableMana == null) {
|
||||
return true;
|
||||
}
|
||||
for (Mana mana : manaCosts.getOptions()) {
|
||||
|
||||
// alternative cost reduce
|
||||
copyAbility = ability.copy();
|
||||
copyAbility.getManaCostsToPay().clear();
|
||||
copyAbility.getManaCostsToPay().addAll(manaCosts.copy());
|
||||
sourceObject.adjustCosts(copyAbility, game);
|
||||
game.getContinuousEffects().costModification(copyAbility, game);
|
||||
|
||||
for (Mana mana : copyAbility.getManaCostsToPay().getOptions()) {
|
||||
for (Mana avail : availableMana) {
|
||||
if (mana.enough(avail)) {
|
||||
return true;
|
||||
|
@ -3092,7 +3101,18 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (manaCosts.isEmpty()) {
|
||||
return true;
|
||||
} else {
|
||||
for (Mana mana : manaCosts.getOptions()) {
|
||||
if (availableMana == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// alternative cost reduce
|
||||
copyAbility = ability.copy();
|
||||
copyAbility.getManaCostsToPay().clear();
|
||||
copyAbility.getManaCostsToPay().addAll(manaCosts.copy());
|
||||
sourceObject.adjustCosts(copyAbility, game);
|
||||
game.getContinuousEffects().costModification(copyAbility, game);
|
||||
|
||||
for (Mana mana : copyAbility.getManaCostsToPay().getOptions()) {
|
||||
for (Mana avail : availableMana) {
|
||||
if (mana.enough(avail)) {
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue