forked from External/mage
[OTC] Implement Cataclysmic Prospecting
This commit is contained in:
parent
16b832198a
commit
e217b3d0d8
4 changed files with 211 additions and 1 deletions
|
|
@ -99,10 +99,11 @@ enum BatColonyValue implements DynamicValue {
|
|||
|
||||
/**
|
||||
* Inspired by {@link mage.watchers.common.ManaPaidSourceWatcher}
|
||||
* If more cards like Bat Colony care for mana spent by Caves in the future, best to refactor the tracking there.
|
||||
* If more cards like Bat Colony care for mana produced by Caves in the future, best to refactor the tracking there.
|
||||
* For now the assumption is that it is a 1of, so don't want to track it in any game.
|
||||
*/
|
||||
class BatColonyWatcher extends Watcher {
|
||||
|
||||
private static final class CaveManaPaidTracker implements Serializable, Copyable<CaveManaPaidTracker> {
|
||||
private int caveMana = 0;
|
||||
|
||||
|
|
|
|||
150
Mage.Sets/src/mage/cards/c/CataclysmicProspecting.java
Normal file
150
Mage.Sets/src/mage/cards/c/CataclysmicProspecting.java
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.abilities.effects.common.DamageAllEffect;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.ValueHint;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.WatcherScope;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ManaPaidEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.token.TreasureToken;
|
||||
import mage.util.Copyable;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public final class CataclysmicProspecting extends CardImpl {
|
||||
|
||||
private static final Hint hint = new ValueHint("Mana spent from a Desert", CataclysmicProspectingValue.instance);
|
||||
|
||||
public CataclysmicProspecting(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}{R}");
|
||||
|
||||
// Cataclysmic Prospecting deals X damage to each creature. For each mana from a Desert spent to cast this spell, create a tapped Treasure token.
|
||||
this.getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.REGULAR, StaticFilters.FILTER_PERMANENT_CREATURE));
|
||||
this.getSpellAbility().addEffect(new CreateTokenEffect(new TreasureToken(), CataclysmicProspectingValue.instance, true, false));
|
||||
this.getSpellAbility().addWatcher(new CataclysmicProspectingWatcher());
|
||||
this.getSpellAbility().addHint(hint);
|
||||
}
|
||||
|
||||
private CataclysmicProspecting(final CataclysmicProspecting card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CataclysmicProspecting copy() {
|
||||
return new CataclysmicProspecting(this);
|
||||
}
|
||||
}
|
||||
|
||||
enum CataclysmicProspectingValue implements DynamicValue {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
return sourceAbility == null ? 0 : CataclysmicProspectingWatcher.getDesertsAmount(sourceAbility.getSourceId(), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CataclysmicProspectingValue copy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "mana from a Desert spent to cast it";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspired by {@link mage.watchers.common.ManaPaidSourceWatcher}
|
||||
* If more cards like Cataclysmic care for mana produced by Deserts in the future, best to refactor the tracking there.
|
||||
* For now the assumption is that it is a 1of, so don't want to track it in any game.
|
||||
*/
|
||||
class CataclysmicProspectingWatcher extends Watcher {
|
||||
|
||||
private static final class DesertManaPaidTracker implements Serializable, Copyable<DesertManaPaidTracker> {
|
||||
private int desertMana = 0;
|
||||
|
||||
private DesertManaPaidTracker() {
|
||||
super();
|
||||
}
|
||||
|
||||
private DesertManaPaidTracker(final DesertManaPaidTracker tracker) {
|
||||
this.desertMana = tracker.desertMana;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DesertManaPaidTracker copy() {
|
||||
return new DesertManaPaidTracker(this);
|
||||
}
|
||||
|
||||
private void increment(MageObject sourceObject, Game game) {
|
||||
if (sourceObject != null && sourceObject.hasSubtype(SubType.DESERT, game)) {
|
||||
desertMana++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final DesertManaPaidTracker emptyTracker = new DesertManaPaidTracker();
|
||||
private final Map<UUID, DesertManaPaidTracker> manaMap = new HashMap<>();
|
||||
|
||||
public CataclysmicProspectingWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
switch (event.getType()) {
|
||||
case ZONE_CHANGE:
|
||||
if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD
|
||||
// Bug #9943 Memory Deluge cast from graveyard during the same turn
|
||||
|| ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) {
|
||||
manaMap.remove(event.getTargetId());
|
||||
}
|
||||
return;
|
||||
case MANA_PAID:
|
||||
ManaPaidEvent manaEvent = (ManaPaidEvent) event;
|
||||
manaMap.computeIfAbsent(manaEvent.getTargetId(), x -> new DesertManaPaidTracker())
|
||||
.increment(manaEvent.getSourceObject(), game);
|
||||
manaMap.computeIfAbsent(manaEvent.getSourcePaidId(), x -> new DesertManaPaidTracker())
|
||||
.increment(manaEvent.getSourceObject(), game);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
manaMap.clear();
|
||||
}
|
||||
|
||||
public static int getDesertsAmount(UUID sourceId, Game game) {
|
||||
CataclysmicProspectingWatcher watcher = game.getState().getWatcher(CataclysmicProspectingWatcher.class);
|
||||
return watcher == null ? 0 : watcher.manaMap.getOrDefault(sourceId, emptyTracker).desertMana;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ public final class OutlawsOfThunderJunctionCommander extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Angel of Indemnity", 45, Rarity.RARE, mage.cards.a.AngelOfIndemnity.class));
|
||||
cards.add(new SetCardInfo("Angelic Sell-Sword", 10, Rarity.RARE, mage.cards.a.AngelicSellSword.class));
|
||||
cards.add(new SetCardInfo("Back in Town", 18, Rarity.RARE, mage.cards.b.BackInTown.class));
|
||||
cards.add(new SetCardInfo("Cataclysmic Prospecting", 24, Rarity.RARE, mage.cards.c.CataclysmicProspecting.class));
|
||||
cards.add(new SetCardInfo("Charred Graverobber", 19, Rarity.RARE, mage.cards.c.CharredGraverobber.class));
|
||||
cards.add(new SetCardInfo("Elemental Eruption", 27, Rarity.RARE, mage.cards.e.ElementalEruption.class));
|
||||
cards.add(new SetCardInfo("Embrace the Unknown", 64, Rarity.RARE, mage.cards.e.EmbraceTheUnknown.class));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
package org.mage.test.cards.single.otc;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class CataclysmicProspectingTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.c.CataclysmicProspecting Cataclysmic Prospecting} {X}{R}{R}
|
||||
* Sorcery
|
||||
* Cataclysmic Prospecting deals X damage to each creature. For each mana from a Desert spent to cast this spell, create a tapped Treasure token.
|
||||
*/
|
||||
private static final String prospecting = "Cataclysmic Prospecting";
|
||||
|
||||
@Test
|
||||
public void test_Two_Desert() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Indomitable Ancients"); // 2/10
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Hostile Desert", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
addCard(Zone.HAND, playerA, prospecting);
|
||||
|
||||
setChoice(playerA, "X=5");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, prospecting);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, prospecting, 1);
|
||||
assertDamageReceived(playerB, "Indomitable Ancients", 5);
|
||||
assertPermanentCount(playerA, "Treasure Token", 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Zero_Desert() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Indomitable Ancients"); // 2/10
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 7);
|
||||
addCard(Zone.HAND, playerA, prospecting);
|
||||
|
||||
setChoice(playerA, "X=5");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, prospecting);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, prospecting, 1);
|
||||
assertDamageReceived(playerB, "Indomitable Ancients", 5);
|
||||
assertPermanentCount(playerA, "Treasure Token", 0);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue