mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
[DFT] Implement Elvish Refueler (#13392)
This commit is contained in:
parent
cd8cb6afe5
commit
9aaad5193f
5 changed files with 232 additions and 1 deletions
151
Mage.Sets/src/mage/cards/e/ElvishRefueler.java
Normal file
151
Mage.Sets/src/mage/cards/e/ElvishRefueler.java
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
package mage.cards.e;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.decorator.ConditionalAsThoughEffect;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.constants.*;
|
||||
import mage.abilities.keyword.ExhaustAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jmlundeen
|
||||
*/
|
||||
public final class ElvishRefueler extends CardImpl {
|
||||
private static final FilterPermanent filter = new FilterPermanent();
|
||||
private static final Hint hint = new ConditionHint(ActivatedExhaustCondition.instance,
|
||||
"You haven't activated an exhaust ability this turn",
|
||||
null,
|
||||
"You have activated an exhaust ability this turn",
|
||||
null,
|
||||
true);
|
||||
|
||||
static {
|
||||
filter.add(TargetController.YOU.getControllerPredicate());
|
||||
}
|
||||
|
||||
public ElvishRefueler(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");
|
||||
|
||||
this.subtype.add(SubType.ELF);
|
||||
this.subtype.add(SubType.DRUID);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// During your turn, as long as you haven't activated an exhaust ability this turn, you may activate exhaust abilities as though they haven't been activated.
|
||||
this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect(
|
||||
new ElvishRefuelerEffect(filter), ActivatedExhaustCondition.instance)
|
||||
.setText("During your turn, as long as you haven't activated an exhaust ability this turn, " +
|
||||
"you may activate exhaust abilities as though they haven't been activated")
|
||||
).addHint(hint), new ElvishRefuelerWatcher());
|
||||
|
||||
// Exhaust -- {1}{G}: Put a +1/+1 counter on this creature.
|
||||
this.addAbility(new ExhaustAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{1}{G}")));
|
||||
|
||||
}
|
||||
|
||||
private ElvishRefueler(final ElvishRefueler card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElvishRefueler copy() {
|
||||
return new ElvishRefueler(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum ActivatedExhaustCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
ElvishRefuelerWatcher watcher = game.getState().getWatcher(ElvishRefuelerWatcher.class);
|
||||
return watcher != null && !watcher.checkActivatedExhaust(source.getControllerId());
|
||||
}
|
||||
}
|
||||
|
||||
class ElvishRefuelerWatcher extends Watcher {
|
||||
|
||||
private final Map<UUID, Boolean> activatedExhaustAbilities = new HashMap<>();
|
||||
|
||||
public ElvishRefuelerWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() != GameEvent.EventType.ACTIVATED_ABILITY) {
|
||||
return;
|
||||
}
|
||||
StackObject stackObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackObject != null && stackObject.getStackAbility() instanceof ExhaustAbility) {
|
||||
activatedExhaustAbilities.put(event.getPlayerId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
activatedExhaustAbilities.clear();
|
||||
}
|
||||
|
||||
public boolean checkActivatedExhaust(UUID playerId) {
|
||||
return activatedExhaustAbilities.getOrDefault(playerId, false);
|
||||
}
|
||||
}
|
||||
|
||||
class ElvishRefuelerEffect extends AsThoughEffectImpl {
|
||||
private final FilterPermanent filter;
|
||||
|
||||
ElvishRefuelerEffect(FilterPermanent filter) {
|
||||
super(AsThoughEffectType.ALLOW_EXHAUST_PER_TURN, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
this.filter = filter;
|
||||
staticText = "During your turn, as long as you haven't activated an exhaust ability this turn, " +
|
||||
"you may activate exhaust abilities as though they haven't been activated";
|
||||
}
|
||||
|
||||
ElvishRefuelerEffect(final ElvishRefuelerEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElvishRefuelerEffect copy() {
|
||||
return new ElvishRefuelerEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
ElvishRefuelerWatcher watcher = game.getState().getWatcher(ElvishRefuelerWatcher.class);
|
||||
if (!game.isActivePlayer(affectedControllerId) || watcher == null || watcher.checkActivatedExhaust(affectedControllerId)) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(objectId);
|
||||
return filter.match(permanent, source.getControllerId(), source, game);
|
||||
}
|
||||
}
|
||||
|
|
@ -107,6 +107,7 @@ public final class Aetherdrift extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Dune Drifter", 200, Rarity.UNCOMMON, mage.cards.d.DuneDrifter.class));
|
||||
cards.add(new SetCardInfo("Dynamite Diver", 123, Rarity.COMMON, mage.cards.d.DynamiteDiver.class));
|
||||
cards.add(new SetCardInfo("Earthrumbler", 160, Rarity.UNCOMMON, mage.cards.e.Earthrumbler.class));
|
||||
cards.add(new SetCardInfo("Elvish Refueler", 161, Rarity.UNCOMMON, mage.cards.e.ElvishRefueler.class));
|
||||
cards.add(new SetCardInfo("Embalmed Ascendant", 201, Rarity.UNCOMMON, mage.cards.e.EmbalmedAscendant.class));
|
||||
cards.add(new SetCardInfo("Endrider Catalyzer", 124, Rarity.COMMON, mage.cards.e.EndriderCatalyzer.class));
|
||||
cards.add(new SetCardInfo("Endrider Spikespitter", 125, Rarity.UNCOMMON, mage.cards.e.EndriderSpikespitter.class));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
package org.mage.test.cards.single.dft;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author jimga150
|
||||
*/
|
||||
public class ElvishRefuelerTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void testExhaustPrevention() {
|
||||
// During your turn, as long as you haven’t activated an exhaust ability this turn,
|
||||
// you may activate exhaust abilities as though they haven’t been activated.
|
||||
String refueler = "Elvish Refueler";
|
||||
addCard(Zone.BATTLEFIELD, playerA, refueler);
|
||||
addCard(Zone.HAND, playerA, refueler);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 7);
|
||||
|
||||
// Should be able to activate refueler's exhaust ability
|
||||
checkPlayableAbility("Should be able to activate exhaust",
|
||||
1, PhaseStep.PRECOMBAT_MAIN, playerA, "Exhaust", true);
|
||||
// Activate refueler's exhaust ability
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Exhaust");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
// Should not be able to activate refueler's exhaust ability
|
||||
checkPlayableAbility("Should not be able to activate exhaust after activating",
|
||||
1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Exhaust", false);
|
||||
// Casting a second refueler should not allow activating the exhaust ability
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, refueler);
|
||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
// Activating second refueler's exhaust ability
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Exhaust");
|
||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
// Should be no exhaust left
|
||||
checkPlayableAbility("All exhausts should be used from both refuelers",
|
||||
1, PhaseStep.END_TURN, playerA, "Exhaust", false);
|
||||
|
||||
// Confirm on opponent's turn that exhaust is still not available
|
||||
checkPlayableAbility("Opponent's turn, effect should not apply",
|
||||
2, PhaseStep.END_TURN, playerA, "Exhaust", false);
|
||||
|
||||
// Should be able to activate refueler's exhaust ability on next turn
|
||||
checkPlayableAbility("Should be able to activate exhaust on our next turn",
|
||||
3, PhaseStep.PRECOMBAT_MAIN, playerA, "Exhaust", true);
|
||||
// Activate refueler's exhaust ability
|
||||
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Exhaust");
|
||||
waitStackResolved(3, PhaseStep.PRECOMBAT_MAIN);
|
||||
// Only one exhaust should have been available
|
||||
checkPlayableAbility("Already activated exhaust, should not be able to activate again",
|
||||
3, PhaseStep.PRECOMBAT_MAIN, playerA, "Exhaust", false);
|
||||
setStopAt(3, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -3,7 +3,9 @@ package mage.abilities.keyword;
|
|||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
|
|
@ -24,6 +26,20 @@ public class ExhaustAbility extends ActivatedAbilityImpl {
|
|||
return new ExhaustAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreActivationsThisTurn(Game game) {
|
||||
ActivationInfo info = getActivationInfo(game);
|
||||
if (info != null && info.totalActivations >= maxActivationsPerGame) {
|
||||
boolean canActivate = !game.getContinuousEffects()
|
||||
.asThough(sourceId, AsThoughEffectType.ALLOW_EXHAUST_PER_TURN, this, controllerId, game)
|
||||
.isEmpty();
|
||||
if (canActivate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.hasMoreActivationsThisTurn(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Exhaust — " + super.getRule() + " <i>(Activate each exhaust ability only once.)</i>";
|
||||
|
|
|
|||
|
|
@ -59,7 +59,10 @@ public enum AsThoughEffectType {
|
|||
//
|
||||
// ALLOW_FORETELL_ANYTIME:
|
||||
// For Cosmos Charger effect
|
||||
ALLOW_FORETELL_ANYTIME;
|
||||
ALLOW_FORETELL_ANYTIME,
|
||||
// ALLOW_EXHAUST_ACTIVE_ABILITY:
|
||||
// Elvish Refueler effect allows Exhaust on your turn as though it hasn't been activated
|
||||
ALLOW_EXHAUST_PER_TURN(true, false);
|
||||
|
||||
private final boolean needAffectedAbility; // mark what AsThough check must be called for specific ability, not full object (example: spell check)
|
||||
private final boolean needPlayCardAbility; // mark what AsThough check must be called for play/cast abilities
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue