forked from External/mage
implement [VIS] Pygmy Hippo
This commit is contained in:
parent
2a6b053e17
commit
f08d5acb30
6 changed files with 281 additions and 93 deletions
|
|
@ -1,25 +1,20 @@
|
|||
package mage.cards.d;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.abilities.effects.common.TargetPlayerActivatesAllManaAbilitiesEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.ManaPoolItem;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author L_J
|
||||
|
|
@ -46,9 +41,7 @@ public final class DrainPower extends CardImpl {
|
|||
|
||||
class DrainPowerEffect extends OneShotEffect {
|
||||
|
||||
private static final FilterLandPermanent filter = new FilterLandPermanent();
|
||||
|
||||
public DrainPowerEffect() {
|
||||
DrainPowerEffect() {
|
||||
super(Outcome.PutManaInPool);
|
||||
this.staticText = "Target player activates a mana ability of each land they control. Then that player loses all unspent mana and you add the mana lost this way";
|
||||
}
|
||||
|
|
@ -64,89 +57,27 @@ class DrainPowerEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Player targetPlayer = game.getPlayer(source.getFirstTarget());
|
||||
if (targetPlayer != null) {
|
||||
List<Permanent> ignorePermanents = new ArrayList<>();
|
||||
Map<Permanent, List<ActivatedManaAbilityImpl>> manaAbilitiesMap = new HashMap<>();
|
||||
TargetPermanent target = null;
|
||||
if (targetPlayer == null) {
|
||||
return false;
|
||||
}
|
||||
new TargetPlayerActivatesAllManaAbilitiesEffect().setTargetPointer(this.getTargetPointer().copy())
|
||||
.apply(game, source);
|
||||
|
||||
while (true) {
|
||||
targetPlayer.setPayManaMode(true);
|
||||
manaAbilitiesMap.clear();
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, targetPlayer.getId(), game)) {
|
||||
if (!ignorePermanents.contains(permanent)) {
|
||||
List<ActivatedManaAbilityImpl> manaAbilities = new ArrayList<>();
|
||||
abilitySearch:
|
||||
for (Ability ability : permanent.getAbilities()) {
|
||||
if (AbilityType.ACTIVATED_MANA.equals(ability.getAbilityType())) {
|
||||
ActivatedManaAbilityImpl manaAbility = (ActivatedManaAbilityImpl) ability;
|
||||
if (manaAbility.canActivate(targetPlayer.getId(), game).canActivate()) {
|
||||
// canActivate can't check for mana abilities that require a mana cost, if the payment isn't possible (Cabal Coffers etc)
|
||||
// so it's necessary to filter them out manually - might be buggy in some fringe cases
|
||||
for (ManaCost manaCost : manaAbility.getManaCosts()) {
|
||||
if (!targetPlayer.getManaPool().getMana().includesMana(manaCost.getMana())) {
|
||||
continue abilitySearch;
|
||||
}
|
||||
}
|
||||
manaAbilities.add(manaAbility);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!manaAbilities.isEmpty()) {
|
||||
manaAbilitiesMap.put(permanent, manaAbilities);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (manaAbilitiesMap.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
List<Permanent> permList = new ArrayList<>(manaAbilitiesMap.keySet());
|
||||
Permanent permanent;
|
||||
if (permList.size() > 1 || target != null) {
|
||||
FilterLandPermanent filter2 = new FilterLandPermanent("land you control to tap for mana (remaining: " + permList.size() + ')');
|
||||
filter2.add(new PermanentReferenceInCollectionPredicate(permList, game));
|
||||
target = new TargetPermanent(1, 1, filter2, true);
|
||||
while (!target.isChosen(game) && target.canChoose(targetPlayer.getId(), source, game) && targetPlayer.canRespond()) {
|
||||
targetPlayer.chooseTarget(Outcome.Neutral, target, source, game);
|
||||
}
|
||||
permanent = game.getPermanent(target.getFirstTarget());
|
||||
} else {
|
||||
permanent = permList.get(0);
|
||||
}
|
||||
if (permanent != null) {
|
||||
int i = 0;
|
||||
for (ActivatedManaAbilityImpl manaAbility : manaAbilitiesMap.get(permanent)) {
|
||||
i++;
|
||||
if (manaAbilitiesMap.get(permanent).size() <= i
|
||||
|| targetPlayer.chooseUse(Outcome.Neutral, "Activate mana ability \"" + manaAbility.getRule() + "\" of " + permanent.getLogName()
|
||||
+ "? (Choose \"no\" to activate next mana ability)", source, game)) {
|
||||
boolean originalCanUndo = manaAbility.isUndoPossible();
|
||||
manaAbility.setUndoPossible(false); // prevents being able to undo Drain Power
|
||||
if (targetPlayer.activateAbility(manaAbility, game)) {
|
||||
ignorePermanents.add(permanent);
|
||||
}
|
||||
manaAbility.setUndoPossible(originalCanUndo); // resets undoPossible to its original state
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
targetPlayer.setPayManaMode(false);
|
||||
|
||||
// 106.12. One card (Drain Power) causes one player to lose unspent mana and another to add “the mana lost this way.” (Note that these may be the same player.)
|
||||
// This empties the former player's mana pool and causes the mana emptied this way to be put into the latter player's mana pool. Which permanents, spells, and/or
|
||||
// abilities produced that mana are unchanged, as are any restrictions or additional effects associated with any of that mana.
|
||||
List<ManaPoolItem> manaItems = targetPlayer.getManaPool().getManaItems();
|
||||
targetPlayer.getManaPool().emptyPool(game);
|
||||
for (ManaPoolItem manaPoolItem : manaItems) {
|
||||
controller.getManaPool().addMana(
|
||||
manaPoolItem.isConditional() ? manaPoolItem.getConditionalMana() : manaPoolItem.getMana(),
|
||||
game, source, Duration.EndOfTurn.equals(manaPoolItem.getDuration()));
|
||||
}
|
||||
// 106.12. One card (Drain Power) causes one player to lose unspent mana and another to add “the mana lost this way.” (Note that these may be the same player.)
|
||||
// This empties the former player's mana pool and causes the mana emptied this way to be put into the latter player's mana pool. Which permanents, spells, and/or
|
||||
// abilities produced that mana are unchanged, as are any restrictions or additional effects associated with any of that mana.
|
||||
List<ManaPoolItem> manaItems = targetPlayer.getManaPool().getManaItems();
|
||||
targetPlayer.getManaPool().emptyPool(game);
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
for (ManaPoolItem manaPoolItem : manaItems) {
|
||||
controller.getManaPool().addMana(
|
||||
manaPoolItem.isConditional() ? manaPoolItem.getConditionalMana() : manaPoolItem.getMana(),
|
||||
game, source, Duration.EndOfTurn.equals(manaPoolItem.getDuration()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
88
Mage.Sets/src/mage/cards/p/PygmyHippo.java
Normal file
88
Mage.Sets/src/mage/cards/p/PygmyHippo.java
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package mage.cards.p;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.DelayedTriggeredAbility;
|
||||
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
|
||||
import mage.abilities.common.delayed.AtTheBeginOfMainPhaseDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.TargetPlayerActivatesAllManaAbilitiesEffect;
|
||||
import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect;
|
||||
import mage.abilities.effects.mana.AddManaToManaPoolSourceControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public final class PygmyHippo extends CardImpl {
|
||||
|
||||
public PygmyHippo(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}");
|
||||
|
||||
this.subtype.add(SubType.HIPPO);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// Whenever Pygmy Hippo attacks and isn't blocked, you may have defending player activate a mana ability of each land they control and lose all unspent mana. If you do, Pygmy Hippo assigns no combat damage this turn and at the beginning of your next main phase this turn, you add an amount of {C} equal to the amount of mana that player lost this way.
|
||||
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new PygmyHippoEffect(), true, true));
|
||||
}
|
||||
|
||||
private PygmyHippo(final PygmyHippo card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PygmyHippo copy() {
|
||||
return new PygmyHippo(this);
|
||||
}
|
||||
}
|
||||
|
||||
class PygmyHippoEffect extends OneShotEffect {
|
||||
|
||||
PygmyHippoEffect() {
|
||||
super(Outcome.PutManaInPool);
|
||||
this.staticText = "you may have defending player activate a mana ability of each land they control" +
|
||||
" and lose all unspent mana. If you do, {this} assigns no combat damage this turn" +
|
||||
" and at the beginning of your next main phase this turn, you add an amount of {C} equal to" +
|
||||
" the amount of mana that player lost this way";
|
||||
}
|
||||
|
||||
private PygmyHippoEffect(final PygmyHippoEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PygmyHippoEffect copy() {
|
||||
return new PygmyHippoEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
if (targetPlayer == null) {
|
||||
return false;
|
||||
}
|
||||
new TargetPlayerActivatesAllManaAbilitiesEffect().setTargetPointer(this.getTargetPointer().copy())
|
||||
.apply(game, source);
|
||||
int amountToAdd = targetPlayer.getManaPool().count();
|
||||
targetPlayer.getManaPool().emptyPool(game);
|
||||
|
||||
game.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true), source);
|
||||
|
||||
if (amountToAdd > 0) {
|
||||
DelayedTriggeredAbility delayed = new AtTheBeginOfMainPhaseDelayedTriggeredAbility(
|
||||
new AddManaToManaPoolSourceControllerEffect(new Mana(ManaType.COLORLESS, amountToAdd)),
|
||||
false, TargetController.YOU,
|
||||
AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN);
|
||||
game.addDelayedTriggeredAbility(delayed, source);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -126,6 +126,7 @@ public final class Visions extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Phyrexian Walker", 152, Rarity.COMMON, mage.cards.p.PhyrexianWalker.class));
|
||||
cards.add(new SetCardInfo("Pillar Tombs of Aku", 67, Rarity.RARE, mage.cards.p.PillarTombsOfAku.class));
|
||||
cards.add(new SetCardInfo("Prosperity", 40, Rarity.UNCOMMON, mage.cards.p.Prosperity.class));
|
||||
cards.add(new SetCardInfo("Pygmy Hippo", 133, Rarity.RARE, mage.cards.p.PygmyHippo.class));
|
||||
cards.add(new SetCardInfo("Python", 68, Rarity.COMMON, mage.cards.p.Python.class));
|
||||
cards.add(new SetCardInfo("Quicksand", 166, Rarity.UNCOMMON, mage.cards.q.Quicksand.class));
|
||||
cards.add(new SetCardInfo("Quirion Druid", 116, Rarity.RARE, mage.cards.q.QuirionDruid.class));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
package org.mage.test.cards.single.vis;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class PygmyHippoTest extends CardTestPlayerBase {
|
||||
|
||||
/*
|
||||
* Whenever Pygmy Hippo attacks and isn’t blocked, you may have defending player activate a mana ability of
|
||||
* each land they control and lose all unspent mana. If you do, Pygmy Hippo assigns no combat damage this turn
|
||||
* and at the beginning of your next main phase this turn, you add an amount of {C} equal to the amount of mana
|
||||
* that player lost this way.
|
||||
*/
|
||||
private static final String hippo = "Pygmy Hippo"; // {G}{U} 2/2
|
||||
private static final String sentinel = "Gilded Sentinel"; // {4} 3/3
|
||||
|
||||
@Test
|
||||
public void testPygmyHippo() {
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, hippo);
|
||||
addCard(Zone.HAND, playerA, sentinel);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 4);
|
||||
|
||||
attack(1, playerA, hippo, playerB);
|
||||
setChoice(playerA, true); // yes to ability
|
||||
setChoice(playerB, "Swamp"); // which land to tap
|
||||
setChoice(playerB, "Swamp"); // which land to tap
|
||||
setChoice(playerB, "Swamp"); // which land to tap
|
||||
setChoice(playerB, "Swamp"); // which land to tap
|
||||
|
||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, sentinel); // with four gained mana
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 20); // no combat damage assigned
|
||||
assertPowerToughness(playerA, hippo, 2, 2);
|
||||
assertPowerToughness(playerA, sentinel, 3, 3);
|
||||
assertTappedCount("Swamp", true, 4);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ public class AtTheBeginOfMainPhaseDelayedTriggeredAbility extends DelayedTrigger
|
|||
public enum PhaseSelection {
|
||||
|
||||
NEXT_PRECOMBAT_MAIN("next precombat main phase"),
|
||||
NEXT_POSTCOMAT_MAIN("next postcombat main phase"),
|
||||
NEXT_POSTCOMBAT_MAIN("next postcombat main phase"),
|
||||
NEXT_MAIN("next main phase"),
|
||||
NEXT_MAIN_THIS_TURN("next main phase this turn", Duration.EndOfTurn);
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ public class AtTheBeginOfMainPhaseDelayedTriggeredAbility extends DelayedTrigger
|
|||
case NEXT_MAIN:
|
||||
case NEXT_MAIN_THIS_TURN:
|
||||
return EventType.PRECOMBAT_MAIN_PHASE_PRE == eventType || EventType.POSTCOMBAT_MAIN_PHASE_PRE == eventType;
|
||||
case NEXT_POSTCOMAT_MAIN:
|
||||
case NEXT_POSTCOMBAT_MAIN:
|
||||
return EventType.POSTCOMBAT_MAIN_PHASE_PRE == eventType;
|
||||
case NEXT_PRECOMBAT_MAIN:
|
||||
return EventType.PRECOMBAT_MAIN_PHASE_PRE == eventType;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author L_J
|
||||
*/
|
||||
public class TargetPlayerActivatesAllManaAbilitiesEffect extends OneShotEffect {
|
||||
|
||||
/**
|
||||
* For use in Drain Power and Pygmy Hippo
|
||||
*/
|
||||
public TargetPlayerActivatesAllManaAbilitiesEffect() {
|
||||
super(Outcome.Detriment);
|
||||
}
|
||||
|
||||
protected TargetPlayerActivatesAllManaAbilitiesEffect(final TargetPlayerActivatesAllManaAbilitiesEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetPlayerActivatesAllManaAbilitiesEffect copy() {
|
||||
return new TargetPlayerActivatesAllManaAbilitiesEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
if (targetPlayer == null) {
|
||||
return false;
|
||||
}
|
||||
List<Permanent> ignorePermanents = new ArrayList<>();
|
||||
Map<Permanent, List<ActivatedManaAbilityImpl>> manaAbilitiesMap = new HashMap<>();
|
||||
TargetPermanent target = null;
|
||||
|
||||
while (targetPlayer.canRespond()) {
|
||||
targetPlayer.setPayManaMode(true);
|
||||
manaAbilitiesMap.clear();
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_LAND, targetPlayer.getId(), game)) {
|
||||
if (!ignorePermanents.contains(permanent)) {
|
||||
List<ActivatedManaAbilityImpl> manaAbilities = new ArrayList<>();
|
||||
abilitySearch:
|
||||
for (Ability ability : permanent.getAbilities()) {
|
||||
if (AbilityType.ACTIVATED_MANA.equals(ability.getAbilityType())) {
|
||||
ActivatedManaAbilityImpl manaAbility = (ActivatedManaAbilityImpl) ability;
|
||||
if (manaAbility.canActivate(targetPlayer.getId(), game).canActivate()) {
|
||||
// canActivate can't check for mana abilities that require a mana cost, if the payment isn't possible (Cabal Coffers etc)
|
||||
// so it's necessary to filter them out manually - might be buggy in some fringe cases
|
||||
for (ManaCost manaCost : manaAbility.getManaCosts()) {
|
||||
if (!targetPlayer.getManaPool().getMana().includesMana(manaCost.getMana())) {
|
||||
continue abilitySearch;
|
||||
}
|
||||
}
|
||||
manaAbilities.add(manaAbility);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!manaAbilities.isEmpty()) {
|
||||
manaAbilitiesMap.put(permanent, manaAbilities);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (manaAbilitiesMap.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
List<Permanent> permList = new ArrayList<>(manaAbilitiesMap.keySet());
|
||||
Permanent permanent;
|
||||
if (permList.size() > 1 || target != null) {
|
||||
FilterLandPermanent filter2 = new FilterLandPermanent("land you control to tap for mana (remaining: " + permList.size() + ')');
|
||||
filter2.add(new PermanentReferenceInCollectionPredicate(permList, game));
|
||||
target = new TargetPermanent(1, 1, filter2, true);
|
||||
while (!target.isChosen(game) && target.canChoose(targetPlayer.getId(), source, game) && targetPlayer.canRespond()) {
|
||||
targetPlayer.choose(Outcome.Neutral, target, source, game);
|
||||
}
|
||||
permanent = game.getPermanent(target.getFirstTarget());
|
||||
} else {
|
||||
permanent = permList.get(0);
|
||||
}
|
||||
if (permanent != null) {
|
||||
int i = 0;
|
||||
for (ActivatedManaAbilityImpl manaAbility : manaAbilitiesMap.get(permanent)) {
|
||||
i++;
|
||||
if (manaAbilitiesMap.get(permanent).size() <= i
|
||||
|| targetPlayer.chooseUse(Outcome.Neutral, "Activate mana ability \"" + manaAbility.getRule() + "\" of " + permanent.getLogName()
|
||||
+ "? (Choose \"no\" to activate next mana ability)", source, game)) {
|
||||
boolean originalCanUndo = manaAbility.isUndoPossible();
|
||||
manaAbility.setUndoPossible(false); // prevents being able to undo Drain Power
|
||||
if (targetPlayer.activateAbility(manaAbility, game)) {
|
||||
ignorePermanents.add(permanent);
|
||||
}
|
||||
manaAbility.setUndoPossible(originalCanUndo); // resets undoPossible to its original state
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
targetPlayer.setPayManaMode(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue