mirror of
https://github.com/magefree/mage.git
synced 2025-12-21 02:52:02 -08:00
This commit is contained in:
parent
c3903dc550
commit
3f5d2bb9b5
4 changed files with 262 additions and 9 deletions
91
Mage.Sets/src/mage/cards/g/GluttonousHellkite.java
Normal file
91
Mage.Sets/src/mage/cards/g/GluttonousHellkite.java
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
package mage.cards.g;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.EntersBattlefieldAbility;
|
||||||
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
|
import mage.abilities.dynamicvalue.common.GetXValue;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.abilities.effects.common.CastSourceTriggeredAbility;
|
||||||
|
import mage.abilities.effects.common.SacrificeAllEffect;
|
||||||
|
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||||
|
import mage.abilities.hint.ValueHint;
|
||||||
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
|
import mage.abilities.keyword.TrampleAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import mage.filter.StaticFilters;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public final class GluttonousHellkite extends CardImpl {
|
||||||
|
|
||||||
|
public GluttonousHellkite(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{X}{B}{R}{G}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.DRAGON);
|
||||||
|
this.power = new MageInt(3);
|
||||||
|
this.toughness = new MageInt(3);
|
||||||
|
|
||||||
|
// When you cast this spell, each player sacrifices X creatures. Gluttonous Hellkite enters the battlefield with two +1/+1 counters on it for each creature sacrificed this way.
|
||||||
|
this.addAbility(new CastSourceTriggeredAbility(new SacrificeAllEffect(GetXValue.instance, StaticFilters.FILTER_PERMANENT_CREATURES)));
|
||||||
|
Ability ability = new EntersBattlefieldAbility(
|
||||||
|
new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), GluttonousHellkiteDynamicValue.instance, true),
|
||||||
|
"with two +1/+1 counters on it for each creature sacrificed this way");
|
||||||
|
ability.addHint(new ValueHint("Will get +1/+1 counters on ETB", GluttonousHellkiteDynamicValue.instance));
|
||||||
|
//ability.setRuleVisible(false);
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
// Flying
|
||||||
|
this.addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
|
// Trample
|
||||||
|
this.addAbility(TrampleAbility.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
private GluttonousHellkite(final GluttonousHellkite card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GluttonousHellkite copy() {
|
||||||
|
return new GluttonousHellkite(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GluttonousHellkiteDynamicValue implements DynamicValue {
|
||||||
|
instance;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||||
|
List<Permanent> list = SacrificeAllEffect.getSacrificedPermanentsList(sourceAbility.getSourceId(), game, false);
|
||||||
|
if (list == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return list.size() * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GluttonousHellkiteDynamicValue copy() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "X";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return "will get counters";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -138,6 +138,7 @@ public final class ModernHorizons3Commander extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Glimmer of Genius", 187, Rarity.UNCOMMON, mage.cards.g.GlimmerOfGenius.class));
|
cards.add(new SetCardInfo("Glimmer of Genius", 187, Rarity.UNCOMMON, mage.cards.g.GlimmerOfGenius.class));
|
||||||
cards.add(new SetCardInfo("Glimmerpost", 346, Rarity.COMMON, mage.cards.g.Glimmerpost.class));
|
cards.add(new SetCardInfo("Glimmerpost", 346, Rarity.COMMON, mage.cards.g.Glimmerpost.class));
|
||||||
cards.add(new SetCardInfo("Goldspan Dragon", 212, Rarity.MYTHIC, mage.cards.g.GoldspanDragon.class));
|
cards.add(new SetCardInfo("Goldspan Dragon", 212, Rarity.MYTHIC, mage.cards.g.GoldspanDragon.class));
|
||||||
|
cards.add(new SetCardInfo("Gluttonous Hellkite", 73, Rarity.RARE, mage.cards.g.GluttonousHellkite.class));
|
||||||
cards.add(new SetCardInfo("Gonti's Aether Heart", 294, Rarity.MYTHIC, mage.cards.g.GontisAetherHeart.class));
|
cards.add(new SetCardInfo("Gonti's Aether Heart", 294, Rarity.MYTHIC, mage.cards.g.GontisAetherHeart.class));
|
||||||
cards.add(new SetCardInfo("Grapple with the Past", 230, Rarity.COMMON, mage.cards.g.GrappleWithThePast.class));
|
cards.add(new SetCardInfo("Grapple with the Past", 230, Rarity.COMMON, mage.cards.g.GrappleWithThePast.class));
|
||||||
cards.add(new SetCardInfo("Graveshifter", 198, Rarity.UNCOMMON, mage.cards.g.Graveshifter.class));
|
cards.add(new SetCardInfo("Graveshifter", 198, Rarity.UNCOMMON, mage.cards.g.Graveshifter.class));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
package org.mage.test.cards.single.mh3;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class GluttonousHellkiteTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_CastWithoutSac_X0() {
|
||||||
|
// When you cast this spell, each player sacrifices X creatures. Gluttonous Hellkite enters the battlefield
|
||||||
|
// with two +1/+1 counters on it for each creature sacrificed this way.
|
||||||
|
addCard(Zone.HAND, playerA, "Gluttonous Hellkite", 1); // {X}{X}{B}{R}{G}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gluttonous Hellkite");
|
||||||
|
setChoice(playerA, "X=0");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Gluttonous Hellkite", 1);
|
||||||
|
assertCounterCount(playerA, "Gluttonous Hellkite", CounterType.P1P1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_CastWithoutSac_NothingToSac() {
|
||||||
|
// When you cast this spell, each player sacrifices X creatures. Gluttonous Hellkite enters the battlefield
|
||||||
|
// with two +1/+1 counters on it for each creature sacrificed this way.
|
||||||
|
addCard(Zone.HAND, playerA, "Gluttonous Hellkite", 1); // {X}{X}{B}{R}{G}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1 * 2); // fox X
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gluttonous Hellkite");
|
||||||
|
setChoice(playerA, "X=1");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Gluttonous Hellkite", 1);
|
||||||
|
assertCounterCount(playerA, "Gluttonous Hellkite", CounterType.P1P1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_CastWithoutSac_CounterTrigger() {
|
||||||
|
// When you cast this spell, each player sacrifices X creatures. Gluttonous Hellkite enters the battlefield
|
||||||
|
// with two +1/+1 counters on it for each creature sacrificed this way.
|
||||||
|
addCard(Zone.HAND, playerA, "Gluttonous Hellkite", 1); // {X}{X}{B}{R}{G}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1 * 2); // fox X
|
||||||
|
//
|
||||||
|
// Ultimate Sacrifice -- {1}{U}, Sacrifice Adric: Counter target activated or triggered ability.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Adric, Mathematical Genius", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
|
||||||
|
//
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton", 1);
|
||||||
|
|
||||||
|
// cast with sac, but B counter it
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gluttonous Hellkite");
|
||||||
|
setChoice(playerA, "X=1");
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "<i>Ultimate Sacrifice</i>");
|
||||||
|
addTarget(playerB, "stack ability (When you cast this spell, each player sacrifices"); // counter sac
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
// no sac due counter
|
||||||
|
assertPermanentCount(playerA, "Gluttonous Hellkite", 1);
|
||||||
|
assertCounterCount(playerA, "Gluttonous Hellkite", CounterType.P1P1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_CastWithSac_LackingToSac() {
|
||||||
|
// When you cast this spell, each player sacrifices X creatures. Gluttonous Hellkite enters the battlefield
|
||||||
|
// with two +1/+1 counters on it for each creature sacrificed this way.
|
||||||
|
addCard(Zone.HAND, playerA, "Gluttonous Hellkite", 1); // {X}{X}{B}{R}{G}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2 * 2); // fox X
|
||||||
|
//
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton", 1);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gluttonous Hellkite");
|
||||||
|
setChoice(playerA, "X=2");
|
||||||
|
setChoice(playerA, "Balduvian Bears"); // sac
|
||||||
|
setChoice(playerB, "Augmenting Automaton"); // sac
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Gluttonous Hellkite", 1);
|
||||||
|
assertCounterCount(playerA, "Gluttonous Hellkite", CounterType.P1P1, 2 + 2); // bear from A + aug from B
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_CastWithSac_SacFullAndBlink() {
|
||||||
|
addCustomEffect_BlinkTarget(playerA);
|
||||||
|
|
||||||
|
// When you cast this spell, each player sacrifices X creatures. Gluttonous Hellkite enters the battlefield
|
||||||
|
// with two +1/+1 counters on it for each creature sacrificed this way.
|
||||||
|
addCard(Zone.HAND, playerA, "Gluttonous Hellkite", 1); // {X}{X}{B}{R}{G}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2 * 3); // fox X
|
||||||
|
//
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton", 2);
|
||||||
|
|
||||||
|
// first cast with counters
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gluttonous Hellkite");
|
||||||
|
setChoice(playerA, "X=3");
|
||||||
|
setChoice(playerB, "Balduvian Bears", 2); // sac
|
||||||
|
setChoice(playerB, "Augmenting Automaton", 1); // sac
|
||||||
|
|
||||||
|
// blinked without counters
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
checkPermanentCount("before blink", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gluttonous Hellkite", 1);
|
||||||
|
checkPermanentCounters("before blink", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gluttonous Hellkite", CounterType.P1P1, 2 + 2 + 2); // 2x bears and 1x aug from B
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target blink", "Gluttonous Hellkite");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Gluttonous Hellkite", 1);
|
||||||
|
assertCounterCount(playerA, "Gluttonous Hellkite", CounterType.P1P1, 0); // 0 after blink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,12 +12,10 @@ import mage.players.Player;
|
||||||
import mage.target.common.TargetSacrifice;
|
import mage.target.common.TargetSacrifice;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||||
*/
|
*/
|
||||||
public class SacrificeAllEffect extends OneShotEffect {
|
public class SacrificeAllEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
|
@ -25,6 +23,8 @@ public class SacrificeAllEffect extends OneShotEffect {
|
||||||
private final FilterPermanent filter;
|
private final FilterPermanent filter;
|
||||||
private final boolean onlyOpponents;
|
private final boolean onlyOpponents;
|
||||||
|
|
||||||
|
private static final String VALUE_KEY = "sacrificeAllEffect_permanentsList";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each player sacrifices a permanent
|
* Each player sacrifices a permanent
|
||||||
*
|
*
|
||||||
|
|
@ -52,9 +52,6 @@ public class SacrificeAllEffect extends OneShotEffect {
|
||||||
this(amount, filter, false);
|
this(amount, filter, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal use for this and SacrificeOpponentsEffect
|
|
||||||
*/
|
|
||||||
protected SacrificeAllEffect(DynamicValue amount, FilterPermanent filter, boolean onlyOpponents) {
|
protected SacrificeAllEffect(DynamicValue amount, FilterPermanent filter, boolean onlyOpponents) {
|
||||||
super(Outcome.Sacrifice);
|
super(Outcome.Sacrifice);
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
|
|
@ -99,15 +96,32 @@ public class SacrificeAllEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
perms.addAll(target.getTargets());
|
perms.addAll(target.getTargets());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Permanent> sacraficedPermanents = new ArrayList<>();
|
||||||
for (UUID permID : perms) {
|
for (UUID permID : perms) {
|
||||||
Permanent permanent = game.getPermanent(permID);
|
Permanent permanent = game.getPermanent(permID);
|
||||||
if (permanent != null) {
|
if (permanent != null && permanent.sacrifice(source, game)) {
|
||||||
permanent.sacrifice(source, game);
|
sacraficedPermanents.add(permanent.copy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
saveSacrificedPermanentsList(source.getSourceId(), game, sacraficedPermanents);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void saveSacrificedPermanentsList(UUID sourceObjectId, Game game, List<Permanent> list) {
|
||||||
|
game.getState().setValue(CardUtil.getCardZoneString(VALUE_KEY, sourceObjectId, game), list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get detailed list of sacrificed permanents
|
||||||
|
*
|
||||||
|
* @param previous if you need to look in detailed list on battlefield, then use previous param to find data from a stack moment
|
||||||
|
*/
|
||||||
|
public static List<Permanent> getSacrificedPermanentsList(UUID sourceObjectId, Game game, boolean previous) {
|
||||||
|
return (List<Permanent>) game.getState().getValue(CardUtil.getCardZoneString(VALUE_KEY, sourceObjectId, game, previous));
|
||||||
|
}
|
||||||
|
|
||||||
private void setText() {
|
private void setText() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(onlyOpponents ? "each opponent sacrifices " : "each player sacrifices ");
|
sb.append(onlyOpponents ? "each opponent sacrifices " : "each player sacrifices ");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue