Bargain ability - fixed that cards can't be cast without full mana (#11089)

* [WOE] Fix Hamlet Glutton & friends
* add tests
This commit is contained in:
Susucre 2023-09-02 13:38:45 +02:00 committed by GitHub
parent 4b8e6ba9bc
commit 24315460fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 130 additions and 6 deletions

View file

@ -5,6 +5,7 @@ import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.BargainedCondition;
import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.OptionalAdditionalCost;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.keyword.BargainAbility;
@ -57,9 +58,12 @@ public final class HamletGlutton extends CardImpl {
enum HamletGluttonAdjuster implements CostAdjuster {
instance;
private static OptionalAdditionalCost bargainCost = BargainAbility.makeBargainCost();
@Override
public void adjustCosts(Ability ability, Game game) {
if (BargainedCondition.instance.apply(game, ability)) {
if (BargainedCondition.instance.apply(game, ability)
|| (game.inCheckPlayableState() && bargainCost.canPay(ability, null, ability.getControllerId(), game))) {
CardUtil.reduceCost(ability, 2);
}
}

View file

@ -3,6 +3,7 @@ package mage.cards.i;
import mage.abilities.Ability;
import mage.abilities.condition.common.BargainedCondition;
import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.OptionalAdditionalCost;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.keyword.BargainAbility;
@ -48,9 +49,12 @@ public final class IceOut extends CardImpl {
enum IceOutAdjuster implements CostAdjuster {
instance;
private static OptionalAdditionalCost bargainCost = BargainAbility.makeBargainCost();
@Override
public void adjustCosts(Ability ability, Game game) {
if (BargainedCondition.instance.apply(game, ability)) {
if (BargainedCondition.instance.apply(game, ability)
|| (game.inCheckPlayableState() && bargainCost.canPay(ability, null, ability.getControllerId(), game))) {
CardUtil.reduceCost(ability, 1);
}
}

View file

@ -3,6 +3,7 @@ package mage.cards.j;
import mage.abilities.Ability;
import mage.abilities.condition.common.BargainedCondition;
import mage.abilities.costs.CostAdjuster;
import mage.abilities.costs.OptionalAdditionalCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
@ -50,9 +51,12 @@ public final class JohannsStopgap extends CardImpl {
enum JohannsStopgapAdjuster implements CostAdjuster {
instance;
private static OptionalAdditionalCost bargainCost = BargainAbility.makeBargainCost();
@Override
public void adjustCosts(Ability ability, Game game) {
if (BargainedCondition.instance.apply(game, ability)) {
if (BargainedCondition.instance.apply(game, ability)
|| (game.inCheckPlayableState() && bargainCost.canPay(ability, null, ability.getControllerId(), game))) {
CardUtil.reduceCost(ability, 2);
}
}

View file

@ -42,6 +42,25 @@ public class BargainTest extends CardTestPlayerBase {
// 4/4 Artifact
private static final String stoneGolem = "Stone Golem";
/**
* Hamlet Glutton
* {5}{G}{G}
* Creature Giant
*
* Bargain (You may sacrifice an artifact, enchantment, or token as you cast this spell.)
*
* This spell costs {2} less to cast if its bargained.
*
* Trample
*
* When Hamlet Glutton enters the battlefield, you gain 3 life.
*
* 6/6
*/
private static final String glutton = "Hamlet Glutton";
private static final String relic = "Darksteel Relic"; // {0} Artifact
@Test
public void testBargainNotPaidOuphe() {
setStrictChooseMode(true);
@ -227,4 +246,93 @@ public class BargainTest extends CardTestPlayerBase {
assertPermanentCount(playerB, stoneGolem, 0);
assertExileCount(playerB, stoneGolem, 1);
}
@Test
public void testBargainOn5ManaGlutton() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
addCard(Zone.HAND, playerA, glutton);
addCard(Zone.HAND, playerA, relic);
checkPlayableAbility("before relic", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hamlet Glutton", false);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, relic, true);
checkPlayableAbility("after relic", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hamlet Glutton", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, glutton, true);
setChoice(playerA, true); // Do bargain.
setChoice(playerA, relic); // Bargain the relic away.
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 20 + 3);
}
@Test
public void testBargainOn7ManaGlutton() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 7);
addCard(Zone.HAND, playerA, glutton);
addCard(Zone.HAND, playerA, relic);
checkPlayableAbility("before relic", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hamlet Glutton", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, relic, true);
checkPlayableAbility("after relic", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hamlet Glutton", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, glutton, true);
setChoice(playerA, true); // Do bargain.
setChoice(playerA, relic); // Bargain the relic away.
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 20 + 3);
assertTappedCount("Forest", true, 5);
}
@Test
public void testNoBargainOn7ManaGlutton() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 7);
addCard(Zone.HAND, playerA, glutton);
addCard(Zone.HAND, playerA, relic);
checkPlayableAbility("before relic", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hamlet Glutton", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, relic, true);
checkPlayableAbility("after relic", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hamlet Glutton", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, glutton, true);
setChoice(playerA, false); // No bargain.
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 20 + 3);
assertTappedCount("Forest", true, 7);
}
@Test
public void testCantBargainOn7ManaGlutton() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 7);
addCard(Zone.HAND, playerA, glutton);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, glutton, true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 20 + 3);
assertTappedCount("Forest", true, 7);
}
}

View file

@ -49,10 +49,15 @@ public class BargainAbility extends StaticAbility implements OptionalAdditionalS
));
}
public static OptionalAdditionalCost makeBargainCost(){
OptionalAdditionalCost cost = new OptionalAdditionalCostImpl(keywordText, reminderText, new SacrificeTargetCost(bargainFilter));
cost.setRepeatable(false);
return cost;
}
public BargainAbility() {
super(Zone.STACK, null);
this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new SacrificeTargetCost(bargainFilter));
this.additionalCost.setRepeatable(false);
this.additionalCost = makeBargainCost();
this.rule = additionalCost.getName() + ' ' + additionalCost.getReminderText();
this.setRuleAtTheTop(true);
this.addHint(BargainCostWasPaidHint.instance);
@ -111,7 +116,6 @@ public class BargainAbility extends StaticAbility implements OptionalAdditionalS
return activationKey != null && getActivationKey(source, game).equalsIgnoreCase(activationKey);
}
/**
* TODO: remove with Tag Cost Tracking.
* Return activation zcc key for searching spell's settings in source object