mirror of
https://github.com/correl/mage.git
synced 2024-12-24 03:00:14 +00:00
* Geode Golem - fixed duplicated commander tax on damage trigger (#7593);
This commit is contained in:
parent
650acf9e1e
commit
f6c0f4c712
4 changed files with 230 additions and 84 deletions
|
@ -4,7 +4,6 @@ import mage.ApprovingObject;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.Card;
|
||||
|
@ -16,8 +15,6 @@ import mage.filter.FilterCard;
|
|||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.util.ManaUtil;
|
||||
import mage.watchers.common.CommanderPlaysCountWatcher;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
@ -37,8 +34,7 @@ public final class GeodeGolem extends CardImpl {
|
|||
// Trample
|
||||
this.addAbility(TrampleAbility.getInstance());
|
||||
|
||||
// Whenever Geode Golem deals combat damage to a player, you may
|
||||
// cast your commander from the command zone without paying its mana cost.
|
||||
// Whenever Geode Golem deals combat damage to a player, you may cast your commander from the command zone without paying its mana cost.
|
||||
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new GeodeGolemEffect(), true));
|
||||
}
|
||||
|
||||
|
@ -83,12 +79,11 @@ class GeodeGolemEffect extends OneShotEffect {
|
|||
target.setNotTarget(true);
|
||||
if (controller.canRespond()
|
||||
&& controller.choose(Outcome.PlayForFree, new CardsImpl(commandersInCommandZone), target, game)) {
|
||||
if (target.getFirstTarget() != null) {
|
||||
selectedCommander = commandersInCommandZone.stream()
|
||||
.filter(c -> c.getId().equals(target.getFirstTarget()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
selectedCommander = commandersInCommandZone.stream()
|
||||
.filter(c -> c.getId().equals(target.getFirstTarget()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,27 +91,17 @@ class GeodeGolemEffect extends OneShotEffect {
|
|||
return false;
|
||||
}
|
||||
|
||||
// PAY
|
||||
// TODO: this is broken with the commander cost reduction effect
|
||||
ManaCost cost = null;
|
||||
CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class);
|
||||
int castCount = watcher.getPlaysCount(selectedCommander.getId());
|
||||
if (castCount > 0) {
|
||||
cost = ManaUtil.createManaCost(castCount * 2, false);
|
||||
}
|
||||
|
||||
// CAST: as spell or as land
|
||||
if (cost == null
|
||||
|| cost.pay(source, game, source, controller.getId(), false, null)) {
|
||||
if (selectedCommander.getSpellAbility() != null) { // TODO: can be broken with mdf cards (one side creature, one side land)?
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + selectedCommander.getId(), Boolean.TRUE);
|
||||
Boolean commanderWasCast = controller.cast(controller.chooseAbilityForCast(selectedCommander, game, true),
|
||||
game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + selectedCommander.getId(), null);
|
||||
return commanderWasCast;
|
||||
} else {
|
||||
return controller.playLand(selectedCommander, game, true);
|
||||
}
|
||||
// commander tax applies as additional cost
|
||||
if (selectedCommander.getSpellAbility() != null) {
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + selectedCommander.getId(), Boolean.TRUE);
|
||||
Boolean commanderWasCast = controller.cast(controller.chooseAbilityForCast(selectedCommander, game, true),
|
||||
game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + selectedCommander.getId(), null);
|
||||
return commanderWasCast;
|
||||
} else {
|
||||
// play commander as land is xmage feature, but mtg rules for text "cast commander" doesn't allow that
|
||||
// TODO: improve lands support for "cast your commander" (allow land play from mdf cards)?
|
||||
return controller.playLand(selectedCommander, game, true);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
package org.mage.test.cards.single.c18;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class GeodeGolemTest extends CardTestCommanderDuelBase {
|
||||
|
||||
@Test
|
||||
public void test_Normal() {
|
||||
// Whenever Geode Golem deals combat damage to a player, you may
|
||||
// cast your commander from the command zone without paying its mana cost.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Geode Golem");
|
||||
//
|
||||
addCard(Zone.COMMAND, playerA, "Grizzly Bears"); // {1}{G}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 10);
|
||||
//
|
||||
addCustomEffect_TargetDamage(playerA, 2);
|
||||
|
||||
checkCommandCardCount("before 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 1);
|
||||
|
||||
// turn 1 - first cast
|
||||
|
||||
// attack and cast first time (free)
|
||||
attack(1, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Grizzly Bears"); // commander choice
|
||||
waitStackResolved(1, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 1", 1, PhaseStep.COMBAT_DAMAGE, playerA, "Grizzly Bears", 1);
|
||||
checkPermanentTapped("after 1", 1, PhaseStep.COMBAT_DAMAGE, playerA, "Forest", true, 0);
|
||||
//
|
||||
// remove to command zone (0x tax)
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "target damage 2", "Grizzly Bears");
|
||||
setChoice(playerA, "Yes"); // move to command zone
|
||||
|
||||
// turn 3 - second cast (1x tax)
|
||||
|
||||
attack(3, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Grizzly Bears"); // commander choice
|
||||
waitStackResolved(3, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 2", 3, PhaseStep.COMBAT_DAMAGE, playerA, "Grizzly Bears", 1);
|
||||
checkPermanentTapped("after 2", 3, PhaseStep.COMBAT_DAMAGE, playerA, "Forest", true, 2); // 1x tax
|
||||
//
|
||||
// remove to command zone
|
||||
activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "target damage 2", "Grizzly Bears");
|
||||
setChoice(playerA, "Yes"); // move to command zone
|
||||
|
||||
// turn 5 - third cast (2x tax)
|
||||
|
||||
attack(5, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Grizzly Bears"); // commander choice
|
||||
waitStackResolved(5, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 3", 5, PhaseStep.COMBAT_DAMAGE, playerA, "Grizzly Bears", 1);
|
||||
checkPermanentTapped("after 3", 5, PhaseStep.COMBAT_DAMAGE, playerA, "Forest", true, 2 * 2); // 2x tax
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(5, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Grizzly Bears", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MDF_SingleSide() {
|
||||
// Whenever Geode Golem deals combat damage to a player, you may
|
||||
// cast your commander from the command zone without paying its mana cost.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Geode Golem");
|
||||
//
|
||||
// Akoum Warrior {5}{R} - creature 4/5
|
||||
// Akoum Teeth - land
|
||||
addCard(Zone.COMMAND, playerA, "Akoum Warrior");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10);
|
||||
//
|
||||
addCustomEffect_TargetDamage(playerA, 5);
|
||||
|
||||
checkCommandCardCount("before 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akoum Warrior", 1);
|
||||
|
||||
// turn 1 - first cast
|
||||
|
||||
// attack and cast first time (free)
|
||||
attack(1, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Akoum Warrior"); // commander choice
|
||||
waitStackResolved(1, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 1", 1, PhaseStep.COMBAT_DAMAGE, playerA, "Akoum Warrior", 1);
|
||||
checkPermanentTapped("after 1", 1, PhaseStep.COMBAT_DAMAGE, playerA, "Mountain", true, 0);
|
||||
//
|
||||
// remove to command zone (0x tax)
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "target damage 5", "Akoum Warrior");
|
||||
setChoice(playerA, "Yes"); // move to command zone
|
||||
|
||||
// turn 3 - second cast (1x tax)
|
||||
|
||||
attack(3, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Akoum Warrior"); // commander choice
|
||||
waitStackResolved(3, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 2", 3, PhaseStep.COMBAT_DAMAGE, playerA, "Akoum Warrior", 1);
|
||||
checkPermanentTapped("after 2", 3, PhaseStep.COMBAT_DAMAGE, playerA, "Mountain", true, 2); // 1x tax
|
||||
//
|
||||
// remove to command zone
|
||||
activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "target damage 5", "Akoum Warrior");
|
||||
setChoice(playerA, "Yes"); // move to command zone
|
||||
|
||||
// turn 5 - third cast (2x tax)
|
||||
|
||||
attack(5, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Akoum Warrior"); // commander choice
|
||||
waitStackResolved(5, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 3", 5, PhaseStep.COMBAT_DAMAGE, playerA, "Akoum Warrior", 1);
|
||||
checkPermanentTapped("after 3", 5, PhaseStep.COMBAT_DAMAGE, playerA, "Mountain", true, 2 * 2); // 2x tax
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(5, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Akoum Warrior", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MDF_BothSides() {
|
||||
// Whenever Geode Golem deals combat damage to a player, you may
|
||||
// cast your commander from the command zone without paying its mana cost.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Geode Golem");
|
||||
//
|
||||
// Birgi, God of Storytelling {2}{R} - creature 3/3
|
||||
// Harnfel, Horn of Bounty {4}{R} - artifact
|
||||
addCard(Zone.COMMAND, playerA, "Birgi, God of Storytelling");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10);
|
||||
//
|
||||
addCustomEffect_TargetDamage(playerA, 3);
|
||||
addCustomEffect_DestroyTarget(playerA);
|
||||
|
||||
checkCommandCardCount("before 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Birgi, God of Storytelling", 1);
|
||||
|
||||
// turn 1 - first cast, LEFT side
|
||||
|
||||
// attack and cast first time (free)
|
||||
attack(1, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Birgi, God of Storytelling"); // commander choice
|
||||
setChoice(playerA, "Cast Birgi, God of Storytelling"); // spell choice
|
||||
waitStackResolved(1, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 1", 1, PhaseStep.COMBAT_DAMAGE, playerA, "Birgi, God of Storytelling", 1);
|
||||
checkPermanentTapped("after 1", 1, PhaseStep.COMBAT_DAMAGE, playerA, "Mountain", true, 0);
|
||||
//
|
||||
// remove to command zone (0x tax)
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "target damage 3", "Birgi, God of Storytelling");
|
||||
setChoice(playerA, "Yes"); // move to command zone
|
||||
|
||||
// turn 3 - second cast, LEFT side (1x tax)
|
||||
|
||||
attack(3, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Birgi, God of Storytelling"); // commander choice
|
||||
setChoice(playerA, "Cast Birgi, God of Storytelling"); // spell choice
|
||||
waitStackResolved(3, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 2", 3, PhaseStep.COMBAT_DAMAGE, playerA, "Birgi, God of Storytelling", 1);
|
||||
checkPermanentTapped("after 2", 3, PhaseStep.COMBAT_DAMAGE, playerA, "Mountain", true, 2); // 1x tax
|
||||
//
|
||||
// remove to command zone
|
||||
activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "target damage 3", "Birgi, God of Storytelling");
|
||||
setChoice(playerA, "Yes"); // move to command zone
|
||||
|
||||
// turn 5 - third cast, RIGHT side (2x tax)
|
||||
|
||||
attack(5, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Birgi, God of Storytelling"); // commander choice
|
||||
setChoice(playerA, "Cast Harnfel, Horn of Bounty"); // spell choice
|
||||
waitStackResolved(5, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 3", 5, PhaseStep.COMBAT_DAMAGE, playerA, "Harnfel, Horn of Bounty", 1);
|
||||
checkPermanentTapped("after 3", 5, PhaseStep.COMBAT_DAMAGE, playerA, "Mountain", true, 2 * 2); // 2x tax
|
||||
//
|
||||
// remove to command zone
|
||||
activateAbility(5, PhaseStep.POSTCOMBAT_MAIN, playerA, "target destroy", "Harnfel, Horn of Bounty");
|
||||
setChoice(playerA, "Yes"); // move to command zone
|
||||
|
||||
// turn 7 - fourth cast, RIGHT side (3x tax)
|
||||
|
||||
attack(7, playerA, "Geode Golem");
|
||||
setChoice(playerA, "Yes"); // cast commander
|
||||
setChoice(playerA, "Birgi, God of Storytelling"); // commander choice
|
||||
setChoice(playerA, "Cast Harnfel, Horn of Bounty"); // spell choice
|
||||
waitStackResolved(7, PhaseStep.COMBAT_DAMAGE);
|
||||
checkPermanentCount("after 4", 7, PhaseStep.COMBAT_DAMAGE, playerA, "Harnfel, Horn of Bounty", 1);
|
||||
checkPermanentTapped("after 4", 7, PhaseStep.COMBAT_DAMAGE, playerA, "Mountain", true, 2 * 3); // 3x tax
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(7, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPermanentCount(playerA, "Harnfel, Horn of Bounty", 1);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.CommanderPlaysCountWatcher;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class CommanderPlaysCount implements DynamicValue {
|
||||
|
||||
private Integer multiplier;
|
||||
|
||||
public CommanderPlaysCount() {
|
||||
this(1);
|
||||
}
|
||||
|
||||
public CommanderPlaysCount(Integer multiplier) {
|
||||
this.multiplier = multiplier;
|
||||
}
|
||||
|
||||
public CommanderPlaysCount(final CommanderPlaysCount dynamicValue) {
|
||||
this.multiplier = dynamicValue.multiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class);
|
||||
int value = 0;
|
||||
if (watcher != null) {
|
||||
value = watcher.getPlaysCount(sourceAbility.getSourceId());
|
||||
}
|
||||
return value * multiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommanderPlaysCount copy() {
|
||||
return new CommanderPlaysCount(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -181,6 +181,14 @@ public interface Card extends MageObject {
|
|||
return getOwnerId().equals(controllerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commander tax calculation. Can be change from {2} to life life cost (see Liesa, Shroud of Dusk)
|
||||
*
|
||||
* @param game
|
||||
* @param source
|
||||
* @param abilityToModify
|
||||
* @return
|
||||
*/
|
||||
default boolean commanderCost(Game game, Ability source, Ability abilityToModify) {
|
||||
CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class);
|
||||
int castCount = watcher.getPlaysCount(getMainCard().getId());
|
||||
|
|
Loading…
Reference in a new issue