* GUI: added card icon for announced X value (activate ability);

This commit is contained in:
Oleg Agafonov 2021-07-19 14:25:51 +04:00
parent 76082e1d7a
commit 7ccb390e4d
3 changed files with 84 additions and 2 deletions

View file

@ -183,6 +183,7 @@
if (card instanceof StackAbilityView) { if (card instanceof StackAbilityView) {
// replace ability by original card // replace ability by original card
CardView tmp = ((StackAbilityView) card).getSourceCard(); CardView tmp = ((StackAbilityView) card).getSourceCard();
// sync settings
tmp.overrideRules(card.getRules()); tmp.overrideRules(card.getRules());
tmp.setChoosable(card.isChoosable()); tmp.setChoosable(card.isChoosable());
tmp.setPlayableStats(card.getPlayableStats().copy()); tmp.setPlayableStats(card.getPlayableStats().copy());
@ -191,6 +192,9 @@
tmp.overrideTargets(card.getTargets()); tmp.overrideTargets(card.getTargets());
tmp.overrideId(card.getId()); tmp.overrideId(card.getId());
tmp.setAbilityType(card.getAbilityType()); tmp.setAbilityType(card.getAbilityType());
// sync card icons
tmp.getCardIcons().clear();
tmp.getCardIcons().addAll(card.getCardIcons());
card = tmp; card = tmp;
} else { } else {
card.setAbilityType(null); card.setAbilityType(null);

View file

@ -3,9 +3,11 @@ package mage.view;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.Modes; import mage.abilities.Modes;
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.hint.Hint; import mage.abilities.hint.Hint;
import mage.abilities.hint.HintUtils; import mage.abilities.hint.HintUtils;
import mage.abilities.icon.other.VariableCostCardIcon;
import mage.cards.Card; import mage.cards.Card;
import mage.constants.AbilityType; import mage.constants.AbilityType;
import mage.constants.CardType; import mage.constants.CardType;
@ -28,7 +30,7 @@ public class StackAbilityView extends CardView {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
// in GUI: that's view will be replaced by sourceCard, so don't forget to sync settings like // in GUI: that's view will be replaced by sourceCard, so don't forget to sync settings like
// selectable, chooseable, etc. Search by getSourceCard // selectable, chooseable, card icons etc. Search by getSourceCard
private final CardView sourceCard; private final CardView sourceCard;
public StackAbilityView(Game game, StackAbility ability, String sourceName, CardView sourceCard) { public StackAbilityView(Game game, StackAbility ability, String sourceName, CardView sourceCard) {
@ -73,6 +75,13 @@ public class StackAbilityView extends CardView {
this.counters = sourceCard.getCounters(); this.counters = sourceCard.getCounters();
updateTargets(game, ability); updateTargets(game, ability);
// card icons (warning, it must be synced in gui dialogs with replaced card, see comments at the start of the file)
// cost x
if (ability.getManaCostsToPay().containsX()) {
int costX = ManacostVariableValue.REGULAR.calculate(game, ability, null);
this.cardIcons.add(new VariableCostCardIcon(costX));
}
} }
private void updateTargets(Game game, StackAbility ability) { private void updateTargets(Game game, StackAbility ability) {
@ -108,7 +117,7 @@ public class StackAbilityView extends CardView {
} }
} }
if (!names.isEmpty()) { if (!names.isEmpty()) {
getRules().add("<i>Related objects: " + names.toString() + "</i>"); getRules().add("<i>Related objects: " + names + "</i>");
} }
// show for modal ability, which mode was choosen // show for modal ability, which mode was choosen

View file

@ -152,4 +152,73 @@ public class CardIconsTest extends CardTestPlayerBase {
execute(); execute();
assertAllCommandsUsed(); assertAllCommandsUsed();
} }
@Test
public void test_CostX_Abilities() {
// X icon must be visible only for activated ability, not spell cast
// {X}{R}, {tap}, Sacrifice Cinder Elemental: Cinder Elemental deals X damage to any target.
addCard(Zone.HAND, playerA, "Cinder Elemental", 1); // {3}{R}
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
// hand (not visible)
runCode("card icons in hand", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
GameView gameView = getGameView(player);
Assert.assertEquals("must have 1 card in hand", 1, gameView.getHand().values().size());
CardView cardView = gameView.getHand().values().stream().findFirst().get();
Assert.assertEquals("must have non x cost card icons in hand", 0, cardView.getCardIcons().size());
});
// spell cast
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cinder Elemental");
// stack (spell cast - not visible)
runCode("card icons on stack (spell cast - not visible)", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
GameView gameView = getGameView(player);
Assert.assertEquals("must have 1 card in stack", 1, gameView.getStack().values().size());
CardView cardView = gameView.getStack().values().stream().findFirst().get();
Assert.assertEquals("must have not x cost card icons in stack", 0, cardView.getCardIcons().size());
});
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPermanentCount("after cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cinder Elemental", 1);
// battlefield (card, not visible)
runCode("card icons in battlefield (card)", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
GameView gameView = getGameView(player);
PlayerView playerView = gameView.getPlayers().get(0);
Assert.assertEquals("player", player.getName(), playerView.getName());
CardView cardView = playerView.getBattlefield().values().stream().filter(p -> p.getName().equals("Cinder Elemental")).findFirst().orElse(null);
Assert.assertNotNull("must have Cinder Elemental in battlefield", cardView);
Assert.assertEquals("must have not x cost card icons in battlefield (card)", 0, cardView.getCardIcons().size());
});
// ACTIVATE ABILITY (x must be visible in stack, but not visible after resolve)
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{X}{R}");
setChoice(playerA, "X=2");
addTarget(playerA, playerB);
// stack (ability activated - visible)
runCode("card icons on stack (ability activated - visible)", 3, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
GameView gameView = getGameView(player);
Assert.assertEquals("ability activated - must have 1 card in stack", 1, gameView.getStack().values().size());
CardView cardView = gameView.getStack().values().stream().findFirst().get();
Assert.assertEquals("ability activated - must have x cost card icons in stack", 1, cardView.getCardIcons().size());
});
// battlefield (ability activated, not visible)
runCode("card icons in battlefield (ability activated)", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
GameView gameView = getGameView(player);
PlayerView playerView = gameView.getPlayers().get(0);
Assert.assertEquals("player", player.getName(), playerView.getName());
CardView cardView = playerView.getBattlefield().values().stream().filter(p -> p.getName().equals("Cinder Elemental")).findFirst().orElse(null);
Assert.assertNotNull("ability activated - must have Cinder Elemental in battlefield", cardView);
Assert.assertEquals("ability activated - must have not x cost card icons in battlefield", 0, cardView.getCardIcons().size());
});
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
}
} }