forked from External/mage
changes to the way abilities are added to cards
This commit is contained in:
parent
65390e09a6
commit
72ff6f27b3
91 changed files with 2003 additions and 217 deletions
|
|
@ -119,7 +119,7 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl {
|
|||
if (xCost > 0) {
|
||||
Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(xCost)));
|
||||
ability.setRuleVisible(false);
|
||||
card.addAbility(ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
ability.setControllerId(source.getControllerId());
|
||||
ability.setSourceId(card.getId());
|
||||
game.getState().addAbility(ability, source.getSourceId(), card);
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class VarolzTheScarStripedEffect extends ContinuousEffectImpl {
|
|||
ScavengeAbility ability = new ScavengeAbility(new ManaCostsImpl(card.getManaCost().getText()));
|
||||
ability.setSourceId(cardId);
|
||||
ability.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(cardId, ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ class GainAbilitySpellsEffect extends ContinuousEffectImpl {
|
|||
Card card = spell.getCard();
|
||||
if (card != null) {
|
||||
if (!card.getAbilities().contains(ability)) {
|
||||
card.addAbility(ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
SoulfireGrandMasterLeavesStackWatcher watcher = (SoulfireGrandMasterLeavesStackWatcher) game.getState().getWatchers().get("SoulfireGrandMasterLeavesStackWatcher");
|
||||
if (watcher != null) {
|
||||
watcher.addCardId(card.getId());
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class MycosynthGolemEffect extends ReplacementEffectImpl {
|
|||
if (object != null) {
|
||||
Card card = (Card) object;
|
||||
Ability ability = new AffinityForArtifactsAbility();
|
||||
card.addAbility(ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
ability.setControllerId(source.getControllerId());
|
||||
ability.setSourceId(card.getId());
|
||||
game.getState().addAbility(ability, source.getSourceId(), card);
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl {
|
|||
mageObject.getPower().setValue(2);
|
||||
mageObject.getToughness().setValue(2);
|
||||
if (mageObject instanceof Card) {
|
||||
((Card)mageObject).addAbility(FlyingAbility.getInstance());
|
||||
game.getState().addOtherAbility((Card)mageObject, FlyingAbility.getInstance());
|
||||
} else {
|
||||
((Token)mageObject).addAbility(FlyingAbility.getInstance());
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl {
|
|||
mageObject.getPower().setValue(1);
|
||||
mageObject.getToughness().setValue(6);
|
||||
if (mageObject instanceof Card) {
|
||||
((Card)mageObject).addAbility(DefenderAbility.getInstance());
|
||||
game.getState().addOtherAbility((Card)mageObject, DefenderAbility.getInstance());
|
||||
} else {
|
||||
((Token)mageObject).addAbility(DefenderAbility.getInstance());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ class DelayEffect extends OneShotEffect {
|
|||
// If the exiled card leaves exile by another way, the abilites won't be removed from the card
|
||||
Abilities oldAbilities = card.getAbilities().copy();
|
||||
SuspendAbility suspendAbility = new SuspendAbility(3, null, card);
|
||||
card.addAbility(suspendAbility);
|
||||
game.getState().addOtherAbility(card, suspendAbility);
|
||||
|
||||
for (Ability ability :card.getAbilities()) {
|
||||
if (!oldAbilities.contains(ability)) {
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class PastInFlamesEffect extends ContinuousEffectImpl {
|
|||
if (ability != null) {
|
||||
ability.setSourceId(cardId);
|
||||
ability.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(cardId, ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ class SnapcasterMageEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
ability.setSourceId(card.getId());
|
||||
ability.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(card.getId(), ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class ChiefEngineerEffect extends ReplacementEffectImpl {
|
|||
if (object != null) {
|
||||
Card card = (Card) object;
|
||||
Ability ability = new ConvokeAbility();
|
||||
card.addAbility(ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
ability.setControllerId(source.getControllerId());
|
||||
ability.setSourceId(card.getId());
|
||||
game.getState().addAbility(ability, source.getSourceId(), card);
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class GruesomeEncoreEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getFirstTarget());
|
||||
if (card != null) {
|
||||
card.addAbility(HasteAbility.getInstance());
|
||||
game.getState().addOtherAbility(card, HasteAbility.getInstance());
|
||||
card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId());
|
||||
|
||||
ExileTargetEffect exileEffect = new ExileTargetEffect();
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ class PostmortemLungeEffect extends OneShotEffect {
|
|||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
card.addAbility(HasteAbility.getInstance());
|
||||
game.getState().addOtherAbility(card, HasteAbility.getInstance());
|
||||
card.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), source.getControllerId());
|
||||
|
||||
ExileTargetEffect exileEffect = new ExileTargetEffect();
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class RecoupEffect extends ContinuousEffectImpl {
|
|||
FlashbackAbility ability = new FlashbackAbility(card.getManaCost(), TimingRule.SORCERY);
|
||||
ability.setSourceId(card.getId());
|
||||
ability.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(card.getId(), ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,34 +136,20 @@ class PrimalPlasmaReplacementEffect extends ReplacementEffectImpl {
|
|||
}
|
||||
}
|
||||
}
|
||||
MageObject mageObject;
|
||||
if (permanent instanceof PermanentCard) {
|
||||
mageObject = ((PermanentCard) permanent).getCard();
|
||||
} else {
|
||||
mageObject = ((PermanentToken) permanent).getToken();
|
||||
}
|
||||
switch (choice.getChoice()) {
|
||||
case choice33:
|
||||
mageObject.getPower().setValue(3);
|
||||
mageObject.getToughness().setValue(3);
|
||||
permanent.getPower().setValue(3);
|
||||
permanent.getToughness().setValue(3);
|
||||
break;
|
||||
case choice22:
|
||||
mageObject.getPower().setValue(2);
|
||||
mageObject.getToughness().setValue(2);
|
||||
if (mageObject instanceof Card) {
|
||||
((Card)mageObject).addAbility(FlyingAbility.getInstance());
|
||||
} else {
|
||||
((Token)mageObject).addAbility(FlyingAbility.getInstance());
|
||||
}
|
||||
permanent.getPower().setValue(2);
|
||||
permanent.getToughness().setValue(2);
|
||||
permanent.addAbility(FlyingAbility.getInstance(), source.getId(), game);
|
||||
break;
|
||||
case choice16:
|
||||
mageObject.getPower().setValue(1);
|
||||
mageObject.getToughness().setValue(6);
|
||||
if (mageObject instanceof Card) {
|
||||
((Card)mageObject).addAbility(DefenderAbility.getInstance());
|
||||
} else {
|
||||
((Token)mageObject).addAbility(DefenderAbility.getInstance());
|
||||
}
|
||||
permanent.getPower().setValue(1);
|
||||
permanent.getToughness().setValue(6);
|
||||
permanent.addAbility(DefenderAbility.getInstance(), source.getId(), game);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class BeastbreakerOfBalaGed extends LevelerCard {
|
|||
Abilities<Ability> levelAbilities = new AbilitiesImpl<Ability>();
|
||||
levelAbilities.add(TrampleAbility.getInstance());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
// LEVEL 1-3
|
||||
// 4/4
|
||||
new LevelerCardBuilder.LevelAbility(1, 3, new AbilitiesImpl<Ability>(), 4, 4),
|
||||
|
|
@ -71,7 +71,8 @@ public class BeastbreakerOfBalaGed extends LevelerCard {
|
|||
// 4/4
|
||||
// Trample
|
||||
new LevelerCardBuilder.LevelAbility(4, -1, levelAbilities, 6, 6)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(4);
|
||||
}
|
||||
|
||||
public BeastbreakerOfBalaGed(final BeastbreakerOfBalaGed card) {
|
||||
|
|
|
|||
|
|
@ -72,10 +72,11 @@ public class BrimstoneMage extends LevelerCard {
|
|||
ability.addTarget(new TargetCreatureOrPlayer());
|
||||
abilities2.add(ability);
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 2, abilities1, 2, 3),
|
||||
new LevelerCardBuilder.LevelAbility(3, -1, abilities2, 2, 4)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(3);
|
||||
}
|
||||
|
||||
public BrimstoneMage (final BrimstoneMage card) {
|
||||
|
|
|
|||
|
|
@ -59,10 +59,10 @@ public class CaravanEscort extends LevelerCard {
|
|||
this.addAbility(new LevelUpAbility(new ManaCostsImpl("{2}")));
|
||||
|
||||
AbilitiesImpl<Ability> levelAbilities = new AbilitiesImpl<Ability>(FirstStrikeAbility.getInstance());
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 4, new AbilitiesImpl<Ability>(), 2, 2),
|
||||
new LevelerCardBuilder.LevelAbility(5, -1, levelAbilities, 5, 5)
|
||||
);
|
||||
));
|
||||
|
||||
setMaxLevelCounters(5);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class CastThroughTime extends CardImpl {
|
|||
|
||||
// Instant and sorcery spells you control have rebound.
|
||||
// (Exile the spell as it resolves if you cast it from your hand. At the beginning of your next upkeep, you may cast that card from exile without paying its mana cost.)
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainReboundEffect()), new LeavesBattlefieldWatcher());
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainReboundEffect()));
|
||||
}
|
||||
|
||||
public CastThroughTime(final CastThroughTime card) {
|
||||
|
|
@ -131,52 +131,52 @@ class GainReboundEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
}
|
||||
if (!found) {
|
||||
Ability ability = new AttachedReboundAbility();
|
||||
card.addAbility(ability);
|
||||
Ability ability = new ReboundAbility();
|
||||
// card.addAbility(ability);
|
||||
ability.setControllerId(source.getControllerId());
|
||||
ability.setSourceId(card.getId());
|
||||
game.getState().addAbility(ability, card);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AttachedReboundAbility extends ReboundAbility {}
|
||||
//class AttachedReboundAbility extends ReboundAbility {}
|
||||
|
||||
class LeavesBattlefieldWatcher extends Watcher {
|
||||
|
||||
public LeavesBattlefieldWatcher() {
|
||||
super("LeavesBattlefieldWatcher", WatcherScope.CARD);
|
||||
}
|
||||
|
||||
public LeavesBattlefieldWatcher(final LeavesBattlefieldWatcher watcher) {
|
||||
super(watcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent)event;
|
||||
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
|
||||
Player player = game.getPlayer(this.getControllerId());
|
||||
if (player != null) {
|
||||
for (Card card : player.getHand().getCards(CastThroughTime.filter, game)) {
|
||||
Iterator<Ability> it = card.getAbilities().iterator();
|
||||
while (it.hasNext()) {
|
||||
if (it.next() instanceof AttachedReboundAbility) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeavesBattlefieldWatcher copy() {
|
||||
return new LeavesBattlefieldWatcher(this);
|
||||
}
|
||||
|
||||
}
|
||||
//class LeavesBattlefieldWatcher extends Watcher {
|
||||
//
|
||||
// public LeavesBattlefieldWatcher() {
|
||||
// super("LeavesBattlefieldWatcher", WatcherScope.CARD);
|
||||
// }
|
||||
//
|
||||
// public LeavesBattlefieldWatcher(final LeavesBattlefieldWatcher watcher) {
|
||||
// super(watcher);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void watch(GameEvent event, Game game) {
|
||||
// if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) {
|
||||
// ZoneChangeEvent zEvent = (ZoneChangeEvent)event;
|
||||
// if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
|
||||
// Player player = game.getPlayer(this.getControllerId());
|
||||
// if (player != null) {
|
||||
// for (Card card : player.getHand().getCards(CastThroughTime.filter, game)) {
|
||||
// Iterator<Ability> it = card.getAbilities().iterator();
|
||||
// while (it.hasNext()) {
|
||||
// if (it.next() instanceof AttachedReboundAbility) {
|
||||
// it.remove();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public LeavesBattlefieldWatcher copy() {
|
||||
// return new LeavesBattlefieldWatcher(this);
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,10 +78,11 @@ public class CoralhelmCommander extends LevelerCard {
|
|||
abilities2.add(FlyingAbility.getInstance());
|
||||
abilities2.add(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, true)));
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(2, 3, abilities1, 3, 3),
|
||||
new LevelerCardBuilder.LevelAbility(4, -1, abilities2, 4, 4)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(4);
|
||||
}
|
||||
|
||||
public CoralhelmCommander(final CoralhelmCommander card) {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import mage.abilities.effects.common.CopyTargetSpellEffect;
|
|||
import mage.abilities.keyword.LevelUpAbility;
|
||||
import mage.abilities.keyword.LevelerCardBuilder;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.LevelerCard;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
|
|
@ -55,7 +56,7 @@ import mage.target.TargetSpell;
|
|||
*
|
||||
* @author North
|
||||
*/
|
||||
public class EchoMage extends CardImpl {
|
||||
public class EchoMage extends LevelerCard {
|
||||
|
||||
private static final FilterSpell filter = new FilterSpell("instant or sorcery spell");
|
||||
|
||||
|
|
@ -94,9 +95,10 @@ public class EchoMage extends CardImpl {
|
|||
ability.addCost(new TapSourceCost());
|
||||
abilities2.add(ability);
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(2, 3, abilities1, 2, 4),
|
||||
new LevelerCardBuilder.LevelAbility(4, -1, abilities2, 2, 5));
|
||||
new LevelerCardBuilder.LevelAbility(4, -1, abilities2, 2, 5)));
|
||||
setMaxLevelCounters(4);
|
||||
}
|
||||
|
||||
public EchoMage(final EchoMage card) {
|
||||
|
|
|
|||
|
|
@ -69,10 +69,11 @@ public class EnclaveCryptologist extends LevelerCard {
|
|||
ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new TapSourceCost());
|
||||
Abilities<Ability> abilities2 = new AbilitiesImpl<Ability>(ability);
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 2, abilities1, 0, 1),
|
||||
new LevelerCardBuilder.LevelAbility(3, -1, abilities2, 0, 1)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(3);
|
||||
}
|
||||
|
||||
public EnclaveCryptologist (final EnclaveCryptologist card) {
|
||||
|
|
|
|||
|
|
@ -76,10 +76,11 @@ public class GuulDrazAssassin extends LevelerCard {
|
|||
ability2.addCost(new TapSourceCost());
|
||||
abilities2.add(ability2);
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(2, 3, abilities1, 2, 2),
|
||||
new LevelerCardBuilder.LevelAbility(4, -1, abilities2, 4, 4)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(4);
|
||||
}
|
||||
|
||||
public GuulDrazAssassin (final GuulDrazAssassin card) {
|
||||
|
|
|
|||
|
|
@ -74,10 +74,11 @@ public class HadaSpyPatrol extends LevelerCard {
|
|||
abilities2.add(ShroudAbility.getInstance());
|
||||
abilities2.add(new CantBeBlockedSourceAbility());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 2, abilities1, 2, 2),
|
||||
new LevelerCardBuilder.LevelAbility(3, -1, abilities2, 3, 3)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(3);
|
||||
}
|
||||
|
||||
public HadaSpyPatrol(final HadaSpyPatrol card) {
|
||||
|
|
|
|||
|
|
@ -62,10 +62,11 @@ public class HalimarWavewatch extends LevelerCard {
|
|||
Abilities<Ability> levelAbilities = new AbilitiesImpl<Ability>();
|
||||
levelAbilities.add(new IslandwalkAbility());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 4, new AbilitiesImpl<Ability>(), 0, 6),
|
||||
new LevelerCardBuilder.LevelAbility(5, -1, levelAbilities, 6, 6)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(5);
|
||||
}
|
||||
|
||||
public HalimarWavewatch(final HalimarWavewatch card) {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import mage.abilities.effects.PreventionEffectImpl;
|
|||
import mage.abilities.keyword.LevelUpAbility;
|
||||
import mage.abilities.keyword.LevelerCardBuilder;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.LevelerCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
|
@ -50,7 +51,7 @@ import mage.game.permanent.Permanent;
|
|||
*
|
||||
* @author North
|
||||
*/
|
||||
public class HedronFieldPurists extends CardImpl {
|
||||
public class HedronFieldPurists extends LevelerCard {
|
||||
|
||||
public HedronFieldPurists(UUID ownerId) {
|
||||
super(ownerId, 25, "Hedron-Field Purists", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}");
|
||||
|
|
@ -75,9 +76,10 @@ public class HedronFieldPurists extends CardImpl {
|
|||
Abilities<Ability> abilities2 = new AbilitiesImpl<>();
|
||||
abilities2.add(new SimpleStaticAbility(Zone.BATTLEFIELD, new HedronFieldPuristsEffect(2)));
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 4, abilities1, 1, 4),
|
||||
new LevelerCardBuilder.LevelAbility(5, -1, abilities2, 2, 5));
|
||||
new LevelerCardBuilder.LevelAbility(5, -1, abilities2, 2, 5)));
|
||||
setMaxLevelCounters(5);
|
||||
}
|
||||
|
||||
public HedronFieldPurists(final HedronFieldPurists card) {
|
||||
|
|
|
|||
|
|
@ -65,10 +65,11 @@ public class IkiralOutrider extends LevelerCard {
|
|||
Abilities<Ability> abilities2 = new AbilitiesImpl<Ability>();
|
||||
abilities2.add(VigilanceAbility.getInstance());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 3, abilities1, 2, 6),
|
||||
new LevelerCardBuilder.LevelAbility(4, -1, abilities2, 3, 10)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(4);
|
||||
}
|
||||
|
||||
public IkiralOutrider (final IkiralOutrider card) {
|
||||
|
|
|
|||
|
|
@ -92,10 +92,11 @@ public class JoragaTreespeaker extends LevelerCard {
|
|||
new TapSourceCost()),
|
||||
Duration.WhileOnBattlefield, filter)));
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 4, abilities1, 1, 2),
|
||||
new LevelerCardBuilder.LevelAbility(5, -1, abilities2, 1, 4)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(5);
|
||||
}
|
||||
|
||||
public JoragaTreespeaker(final JoragaTreespeaker card) {
|
||||
|
|
|
|||
|
|
@ -69,10 +69,11 @@ public class KabiraVindicator extends LevelerCard {
|
|||
Abilities<Ability> abilities2 = new AbilitiesImpl<Ability>();
|
||||
abilities2.add(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, new FilterCreaturePermanent(), true)));
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(2, 4, abilities1, 3, 6),
|
||||
new LevelerCardBuilder.LevelAbility(5, -1, abilities2, 4, 8)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(5);
|
||||
}
|
||||
|
||||
public KabiraVindicator(final KabiraVindicator card) {
|
||||
|
|
|
|||
|
|
@ -72,10 +72,11 @@ public class KarganDragonlord extends LevelerCard {
|
|||
abilities2.add(TrampleAbility.getInstance());
|
||||
abilities2.add(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}")));
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(4, 7, abilities1, 4, 4),
|
||||
new LevelerCardBuilder.LevelAbility(8, -1, abilities2, 8, 8)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(8);
|
||||
}
|
||||
|
||||
public KarganDragonlord(final KarganDragonlord card) {
|
||||
|
|
|
|||
|
|
@ -72,10 +72,11 @@ public class KazanduTuskcaller extends LevelerCard {
|
|||
new CreateTokenEffect(new ElephantToken(), 2),
|
||||
new TapSourceCost()));
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(2, 5, abilities1, 1, 1),
|
||||
new LevelerCardBuilder.LevelAbility(6, -1, abilities2, 1, 1)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(6);
|
||||
}
|
||||
|
||||
public KazanduTuskcaller(final KazanduTuskcaller card) {
|
||||
|
|
|
|||
|
|
@ -67,10 +67,11 @@ public class KnightOfCliffhaven extends LevelerCard {
|
|||
abilities2.add(FlyingAbility.getInstance());
|
||||
abilities2.add(VigilanceAbility.getInstance());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 3, abilities1, 2, 3),
|
||||
new LevelerCardBuilder.LevelAbility(4, -1, abilities2, 4, 4)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(4);
|
||||
}
|
||||
|
||||
public KnightOfCliffhaven(final KnightOfCliffhaven card) {
|
||||
|
|
|
|||
|
|
@ -75,10 +75,11 @@ public class LighthouseChronologist extends LevelerCard {
|
|||
Abilities<Ability> abilities2 = new AbilitiesImpl<>();
|
||||
abilities2.add(new LighthouseChronologistAbility());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(4, 6, abilities1, 2, 4),
|
||||
new LevelerCardBuilder.LevelAbility(7, -1, abilities2, 3, 5)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(7);
|
||||
}
|
||||
|
||||
public LighthouseChronologist (final LighthouseChronologist card) {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import mage.abilities.effects.OneShotEffect;
|
|||
import mage.abilities.keyword.LevelUpAbility;
|
||||
import mage.abilities.keyword.LevelerCardBuilder;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.LevelerCard;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.game.Game;
|
||||
|
|
@ -51,7 +52,7 @@ import mage.game.permanent.Permanent;
|
|||
*
|
||||
* @author North
|
||||
*/
|
||||
public class LordOfShatterskullPass extends CardImpl {
|
||||
public class LordOfShatterskullPass extends LevelerCard {
|
||||
|
||||
public LordOfShatterskullPass(UUID ownerId) {
|
||||
super(ownerId, 156, "Lord of Shatterskull Pass", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{R}");
|
||||
|
|
@ -74,9 +75,10 @@ public class LordOfShatterskullPass extends CardImpl {
|
|||
Abilities<Ability> abilities2 = new AbilitiesImpl<Ability>();
|
||||
abilities2.add(new AttacksTriggeredAbility(new LordOfShatterskullPassEffect(), false));
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 5, abilities1, 6, 6),
|
||||
new LevelerCardBuilder.LevelAbility(6, -1, abilities2, 6, 6));
|
||||
new LevelerCardBuilder.LevelAbility(6, -1, abilities2, 6, 6)));
|
||||
setMaxLevelCounters(6);
|
||||
}
|
||||
|
||||
public LordOfShatterskullPass(final LordOfShatterskullPass card) {
|
||||
|
|
|
|||
|
|
@ -66,10 +66,11 @@ public class NirkanaCutthroat extends LevelerCard {
|
|||
abilities2.add(FirstStrikeAbility.getInstance());
|
||||
abilities2.add(DeathtouchAbility.getInstance());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 2, abilities1, 4, 3),
|
||||
new LevelerCardBuilder.LevelAbility(3, -1, abilities2, 5, 4)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(3);
|
||||
}
|
||||
|
||||
public NirkanaCutthroat (final NirkanaCutthroat card) {
|
||||
|
|
|
|||
|
|
@ -65,10 +65,11 @@ public class NullChampion extends LevelerCard {
|
|||
Abilities<Ability> abilities2 = new AbilitiesImpl<Ability>();
|
||||
abilities2.add(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}")));
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 3, abilities1, 4, 2),
|
||||
new LevelerCardBuilder.LevelAbility(4, -1, abilities2, 7, 3)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(4);
|
||||
}
|
||||
|
||||
public NullChampion (final NullChampion card) {
|
||||
|
|
|
|||
|
|
@ -65,10 +65,11 @@ public class SkywatcherAdept extends LevelerCard {
|
|||
Abilities<Ability> abilities2 = new AbilitiesImpl<Ability>();
|
||||
abilities2.add(FlyingAbility.getInstance());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 2, abilities1, 2, 2),
|
||||
new LevelerCardBuilder.LevelAbility(3, -1, abilities2, 4, 2)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(3);
|
||||
}
|
||||
|
||||
public SkywatcherAdept(final SkywatcherAdept card) {
|
||||
|
|
|
|||
|
|
@ -65,10 +65,11 @@ public class StudentOfWarfare extends LevelerCard {
|
|||
Abilities<Ability> abilities2 = new AbilitiesImpl<Ability>();
|
||||
abilities2.add(DoubleStrikeAbility.getInstance());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(2, 6, abilities1, 3, 3),
|
||||
new LevelerCardBuilder.LevelAbility(7, -1, abilities2, 4, 4)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(7);
|
||||
}
|
||||
|
||||
public StudentOfWarfare (final StudentOfWarfare card) {
|
||||
|
|
|
|||
|
|
@ -70,10 +70,11 @@ public class TranscendentMaster extends LevelerCard {
|
|||
LifelinkAbility.getInstance(),
|
||||
IndestructibleAbility.getInstance());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(6, 11, abilities1, 6, 6),
|
||||
new LevelerCardBuilder.LevelAbility(12, -1, abilities2, 9, 9)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(12);
|
||||
}
|
||||
|
||||
public TranscendentMaster(final TranscendentMaster card) {
|
||||
|
|
|
|||
|
|
@ -70,10 +70,11 @@ public class ZulaportEnforcer extends LevelerCard {
|
|||
Abilities<Ability> levelAbilities = new AbilitiesImpl<Ability>();
|
||||
levelAbilities.add(ZulaportEnforcerAbility.getInstance());
|
||||
|
||||
LevelerCardBuilder.construct(this,
|
||||
this.addAbilities(LevelerCardBuilder.construct(
|
||||
new LevelerCardBuilder.LevelAbility(1, 2, new AbilitiesImpl<Ability>(), 3, 3),
|
||||
new LevelerCardBuilder.LevelAbility(3, -1, levelAbilities, 5, 5)
|
||||
);
|
||||
));
|
||||
setMaxLevelCounters(3);
|
||||
}
|
||||
|
||||
public ZulaportEnforcer(final ZulaportEnforcer card) {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class SedrisTheTraitorKingEffect extends ContinuousEffectImpl {
|
|||
UnearthAbility ability = new UnearthAbility(new ManaCostsImpl("{2}{B}"));
|
||||
ability.setSourceId(cardId);
|
||||
ability.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(cardId, ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class CrucibleOfWorldsEffect extends ContinuousEffectImpl {
|
|||
PlayLandFromGraveyardAbility ability = new PlayLandFromGraveyardAbility(card.getName());
|
||||
ability.setSourceId(cardId);
|
||||
ability.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(cardId, ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ class WhipOfErebosEffect extends OneShotEffect {
|
|||
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null && card != null) {
|
||||
card.addAbility(HasteAbility.getInstance());
|
||||
if (controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId())) {
|
||||
// gains haste
|
||||
ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom);
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ class DralnuLichLordFlashbackEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
ability.setSourceId(card.getId());
|
||||
ability.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(card.getId(), ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -110,20 +110,20 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl {
|
|||
for (UUID cardId: controller.getGraveyard()) {
|
||||
Card card = game.getCard(cardId);
|
||||
if (card.getCardType().contains(CardType.CREATURE)) {
|
||||
game.getState().addOtherAbility(cardId, FlashAbility.getInstance());
|
||||
game.getState().addOtherAbility(card, FlashAbility.getInstance());
|
||||
}
|
||||
}
|
||||
// on Hand
|
||||
for (UUID cardId: controller.getHand()) {
|
||||
Card card = game.getCard(cardId);
|
||||
if (card.getCardType().contains(CardType.CREATURE)) {
|
||||
game.getState().addOtherAbility(cardId, FlashAbility.getInstance());
|
||||
game.getState().addOtherAbility(card, FlashAbility.getInstance());
|
||||
}
|
||||
}
|
||||
// in Exile
|
||||
for (Card card: game.getState().getExile().getAllCards(game)) {
|
||||
if (card.getOwnerId().equals(controller.getId()) && card.getCardType().contains(CardType.CREATURE)) {
|
||||
game.getState().addOtherAbility(card.getId(), FlashAbility.getInstance());
|
||||
game.getState().addOtherAbility(card, FlashAbility.getInstance());
|
||||
}
|
||||
}
|
||||
// in Library seems not relevant yet
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ public class Necromancy extends CardImpl {
|
|||
|
||||
// You may cast Necromancy as though it had flash. If you cast it any time a sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new CastSourceAsThoughItHadFlashEffect(this, Duration.EndOfGame, true)));
|
||||
|
||||
this.addAbility(new CastAtInstantTimeTriggeredAbility());
|
||||
|
||||
// When Necromancy enters the battlefield, if it's on the battlefield, it becomes an Aura with "enchant creature put onto the battlefield with Necromancy."
|
||||
// Put target creature card from a graveyard onto the battlefield under your control and attach Necromancy to it.
|
||||
// When Necromancy leaves the battlefield, that creature's controller sacrifices it.
|
||||
|
|
@ -111,9 +112,6 @@ class CastSourceAsThoughItHadFlashEffect extends AsThoughEffectImpl {
|
|||
public CastSourceAsThoughItHadFlashEffect(Card card, Duration duration, boolean sacrificeIfCastAsInstant) {
|
||||
super(AsThoughEffectType.CAST_AS_INSTANT, duration, Outcome.Benefit);
|
||||
this.sacrificeIfCastAsInstant = sacrificeIfCastAsInstant;
|
||||
if (sacrificeIfCastAsInstant) {
|
||||
card.addAbility(new CastAtInstantTimeTriggeredAbility());
|
||||
}
|
||||
staticText = "You may cast {this} as though it had flash";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class ChampionTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* 702.71. Champion
|
||||
* 702.71a Champion represents two triggered abilities. “Champion an [object]” means “When this
|
||||
* permanent enters the battlefield, sacrifice it unless you exile another [object] you control” and
|
||||
* “When this permanent leaves the battlefield, return the exiled card to the battlefield under its
|
||||
* owner’s control.”
|
||||
*
|
||||
* 702.71b The two abilities represented by champion are linked. See rule 607, “Linked Abilities.”
|
||||
*
|
||||
* 702.71c A permanent is “championed” by another permanent if the latter exiles the former as the
|
||||
* direct result of a champion ability.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Lightning Crafter
|
||||
* Creature — Goblin Shaman 3/3, 3R (4)
|
||||
* Champion a Goblin or Shaman (When this enters the battlefield, sacrifice
|
||||
* it unless you exile another Goblin or Shaman you control. When this
|
||||
* leaves the battlefield, that card returns to the battlefield.)
|
||||
* {T}: Lightning Crafter deals 3 damage to target creature or player.
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testChampionCreature() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Goblin Roughrider");
|
||||
addCard(Zone.HAND, playerA, "Lightning Crafter");
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Crafter");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Lightning Crafter", 1);
|
||||
assertExileCount("Goblin Roughrider", 1);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExiledCreatureReturns() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Goblin Roughrider");
|
||||
addCard(Zone.HAND, playerA, "Lightning Crafter");
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Crafter");
|
||||
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: {source} deals 3 damage to target creature or player.", "Lightning Crafter");
|
||||
|
||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Lightning Crafter", 0);
|
||||
assertPermanentCount(playerA, "Goblin Roughrider", 1);
|
||||
assertExileCount("Goblin Roughrider", 0);
|
||||
assertGraveyardCount(playerA, "Lightning Crafter", 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class ConspireTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* 702.77. Conspire
|
||||
* 702.77a Conspire is a keyword that represents two abilities. The first is a static ability that functions
|
||||
* while the spell with conspire is on the stack. The second is a triggered ability that functions
|
||||
* while the spell with conspire is on the stack. “Conspire” means “As an additional cost to cast
|
||||
* this spell, you may tap two untapped creatures you control that each share a color with it” and
|
||||
* “When you cast this spell, if its conspire cost was paid, copy it. If the spell has any targets, you
|
||||
* may choose new targets for the copy.” Paying a spell’s conspire cost follows the rules for
|
||||
* paying additional costs in rules 601.2b and 601.2e–g.
|
||||
*
|
||||
* 702.77b If a spell has multiple instances of conspire, each is paid separately and triggers based on
|
||||
* its own payment, not any other instance of conspire
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Burn Trail
|
||||
* Sorcery, 3R (4)
|
||||
* Burn Trail deals 3 damage to target creature or player.
|
||||
*
|
||||
* Conspire (As you cast this spell, you may tap two untapped creatures you
|
||||
* control that share a color with it. When you do, copy it and you may
|
||||
* choose a new target for the copy.)
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testConspire() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Goblin Roughrider");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
|
||||
addCard(Zone.HAND, playerA, "Burn Trail");
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB);
|
||||
setChoice(playerA, "Yes");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 14);
|
||||
assertGraveyardCount(playerA, "Burn Trail", 1);
|
||||
assertTapped("Goblin Roughrider", true);
|
||||
assertTapped("Raging Goblin", true);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConspireNotUsed() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Goblin Roughrider");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
|
||||
addCard(Zone.HAND, playerA, "Burn Trail");
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB);
|
||||
setChoice(playerA, "No");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 17);
|
||||
assertGraveyardCount(playerA, "Burn Trail", 1);
|
||||
assertTapped("Goblin Roughrider", false);
|
||||
assertTapped("Raging Goblin", false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class DashTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* 702.108. Dash
|
||||
* 702.108a Dash represents three abilities: two static abilities that function while the card with dash is
|
||||
* on the stack, one of which may create a delayed triggered ability, and a static ability that
|
||||
* functions while the object with dash is on the battlefield. “Dash [cost]” means “You may cast
|
||||
* this card by paying [cost] rather that its mana cost,” “If this spell’s dash cost was paid, return the
|
||||
* permanent this spell becomes to its owner’s hand at the beginning of the next end step,” and “As
|
||||
* long as this permanent’s dash cost was paid, it has haste.” Paying a card’s dash cost follows the
|
||||
* rules for paying alternative costs in rules 601.2b and 601.2e–g.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Screamreach Brawler
|
||||
* Creature — Orc Berserker 2/3, 2R (3)
|
||||
* Dash {1}{R} (You may cast this spell for its dash cost. If you do, it
|
||||
* gains haste, and it's returned from the battlefield to its owner's hand
|
||||
* at the beginning of the next end step.)
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testDash() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||
addCard(Zone.HAND, playerA, "Screamreach Brawler");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Screamreach Brawler");
|
||||
setChoice(playerA, "Yes");
|
||||
attack(1, playerA, "Screamreach Brawler");
|
||||
|
||||
setStopAt(2, PhaseStep.UNTAP);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 18);
|
||||
assertPermanentCount(playerA, "Screamreach Brawler", 0);
|
||||
assertHandCount(playerA, "Screamreach Brawler", 1);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoDash() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
addCard(Zone.HAND, playerA, "Screamreach Brawler");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Screamreach Brawler");
|
||||
setChoice(playerA, "No");
|
||||
attack(1, playerA, "Screamreach Brawler");
|
||||
|
||||
setStopAt(2, PhaseStep.UNTAP);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20);
|
||||
assertPermanentCount(playerA, "Screamreach Brawler", 1);
|
||||
assertHandCount(playerA, "Screamreach Brawler", 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class FadingTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* 702.31. Fading
|
||||
* 702.31a Fading is a keyword that represents two abilities. “Fading N” means “This permanent
|
||||
* enters the battlefield with N fade counters on it” and “At the beginning of your upkeep, remove
|
||||
* a fade counter from this permanent. If you can’t, sacrifice the permanent.”
|
||||
*/
|
||||
|
||||
/**
|
||||
* Blastoderm
|
||||
* Creature — Beast 5/5, 2GG (4)
|
||||
* Shroud (This creature can't be the target of spells or abilities.)
|
||||
* Fading 3 (This creature enters the battlefield with three fade counters
|
||||
* on it. At the beginning of your upkeep, remove a fade counter from it.
|
||||
* If you can't, sacrifice it.)
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testFading() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.HAND, playerA, "Blastoderm");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blastoderm");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Blastoderm", 1);
|
||||
this.assertCounterCount("Blastoderm", CounterType.FADE, 3);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFades() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.HAND, playerA, "Blastoderm");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blastoderm");
|
||||
|
||||
setStopAt(5, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Blastoderm", 1);
|
||||
this.assertCounterCount("Blastoderm", CounterType.FADE, 1);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFadesAway() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.HAND, playerA, "Blastoderm");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blastoderm");
|
||||
|
||||
setStopAt(9, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Blastoderm", 0);
|
||||
assertGraveyardCount(playerA, "Blastoderm", 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class GraftTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* 702.57. Graft
|
||||
* 702.57a Graft represents both a static ability and a triggered ability. “Graft N” means “This
|
||||
* permanent enters the battlefield with N +1/+1 counters on it” and “Whenever another creature
|
||||
* enters the battlefield, if this permanent has a +1/+1 counter on it, you may move a +1/+1
|
||||
* counter from this permanent onto that creature.”
|
||||
* 702.57b If a creature has multiple instances of graft, each one works separately.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sporeback Troll
|
||||
* Creature — Troll Mutant 0/0, 3G (4)
|
||||
* Graft 2 (This creature enters the battlefield with two +1/+1 counters on it.
|
||||
* Whenever another creature enters the battlefield, you may move a +1/+1
|
||||
* counter from this creature onto it.)
|
||||
* {1}{G}: Regenerate target creature with a +1/+1 counter on it.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Cytoplast Root-Kin
|
||||
* Creature — Elemental Mutant 0/0, 2GG (4)
|
||||
* Graft 4 (This creature enters the battlefield with four +1/+1 counters on
|
||||
* it. Whenever another creature enters the battlefield, you may move a +1/+1
|
||||
* counter from this creature onto it.)
|
||||
* When Cytoplast Root-Kin enters the battlefield, put a +1/+1 counter on
|
||||
* each other creature you control with a +1/+1 counter on it.
|
||||
* {2}: Move a +1/+1 counter from target creature you control onto Cytoplast Root-Kin.
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGraft() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.HAND, playerA, "Sporeback Troll");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sporeback Troll");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Sporeback Troll", 1);
|
||||
assertPowerToughness(playerA, "Sporeback Troll", 2, 2);
|
||||
assertCounterCount("Sporeback Troll", CounterType.P1P1, 2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveCounters() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 8);
|
||||
addCard(Zone.HAND, playerA, "Cytoplast Root-Kin");
|
||||
addCard(Zone.HAND, playerA, "Sporeback Troll");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cytoplast Root-Kin");
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Sporeback Troll");
|
||||
setChoice(playerA, "Yes");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Sporeback Troll", 1);
|
||||
assertPermanentCount(playerA, "Cytoplast Root-Kin", 1);
|
||||
assertPowerToughness(playerA, "Sporeback Troll", 3, 3);
|
||||
assertPowerToughness(playerA, "Cytoplast Root-Kin", 3, 3);
|
||||
assertCounterCount("Sporeback Troll", CounterType.P1P1, 3);
|
||||
assertCounterCount("Cytoplast Root-Kin", CounterType.P1P1, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDontMoveCounters() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 8);
|
||||
addCard(Zone.HAND, playerA, "Cytoplast Root-Kin");
|
||||
addCard(Zone.HAND, playerA, "Sporeback Troll");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cytoplast Root-Kin");
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Sporeback Troll");
|
||||
setChoice(playerA, "No");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Sporeback Troll", 1);
|
||||
assertPermanentCount(playerA, "Cytoplast Root-Kin", 1);
|
||||
assertPowerToughness(playerA, "Sporeback Troll", 2, 2);
|
||||
assertPowerToughness(playerA, "Cytoplast Root-Kin", 4, 4);
|
||||
assertCounterCount("Sporeback Troll", CounterType.P1P1, 2);
|
||||
assertCounterCount("Cytoplast Root-Kin", CounterType.P1P1, 4);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.cards.Card;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class HideawayTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* 702.74. Hideaway
|
||||
* 702.74a Hideaway represents a static ability and a triggered ability. “Hideaway” means “This
|
||||
* permanent enters the battlefield tapped” and “When this permanent enters the battlefield, look at
|
||||
* the top four cards of your library. Exile one of them face down and put the rest on the bottom of
|
||||
* your library in any order. The exiled card gains ‘Any player who has controlled the permanent
|
||||
* that exiled this card may look at this card in the exile zone.’”
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Shelldock Isle
|
||||
* Land
|
||||
* Hideaway (This land enters the battlefield tapped. When it does, look at
|
||||
* the top four cards of your library, exile one face down, then put the
|
||||
* rest on the bottom of your library.)
|
||||
* {T}: Add {U} to your mana pool.
|
||||
* {U}, {T}: You may play the exiled card without paying its mana cost if a
|
||||
* library has twenty or fewer cards in it.
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testHideaway() {
|
||||
addCard(Zone.HAND, playerA, "Shelldock Isle");
|
||||
|
||||
this.playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shelldock Isle");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Shelldock Isle", 1);
|
||||
assertExileCount(playerA, 1);
|
||||
for (Card card :currentGame.getExile().getAllCards(currentGame)){
|
||||
Assert.assertTrue("Exiled card is not face down", card.isFaceDown(currentGame));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class MadnessTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* 702.34. Madness
|
||||
* 702.34a Madness is a keyword that represents two abilities. The first is a static ability that functions
|
||||
* while the card with madness is in a player’s hand. The second is a triggered ability that
|
||||
* functions when the first ability is applied. “Madness [cost]” means “If a player would discard
|
||||
* this card, that player discards it, but may exile it instead of putting it into his or her graveyard”
|
||||
* and “When this card is exiled this way, its owner may cast it by paying [cost] rather than paying
|
||||
* its mana cost. If that player doesn’t, he or she puts this card into his or her graveyard.”
|
||||
* 702.34b Casting a spell using its madness ability follows the rules for paying alternative costs in
|
||||
* rules 601.2b and 601.2e–g.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Arrogant Wurm
|
||||
* 3GG
|
||||
* Creature -- Wurm
|
||||
* 4/4
|
||||
* Trample
|
||||
* Madness {2}{G} (If you discard this card, you may cast it for its
|
||||
* madness cost instead of putting it into your graveyard.)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Raven's Crime
|
||||
* B
|
||||
* Sorcery
|
||||
* Target player discards a card.
|
||||
* Retrace (You may cast this card from your graveyard by discarding a land
|
||||
* card in addition to paying its other costs.)
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testMadness() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
addCard(Zone.HAND, playerA, "Arrogant Wurm");
|
||||
addCard(Zone.HAND, playerA, "Raven's Crime");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Raven's Crime", playerA);
|
||||
setChoice(playerA, "Yes");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Arrogant Wurm", 1);
|
||||
assertGraveyardCount(playerA, "Raven's Crime", 1);
|
||||
assertHandCount(playerA, 0);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoMadness() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
addCard(Zone.HAND, playerA, "Arrogant Wurm");
|
||||
addCard(Zone.HAND, playerA, "Raven's Crime");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Raven's Crime", playerA);
|
||||
setChoice(playerA, "No");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Arrogant Wurm", 0);
|
||||
assertGraveyardCount(playerA, "Raven's Crime", 1);
|
||||
assertGraveyardCount(playerA, "Arrogant Wurm", 1);
|
||||
assertHandCount(playerA, 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class ModularTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* 702.42. Modular
|
||||
* 702.42a Modular represents both a static ability and a triggered ability. “Modular N” means “This
|
||||
* permanent enters the battlefield with N +1/+1 counters on it” and “When this permanent is put
|
||||
* into a graveyard from the battlefield, you may put a +1/+1 counter on target artifact creature for
|
||||
* each +1/+1 counter on this permanent.”
|
||||
* 702.42b If a creature has multiple instances of modular, each one works separately.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Arcbound Bruiser
|
||||
* Artifact Creature — Golem 0/0, 5 (5)
|
||||
* Modular 3 (This enters the battlefield with three +1/+1 counters on it.
|
||||
* When it dies, you may put its +1/+1 counters on target artifact creature.)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Arcbound Hybrid
|
||||
* Artifact Creature — Beast 0/0, 4 (4)
|
||||
* Haste
|
||||
* Modular 2 (This enters the battlefield with two +1/+1 counters on it.
|
||||
* When it dies, you may put its +1/+1 counters on target artifact creature.)
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testModularEnters() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
|
||||
addCard(Zone.HAND, playerA, "Arcbound Bruiser");
|
||||
addCard(Zone.HAND, playerA, "Arcbound Hybrid");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Arcbound Bruiser");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Arcbound Hybrid");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Arcbound Bruiser", 1);
|
||||
assertPermanentCount(playerA, "Arcbound Hybrid", 1);
|
||||
assertPowerToughness(playerA, "Arcbound Bruiser", 3, 3);
|
||||
assertPowerToughness(playerA, "Arcbound Hybrid", 2, 2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModularLeaves() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
addCard(Zone.HAND, playerA, "Arcbound Bruiser");
|
||||
addCard(Zone.HAND, playerA, "Arcbound Hybrid");
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Arcbound Bruiser");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Arcbound Hybrid");
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Arcbound Bruiser");
|
||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||
setChoice(playerA, "Yes");
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Arcbound Bruiser", 0);
|
||||
assertPermanentCount(playerA, "Arcbound Hybrid", 1);
|
||||
assertGraveyardCount(playerA, "Arcbound Bruiser", 1);
|
||||
assertPowerToughness(playerA, "Arcbound Hybrid", 5, 5);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.keywords;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class ReplicateTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* 702.55. Replicate
|
||||
* 702.55a Replicate is a keyword that represents two abilities. The first is a static ability that
|
||||
* functions while the spell with replicate is on the stack. The second is a triggered ability that
|
||||
* functions while the spell with replicate is on the stack. “Replicate [cost]” means “As an
|
||||
* additional cost to cast this spell, you may pay [cost] any number of times” and “When you cast
|
||||
* this spell, if a replicate cost was paid for it, copy it for each time its replicate cost was paid. If
|
||||
* the spell has any targets, you may choose new targets for any of the copies.” Paying a spell’s
|
||||
* replicate cost follows the rules for paying additional costs in rules 601.2b and 601.2e–g.
|
||||
* 702.55b If a spell has multiple instances of replicate, each is paid separately and triggers based on
|
||||
* the payments made for it, not any other instance of replicate.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Train of Thought
|
||||
* Sorcery, 1U (2)
|
||||
* Replicate {1}{U} (When you cast this spell, copy it for each time you paid its replicate cost.)
|
||||
* Draw a card.
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testReplicate1Time() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||
addCard(Zone.HAND, playerA, "Train of Thought");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Train of Thought");
|
||||
setChoice(playerA, "Yes");
|
||||
setChoice(playerA, "No");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Train of Thought", 1);
|
||||
assertHandCount(playerA, 2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplicate2Times() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||
addCard(Zone.HAND, playerA, "Train of Thought");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Train of Thought");
|
||||
setChoice(playerA, "Yes");
|
||||
setChoice(playerA, "Yes");
|
||||
setChoice(playerA, "No");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Train of Thought", 1);
|
||||
assertHandCount(playerA, 3);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotReplicate() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||
addCard(Zone.HAND, playerA, "Train of Thought");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Train of Thought");
|
||||
setChoice(playerA, "No");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Train of Thought", 1);
|
||||
assertHandCount(playerA, 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.other;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class ChiefEngineerTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Chief Engineer
|
||||
* Creature — Vedalken Artificer 1/3, 1U (2)
|
||||
* Artifact spells you cast have convoke. (Your creatures can help cast
|
||||
* those spells. Each creature you tap while casting an artifact spell pays
|
||||
* for {1} or one mana of that creature's color.)
|
||||
*
|
||||
*/
|
||||
|
||||
@Ignore // at this time player.getPlayable() does not take into account convoke payments
|
||||
@Test
|
||||
public void testGainsConvoke() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Chief Engineer");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Alpha Myr");
|
||||
addCard(Zone.HAND, playerA, "Goblin Roughrider");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Roughrider");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Goblin Roughrider", 1);
|
||||
assertTapped("Alpha Myr", true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.other;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class ChorusOfTheConclaveTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Chorus of the Conclave
|
||||
* 4GGWW
|
||||
* Legendary Creature -- Dryad
|
||||
* 3/8
|
||||
* Forestwalk
|
||||
* As an additional cost to cast creature spells, you may pay any amount of
|
||||
* mana. If you do, that creature enters the battlefield with that many
|
||||
* additional +1/+1 counters on it.
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testPlayCreature() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Chorus of the Conclave");
|
||||
addCard(Zone.HAND, playerA, "Goblin Roughrider");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Roughrider");
|
||||
setChoice(playerA, "Yes");
|
||||
setChoice(playerA, "X=1");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Goblin Roughrider", 1);
|
||||
assertCounterCount("Goblin Roughrider", CounterType.P1P1, 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.other;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class CrucibleOfWorldsTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Crucible of Worlds
|
||||
* Artifact, 3 (3)
|
||||
* You may play land cards from your graveyard.
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testPlayLand() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Crucible of Worlds");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Swamp");
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Swamp");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Swamp", 1);
|
||||
assertGraveyardCount(playerA, "Swamp", 0);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCantPlayMoreThanOneLandPerTurn() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Crucible of Worlds");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Swamp");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Plains");
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Swamp");
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Play Plains");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Swamp", 1);
|
||||
assertGraveyardCount(playerA, "Swamp", 0);
|
||||
assertPermanentCount(playerA, "Plains", 0);
|
||||
assertGraveyardCount(playerA, "Plains", 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.other;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class MycosynthGolemTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Mycosynth Golem
|
||||
* Artifact Creature — Golem 4/5, 11 (11)
|
||||
* Affinity for artifacts (This spell costs {1} less to cast for each
|
||||
* artifact you control.)
|
||||
* Artifact creature spells you cast have affinity for artifacts. (They cost
|
||||
* {1} less to cast for each artifact you control.)
|
||||
*
|
||||
*/
|
||||
|
||||
@Ignore // at this time player.getPlayable() does not account for spells that gain abilities
|
||||
@Test
|
||||
public void testSpellsAffinity() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mycosynth Golem");
|
||||
addCard(Zone.HAND, playerA, "Alpha Myr");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Alpha Myr");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Alpha Myr", 1);
|
||||
assertHandCount(playerA, "Alpha Myr", 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.other;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class NecromancyTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Necromancy
|
||||
* Enchantment, 2B (3)
|
||||
* You may cast Necromancy as though it had flash. If you cast it any time a
|
||||
* sorcery couldn't have been cast, the controller of the permanent it
|
||||
* becomes sacrifices it at the beginning of the next cleanup step.
|
||||
* When Necromancy enters the battlefield, if it's on the battlefield, it
|
||||
* becomes an Aura with "enchant creature put onto the battlefield with
|
||||
* Necromancy." Put target creature card from a graveyard onto the
|
||||
* battlefield under your control and attach Necromancy to it. When
|
||||
* Necromancy leaves the battlefield, that creature's controller sacrifices it.
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testNecromancy() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.HAND, playerA, "Necromancy");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Craw Wurm");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Necromancy");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Craw Wurm", 1);
|
||||
assertPermanentCount(playerA, "Necromancy", 1);
|
||||
assertGraveyardCount(playerA, "Craw Wurm", 0);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNecromancyFlash() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.HAND, playerA, "Necromancy");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Craw Wurm");
|
||||
|
||||
castSpell(1, PhaseStep.UPKEEP, playerA, "Necromancy");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Craw Wurm", 1);
|
||||
assertPermanentCount(playerA, "Necromancy", 1);
|
||||
assertGraveyardCount(playerA, "Craw Wurm", 0);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNecromancyFlashSacrifice() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.HAND, playerA, "Necromancy");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Craw Wurm");
|
||||
|
||||
castSpell(1, PhaseStep.UPKEEP, playerA, "Necromancy");
|
||||
|
||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Craw Wurm", 0);
|
||||
assertPermanentCount(playerA, "Necromancy", 0);
|
||||
assertGraveyardCount(playerA, "Craw Wurm", 1);
|
||||
assertGraveyardCount(playerA, "Necromancy", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNecromancyLeaves() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
||||
addCard(Zone.HAND, playerA, "Necromancy");
|
||||
addCard(Zone.HAND, playerA, "Disenchant");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Craw Wurm");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Necromancy");
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Disenchant", "Necromancy");
|
||||
|
||||
setStopAt(2, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Craw Wurm", 0);
|
||||
assertPermanentCount(playerA, "Necromancy", 0);
|
||||
assertGraveyardCount(playerA, "Necromancy", 1);
|
||||
assertGraveyardCount(playerA, "Craw Wurm", 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.other;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class PastInFlamesTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Past in Flames
|
||||
* Sorcery, 3R (4)
|
||||
* Each instant and sorcery card in your graveyard gains flashback until end
|
||||
* of turn. The flashback cost is equal to its mana cost.
|
||||
* Flashback {4}{R} (You may cast this card from your graveyard for its
|
||||
* flashback cost. Then exile it.)
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testSpellsGainFlashback() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
addCard(Zone.HAND, playerA, "Past in Flames");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Past in Flames");
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertExileCount("Lightning Bolt", 1);
|
||||
assertGraveyardCount(playerA, "Lightning Bolt", 0);
|
||||
assertLife(playerB, 17);
|
||||
assertLife(playerA, 20);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.other;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class SoulfireGrandMasterTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Soulfire Grand Master
|
||||
* Creature — Human Monk 2/2, 1W (2)
|
||||
* Lifelink
|
||||
* Instant and sorcery spells you control have lifelink.
|
||||
* {2}{U/R}{U/R}: The next time you cast an instant or sorcery spell from
|
||||
* your hand this turn, put that card into your hand instead of into your
|
||||
* graveyard as it resolves.
|
||||
*
|
||||
*/
|
||||
|
||||
@Ignore // at this time player.getPlayable() does not account for spells that gain abilities
|
||||
@Test
|
||||
public void testSpellsGainLifelink() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master");
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||
assertHandCount(playerA, "Lightning Bolt", 0);
|
||||
assertLife(playerB, 17);
|
||||
assertLife(playerA, 23);
|
||||
|
||||
}
|
||||
|
||||
@Ignore // at this time player.getPlayable() does not account for spells that gain abilities
|
||||
@Test
|
||||
public void testSpellsReturnToHand() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master");
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{U/R}{U/R}:");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Lightning Bolt", 0);
|
||||
assertHandCount(playerA, "Lightning Bolt", 1);
|
||||
assertLife(playerA, 23);
|
||||
assertLife(playerB, 17);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package org.mage.test.cards.abilities.other;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward
|
||||
*/
|
||||
public class VarolzTheScarStripedTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Varolz, the Scar-Striped
|
||||
* Legendary Creature — Troll Warrior 2/2, 1BG (3)
|
||||
* Each creature card in your graveyard has scavenge. The scavenge cost is
|
||||
* equal to its mana cost. (Exile a creature card from your graveyard and
|
||||
* pay its mana cost: Put a number of +1/+1 counters equal to that card's
|
||||
* power on target creature. Scavenge only as a sorcery.)
|
||||
* Sacrifice another creature: Regenerate Varolz, the Scar-Striped.
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testUseScavenge() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Varolz, the Scar-Striped");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Goblin Roughrider");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Goblin Roughrider");
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Scavenge", "Goblin Roughrider");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Goblin Roughrider", 1);
|
||||
assertGraveyardCount(playerA, "Goblin Roughrider", 0);
|
||||
assertExileCount("Goblin Roughrider", 1);
|
||||
assertCounterCount("Goblin Roughrider", CounterType.P1P1, 3);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -361,6 +361,19 @@ public interface Ability extends Controllable, Serializable {
|
|||
|
||||
boolean canChooseTarget(Game game);
|
||||
|
||||
/**
|
||||
* Gets the list of sub-abilities associated with this ability.
|
||||
* @return
|
||||
*/
|
||||
List<Ability> getSubAbilities();
|
||||
|
||||
/**
|
||||
* Adds a sub-ability to this ability.
|
||||
*
|
||||
* @param ability The {@link Ability} to add.
|
||||
*/
|
||||
void addSubAbility(Ability ability);
|
||||
|
||||
List<Watcher> getWatchers();
|
||||
void addWatcher(Watcher watcher);
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
|
||||
private static final transient Logger logger = Logger.getLogger(AbilityImpl.class);
|
||||
private static final List<Watcher> emptyWatchers = new ArrayList<>();
|
||||
private static final List<Ability> emptyAbilities = new ArrayList<>();
|
||||
|
||||
protected UUID id;
|
||||
protected UUID originalId;
|
||||
|
|
@ -110,6 +111,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
protected boolean worksFaceDown = false;
|
||||
protected MageObject sourceObject;
|
||||
protected List<Watcher> watchers = null;
|
||||
protected List<Ability> subAbilities = null;
|
||||
|
||||
public AbilityImpl(AbilityType abilityType, Zone zone) {
|
||||
this.id = UUID.randomUUID();
|
||||
|
|
@ -145,6 +147,12 @@ public abstract class AbilityImpl implements Ability {
|
|||
watchers.add(watcher.copy());
|
||||
}
|
||||
}
|
||||
if (ability.subAbilities != null) {
|
||||
this.subAbilities = new ArrayList<>();
|
||||
for (Ability subAbility: ability.subAbilities) {
|
||||
subAbilities.add(subAbility.copy());
|
||||
}
|
||||
}
|
||||
this.modes = ability.modes.copy();
|
||||
this.ruleAtTheTop = ability.ruleAtTheTop;
|
||||
this.ruleVisible = ability.ruleVisible;
|
||||
|
|
@ -562,6 +570,11 @@ public abstract class AbilityImpl implements Ability {
|
|||
watcher.setControllerId(controllerId);
|
||||
}
|
||||
}
|
||||
if (subAbilities != null) {
|
||||
for (Ability subAbility: subAbilities) {
|
||||
subAbility.setControllerId(controllerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -579,6 +592,11 @@ public abstract class AbilityImpl implements Ability {
|
|||
this.sourceId = sourceId;
|
||||
}
|
||||
}
|
||||
if (subAbilities != null) {
|
||||
for (Ability subAbility: subAbilities) {
|
||||
subAbility.setSourceId(sourceId);
|
||||
}
|
||||
}
|
||||
if (watchers != null) {
|
||||
for (Watcher watcher: watchers) {
|
||||
watcher.setSourceId(sourceId);
|
||||
|
|
@ -660,6 +678,23 @@ public abstract class AbilityImpl implements Ability {
|
|||
watchers.add(watcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Ability> getSubAbilities() {
|
||||
if (subAbilities != null)
|
||||
return subAbilities;
|
||||
else
|
||||
return emptyAbilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSubAbility(Ability ability) {
|
||||
if (subAbilities == null)
|
||||
subAbilities = new ArrayList<>();
|
||||
ability.setSourceId(this.sourceId);
|
||||
ability.setControllerId(this.controllerId);
|
||||
subAbilities.add(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsesStack() {
|
||||
return usesStack;
|
||||
|
|
|
|||
|
|
@ -107,8 +107,7 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou
|
|||
}
|
||||
if (card != null) {
|
||||
// add ability to card only once
|
||||
card.addAbility(ability);
|
||||
discard();
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ public class GainAbilityTargetEffect extends ContinuousEffectImpl {
|
|||
for (UUID cardId : targetPointer.getTargets(game, source)) {
|
||||
Card card = game.getCard(cardId);
|
||||
if (card != null) {
|
||||
card.addAbility(ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
affectedTargets++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public class BestowAbility extends SpellAbility {
|
|||
this.addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BestowTypeChangingEffect());
|
||||
ability.setRuleVisible(false);
|
||||
card.addAbility(ability);
|
||||
addSubAbility(ability);
|
||||
}
|
||||
|
||||
public BestowAbility(final BestowAbility ability) {
|
||||
|
|
|
|||
|
|
@ -105,12 +105,12 @@ public class ChampionAbility extends StaticAbility {
|
|||
Ability ability1 = new EntersBattlefieldTriggeredAbility(
|
||||
new SacrificeSourceUnlessPaysEffect(new ChampionExileCost(filter, new StringBuilder(card.getName()).append(" championed permanents").toString())),false);
|
||||
ability1.setRuleVisible(false);
|
||||
card.addAbility(ability1);
|
||||
addSubAbility(ability1);
|
||||
|
||||
// When this permanent leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
Ability ability2 = new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false);
|
||||
ability2.setRuleVisible(false);
|
||||
card.addAbility(ability2);
|
||||
addSubAbility(ability2);
|
||||
}
|
||||
|
||||
public ChampionAbility(final ChampionAbility ability) {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional
|
|||
public ConspireAbility(Card card) {
|
||||
super(Zone.STACK, null);
|
||||
setRuleAtTheTop(false);
|
||||
card.addAbility(new ConspireTriggeredAbility());
|
||||
addSubAbility(new ConspireTriggeredAbility());
|
||||
}
|
||||
|
||||
public ConspireAbility(final ConspireAbility ability) {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts
|
|||
Effect effect = new ReturnToHandTargetEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card.getId()));
|
||||
ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), false));
|
||||
card.addAbility(ability);
|
||||
addSubAbility(ability);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost
|
|||
this.addEvokeCost(manaString);
|
||||
Ability ability = new ConditionalTriggeredAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceEffect()), EvokedCondition.getInstance(), "Sacrifice {this} when it enters the battlefield and was evoked.");
|
||||
ability.setRuleVisible(false);
|
||||
card.addAbility(ability);
|
||||
addSubAbility(ability);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class FadingAbility extends EntersBattlefieldAbility {
|
|||
super(new AddCountersSourceEffect(CounterType.FADE.createInstance(fadeCounter)), "with");
|
||||
Ability ability = new BeginningOfUpkeepTriggeredAbility(new FadingEffect(), TargetController.YOU, false);
|
||||
ability.setRuleVisible(false);
|
||||
card.addAbility(ability);
|
||||
addSubAbility(ability);
|
||||
StringBuilder sb = new StringBuilder("Fading ");
|
||||
sb.append(fadeCounter);
|
||||
sb.append(" <i>(This permanent enters the battlefield with ")
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ public class GraftAbility extends TriggeredAbilityImpl {
|
|||
sb.append(theCardtype.toString().toLowerCase(Locale.ENGLISH)).append(" ");
|
||||
}
|
||||
this.cardtype = sb.toString().trim();
|
||||
card.addAbility(new GraftStaticAbility(amount));
|
||||
addSubAbility(new GraftStaticAbility(amount));
|
||||
}
|
||||
|
||||
public GraftAbility(GraftAbility ability) {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public class HauntAbility extends TriggeredAbilityImpl {
|
|||
|
||||
public HauntAbility(Card card, Effect effect) {
|
||||
super(Zone.ALL, effect , false);
|
||||
card.addAbility(new HauntExileAbility());
|
||||
addSubAbility(new HauntExileAbility());
|
||||
}
|
||||
|
||||
public HauntAbility(final HauntAbility ability) {
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@ public class HideawayAbility extends StaticAbility {
|
|||
super(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new TapSourceEffect(true)));
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new HideawayExileEffect(), false);
|
||||
ability.setRuleVisible(false);
|
||||
card.addAbility(ability);
|
||||
addSubAbility(ability);
|
||||
// Allow controller to look at face down card
|
||||
ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new HideawayLookAtFaceDownCardEffect());
|
||||
ability.setRuleVisible(false);
|
||||
card.addAbility(ability);
|
||||
addSubAbility(ability);
|
||||
}
|
||||
|
||||
public HideawayAbility(final HideawayAbility ability) {
|
||||
|
|
|
|||
|
|
@ -134,9 +134,11 @@ public class LevelerCardBuilder {
|
|||
*
|
||||
* @param card
|
||||
* @param levelAbilities
|
||||
* @return list of levelAbilities to add to card
|
||||
*/
|
||||
public static void construct(Card card, LevelAbility... levelAbilities) {
|
||||
public static List<Ability> construct(LevelAbility... levelAbilities) {
|
||||
LevelerCardBuilder builder = new LevelerCardBuilder();
|
||||
List<Ability> abilities = new ArrayList<>();
|
||||
|
||||
for (LevelAbility levelAbility : levelAbilities) {
|
||||
// set main params
|
||||
|
|
@ -153,22 +155,11 @@ public class LevelerCardBuilder {
|
|||
builder.addAbility(addedAbility);
|
||||
}
|
||||
|
||||
// build static abilities and add them to card
|
||||
for (Ability simpleStaticAbility : builder.build()) {
|
||||
card.addAbility(simpleStaticAbility);
|
||||
}
|
||||
// build static abilities and add them to list
|
||||
abilities.addAll(builder.build());
|
||||
}
|
||||
|
||||
// set max level counters (for ai)
|
||||
if (card instanceof LevelerCard) {
|
||||
int maxValue = 0;
|
||||
for (LevelAbility levelAbility : levelAbilities) {
|
||||
if (levelAbility.getLevel1() > maxValue) {
|
||||
maxValue = levelAbility.getLevel1();
|
||||
}
|
||||
}
|
||||
((LevelerCard) card).setMaxLevelCounters(maxValue);
|
||||
}
|
||||
return abilities;
|
||||
}
|
||||
|
||||
public static class LevelAbility {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public class MadnessAbility extends StaticAbility {
|
|||
@SuppressWarnings("unchecked")
|
||||
public MadnessAbility(Card card, ManaCosts madnessCost) {
|
||||
super(Zone.HAND, new MadnessReplacementEffect((ManaCosts<ManaCost>)madnessCost));
|
||||
card.addAbility(new MadnessTriggeredAbility((ManaCosts<ManaCost>)madnessCost));
|
||||
addSubAbility(new MadnessTriggeredAbility((ManaCosts<ManaCost>)madnessCost));
|
||||
rule = "Madness " + madnessCost.getText() + " <i>(If you discard this card, you may cast it for its madness cost instead of putting it into your graveyard.)<i/>";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ public class ModularAbility extends DiesTriggeredAbility {
|
|||
if (sunburst) {
|
||||
Ability ability = new SunburstAbility(card);
|
||||
ability.setRuleVisible(false);
|
||||
card.addAbility(ability);
|
||||
addSubAbility(ability);
|
||||
} else {
|
||||
card.addAbility(new ModularStaticAbility(amount));
|
||||
addSubAbility(new ModularStaticAbility(amount));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
|
|||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesFaceDownCreatureEffect(morphCosts, (megamorph ? FaceDownType.MEGAMORPHED :FaceDownType.MORPHED)));
|
||||
ability.setWorksFaceDown(true);
|
||||
ability.setRuleVisible(false);
|
||||
card.addAbility(ability);
|
||||
addSubAbility(ability);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ public class ReboundAbility extends TriggeredAbilityImpl {
|
|||
((ZoneChangeEvent) event).getToZone() == Zone.STACK) {
|
||||
Card card = (Card) game.getObject(event.getTargetId());
|
||||
|
||||
if (card.getAbilities().contains(this)) {
|
||||
if (card.getAbilities(game).contains(this)) {
|
||||
this.installReboundEffect = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public class ReplicateAbility extends StaticAbility implements OptionalAdditiona
|
|||
this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderTextMana, new ManaCostsImpl(manaString));
|
||||
this.additionalCost.setRepeatable(true);
|
||||
setRuleAtTheTop(true);
|
||||
card.addAbility(new ReplicateTriggeredAbility());
|
||||
addSubAbility(new ReplicateTriggeredAbility());
|
||||
}
|
||||
|
||||
public ReplicateAbility(final ReplicateAbility ability) {
|
||||
|
|
|
|||
|
|
@ -179,8 +179,8 @@ public class SuspendAbility extends ActivatedAbilityImpl {
|
|||
if (card.getManaCost().isEmpty()) {
|
||||
setRuleAtTheTop(true);
|
||||
}
|
||||
card.addAbility(new SuspendBeginningOfUpkeepTriggeredAbility());
|
||||
card.addAbility(new SuspendPlayCardAbility(card.getCardType().contains(CardType.CREATURE)));
|
||||
addSubAbility(new SuspendBeginningOfUpkeepTriggeredAbility());
|
||||
addSubAbility(new SuspendPlayCardAbility(card.getCardType().contains(CardType.CREATURE)));
|
||||
}
|
||||
ruleText = sb.toString();
|
||||
}
|
||||
|
|
@ -196,18 +196,18 @@ public class SuspendAbility extends ActivatedAbilityImpl {
|
|||
SuspendAbility ability = new SuspendAbility(0, null, card, false);
|
||||
ability.setSourceId(card.getId());
|
||||
ability.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(card.getId(), ability);
|
||||
game.getState().addOtherAbility(card, ability);
|
||||
|
||||
SuspendBeginningOfUpkeepTriggeredAbility ability1 = new SuspendBeginningOfUpkeepTriggeredAbility();
|
||||
ability1.setSourceId(card.getId());
|
||||
ability1.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(card.getId(), ability1);
|
||||
game.getState().addOtherAbility(card, ability1);
|
||||
game.getState().addAbility(ability1, source.getSourceId(), card);
|
||||
|
||||
SuspendPlayCardAbility ability2 = new SuspendPlayCardAbility(card.getCardType().contains(CardType.CREATURE));
|
||||
ability2.setSourceId(card.getId());
|
||||
ability2.setControllerId(card.getOwnerId());
|
||||
game.getState().addOtherAbility(card.getId(), ability2);
|
||||
game.getState().addOtherAbility(card, ability2);
|
||||
game.getState().addAbility(ability2, source.getSourceId(), card);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import java.util.List;
|
|||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Abilities;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.constants.Rarity;
|
||||
|
|
@ -47,7 +48,7 @@ public interface Card extends MageObject {
|
|||
int getCardNumber();
|
||||
Rarity getRarity();
|
||||
void setOwnerId(UUID ownerId);
|
||||
void addAbility(Ability ability);
|
||||
public Abilities<Ability> getAbilities(Game game);
|
||||
void setSpellAbility(SpellAbility ability);
|
||||
SpellAbility getSpellAbility();
|
||||
List<String> getRules(); // gets base card rules
|
||||
|
|
|
|||
|
|
@ -36,10 +36,11 @@ import java.util.UUID;
|
|||
import mage.MageObject;
|
||||
import mage.MageObjectImpl;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Abilities;
|
||||
import mage.abilities.AbilitiesImpl;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.PlayLandAbility;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.keyword.MorphAbility;
|
||||
import mage.abilities.mana.ManaAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
|
|
@ -226,11 +227,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
for (String data : cardState.getInfo().values()) {
|
||||
rules.add(data);
|
||||
}
|
||||
for (Ability ability: cardState.getAbilities()) {
|
||||
rules.add(ability.getRule());
|
||||
}
|
||||
}
|
||||
}
|
||||
// for (Ability ability: state.getAbilities()) {
|
||||
// rules.add(ability.getRule());
|
||||
// }
|
||||
return rules;
|
||||
} catch (Exception e) {
|
||||
logger.error("Exception in rules generation for card: " + this.getName(), e);
|
||||
|
|
@ -238,12 +239,48 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
return rulesError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all base abilities - does not include additional abilities added by
|
||||
* other cards or effects
|
||||
* @return A list of {@link Ability} - this collection is modifiable
|
||||
*/
|
||||
@Override
|
||||
public void addAbility(Ability ability) {
|
||||
ability.setSourceId(this.getId());
|
||||
abilities.add(ability);
|
||||
public Abilities<Ability> getAbilities() {
|
||||
return super.getAbilities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all current abilities - includes additional abilities added by
|
||||
* other cards or effects
|
||||
* @param game
|
||||
* @return A list of {@link Ability} - this collection is not modifiable
|
||||
*/
|
||||
@Override
|
||||
public Abilities<Ability> getAbilities(Game game) {
|
||||
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(objectId);
|
||||
if (otherAbilities == null) {
|
||||
return abilities;
|
||||
}
|
||||
Abilities<Ability> all = new AbilitiesImpl<>();
|
||||
all.addAll(abilities);
|
||||
all.addAll(otherAbilities);
|
||||
return all;
|
||||
}
|
||||
|
||||
protected void addAbility(Ability ability) {
|
||||
ability.setSourceId(this.getId());
|
||||
abilities.add(ability);
|
||||
for (Ability subAbility: ability.getSubAbilities()) {
|
||||
abilities.add(subAbility);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addAbilities(List<Ability> abilities) {
|
||||
for (Ability ability: abilities) {
|
||||
addAbility(ability);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addAbility(Ability ability, Watcher watcher) {
|
||||
addAbility(ability);
|
||||
ability.addWatcher(watcher);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public abstract class LevelerCard extends CardImpl {
|
|||
return maxLevelCounters;
|
||||
}
|
||||
|
||||
public void setMaxLevelCounters(int maxLevelCounters) {
|
||||
protected void setMaxLevelCounters(int maxLevelCounters) {
|
||||
this.maxLevelCounters = maxLevelCounters;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,6 +145,19 @@ public abstract class SplitCard extends CardImpl {
|
|||
return allAbilites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Abilities<Ability> getAbilities(Game game) {
|
||||
Abilities<Ability> allAbilites = new AbilitiesImpl<>();
|
||||
for (Ability ability : super.getAbilities(game)) {
|
||||
if (ability instanceof SpellAbility && !((SpellAbility)ability).getSpellAbilityType().equals(SpellAbilityType.SPLIT)) {
|
||||
allAbilites.add(ability);
|
||||
}
|
||||
}
|
||||
allAbilites.addAll(leftHalfCard.getAbilities(game));
|
||||
allAbilites.addAll(rightHalfCard.getAbilities(game));
|
||||
return allAbilites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRules() {
|
||||
List<String> rules = new ArrayList<>();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package mage.game;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import mage.abilities.Abilities;
|
||||
import mage.abilities.AbilitiesImpl;
|
||||
import mage.abilities.Ability;
|
||||
import mage.counters.Counters;
|
||||
/**
|
||||
*
|
||||
|
|
@ -12,8 +15,10 @@ public class CardState {
|
|||
protected boolean faceDown;
|
||||
protected Map<String, String> info;
|
||||
protected Counters counters;
|
||||
protected Abilities<Ability> abilities;
|
||||
|
||||
private static final Map<String, String> emptyInfo = new HashMap<>();
|
||||
private static final Abilities<Ability> emptyAbilities = new AbilitiesImpl<>();
|
||||
|
||||
public CardState() {
|
||||
counters = new Counters();
|
||||
|
|
@ -26,6 +31,12 @@ public class CardState {
|
|||
info.putAll(state.info);
|
||||
}
|
||||
counters = state.counters.copy();
|
||||
if (state.abilities != null) {
|
||||
abilities = new AbilitiesImpl<>();
|
||||
for (Ability ability: state.abilities) {
|
||||
abilities.add(ability.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CardState copy() {
|
||||
|
|
@ -62,10 +73,37 @@ public class CardState {
|
|||
return info;
|
||||
}
|
||||
|
||||
public Abilities<Ability> getAbilities() {
|
||||
if (abilities == null) {
|
||||
return emptyAbilities;
|
||||
}
|
||||
return abilities;
|
||||
}
|
||||
|
||||
public void addAbility(Ability ability) {
|
||||
if (abilities == null) {
|
||||
abilities = new AbilitiesImpl<>();
|
||||
}
|
||||
abilities.add(ability);
|
||||
for (Ability sub: ability.getSubAbilities()) {
|
||||
abilities.add(sub);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAbilities() {
|
||||
if (abilities != null) {
|
||||
for (Ability ability: abilities) {
|
||||
ability.setSourceId(null);
|
||||
ability.setControllerId(null);
|
||||
}
|
||||
abilities = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
counters.clear();
|
||||
info = null;
|
||||
clearAbilities();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ import mage.watchers.Watchers;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -80,7 +79,6 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
private final Map<UUID, LookedAt> lookedAt = new HashMap<>();
|
||||
private final DelayedTriggeredAbilities delayed;
|
||||
private final SpecialActions specialActions;
|
||||
private final Map<UUID, Abilities<Ability>> otherAbilities = new HashMap<>();
|
||||
private final TurnMods turnMods;
|
||||
private final Watchers watchers;
|
||||
|
||||
|
|
@ -156,9 +154,6 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.values.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
this.zones.putAll(state.zones);
|
||||
for (Map.Entry<UUID, Abilities<Ability>> entry: state.otherAbilities.entrySet()) {
|
||||
otherAbilities.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
this.paused = state.paused;
|
||||
this.simultaneousEvents.addAll(state.simultaneousEvents);
|
||||
for (Map.Entry<UUID, CardState> entry: state.cardState.entrySet()) {
|
||||
|
|
@ -601,6 +596,9 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
watcher.setSourceId(attachedTo.getId());
|
||||
watchers.add(watcher);
|
||||
}
|
||||
for (Ability sub: ability.getSubAbilities()) {
|
||||
addAbility(sub, sourceId, attachedTo);
|
||||
}
|
||||
}
|
||||
|
||||
public void addCommandObject(CommandObject commandObject) {
|
||||
|
|
@ -678,41 +676,32 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
* @return
|
||||
*/
|
||||
public Abilities<ActivatedAbility> getActivatedOtherAbilities(UUID objectId, Zone zone) {
|
||||
if (otherAbilities.containsKey(objectId)) {
|
||||
return otherAbilities.get(objectId).getActivatedAbilities(zone);
|
||||
if (cardState.containsKey(objectId)) {
|
||||
return cardState.get(objectId).getAbilities().getActivatedAbilities(zone);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Abilities<Ability> getAllOtherAbilities(UUID objectId) {
|
||||
if (otherAbilities.containsKey(objectId)) {
|
||||
return otherAbilities.get(objectId);
|
||||
if (cardState.containsKey(objectId)) {
|
||||
return cardState.get(objectId).getAbilities();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void addOtherAbility(UUID objectId, Ability ability) {
|
||||
if (!otherAbilities.containsKey(objectId)) {
|
||||
otherAbilities.put(objectId, new AbilitiesImpl(ability));
|
||||
} else {
|
||||
otherAbilities.get(objectId).add(ability);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the ability to continuous or triggered abilities
|
||||
* @param ability
|
||||
* @param card
|
||||
*/
|
||||
public void addOtherAbility(Ability ability, Card card) {
|
||||
addOtherAbility(card.getId(), ability);
|
||||
addAbility(ability, card.getId(), card);
|
||||
}
|
||||
|
||||
private void resetOtherAbilities() {
|
||||
otherAbilities.clear();
|
||||
public void addOtherAbility(Card attachedTo, Ability ability) {
|
||||
ability.setSourceId(attachedTo.getId());
|
||||
ability.setControllerId(attachedTo.getOwnerId());
|
||||
if (!cardState.containsKey(attachedTo.getId())) {
|
||||
cardState.put(attachedTo.getId(), new CardState());
|
||||
}
|
||||
cardState.get(attachedTo.getId()).addAbility(ability);
|
||||
addAbility(ability, attachedTo.getId(), attachedTo);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -734,7 +723,9 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
triggers.removeAllGainedAbilities();
|
||||
getContinuousEffects().removeAllTemporaryEffects();
|
||||
this.setLegendaryRuleActive(true);
|
||||
this.resetOtherAbilities();
|
||||
for (CardState state: cardState.values()) {
|
||||
state.clearAbilities();
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
|
@ -754,7 +745,6 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
legendaryRuleActive = true;
|
||||
gameOver = false;
|
||||
specialActions.clear();
|
||||
otherAbilities.clear();
|
||||
cardState.clear();
|
||||
combat.clear();
|
||||
turnMods.clear();
|
||||
|
|
|
|||
|
|
@ -125,7 +125,6 @@ public interface Permanent extends Card, Controllable {
|
|||
String getValue();
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
void addAbility(Ability ability);
|
||||
@Deprecated
|
||||
void addAbility(Ability ability, Game game);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ import java.util.Map;
|
|||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Abilities;
|
||||
import mage.abilities.AbilitiesImpl;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
|
|
@ -244,6 +246,16 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Abilities<Ability> getAbilities() {
|
||||
return abilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Abilities<Ability> getAbilities(Game game) {
|
||||
return abilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void addAbility(Ability ability) {
|
||||
|
|
|
|||
|
|
@ -601,6 +601,11 @@ public class Spell implements StackObject, Card {
|
|||
return card.getAbilities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Abilities<Ability> getAbilities(Game game) {
|
||||
return card.getAbilities(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAbility(UUID abilityId, Game game) {
|
||||
return card.hasAbility(abilityId, game);
|
||||
|
|
@ -674,7 +679,6 @@ public class Spell implements StackObject, Card {
|
|||
spellAbilities.add(spellAbility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAbility(Ability ability) {}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -487,6 +487,16 @@ public class StackAbility implements StackObject, Ability {
|
|||
throw new UnsupportedOperationException("Not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Ability> getSubAbilities() {
|
||||
return this.ability.getSubAbilities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSubAbility(Ability ability) {
|
||||
throw new UnsupportedOperationException("Not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MageObject getSourceObject(Game game) {
|
||||
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue