mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
[OTJ] Implementing "commit crime" mechanic (#11859)
* [OTJ] Implement Oko the Ringleader * [OTJ] Implement Duelist of the Mind * update implementation of crime mechanic to match new info * [OTJ] Implement Marauding Sphinx * [OTJ] Implement Hardbristle Bandit * [OTJ] Implement Intimidation Campaign * [OTJ] Implement Freestrider Lookout * add initial test * add more tests * apply requested changes * applied requested changes * fix verify failure
This commit is contained in:
parent
6d7f42e5d7
commit
fa0f9f3d00
13 changed files with 896 additions and 2 deletions
57
Mage.Sets/src/mage/cards/d/DuelistOfTheMind.java
Normal file
57
Mage.Sets/src/mage/cards/d/DuelistOfTheMind.java
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
package mage.cards.d;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.common.CommittedCrimeTriggeredAbility;
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.dynamicvalue.common.CardsDrawnThisTurnDynamicValue;
|
||||||
|
import mage.abilities.effects.common.DrawDiscardControllerEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect;
|
||||||
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
|
import mage.abilities.keyword.VigilanceAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class DuelistOfTheMind extends CardImpl {
|
||||||
|
|
||||||
|
public DuelistOfTheMind(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.HUMAN);
|
||||||
|
this.subtype.add(SubType.ADVISOR);
|
||||||
|
this.power = new MageInt(0);
|
||||||
|
this.toughness = new MageInt(3);
|
||||||
|
|
||||||
|
// Flying
|
||||||
|
this.addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
|
// Vigilance
|
||||||
|
this.addAbility(VigilanceAbility.getInstance());
|
||||||
|
|
||||||
|
// Duelist of the Mind's power is equal to the number of cards you've drawn this turn.
|
||||||
|
this.addAbility(new SimpleStaticAbility(
|
||||||
|
Zone.ALL, new SetBasePowerSourceEffect(CardsDrawnThisTurnDynamicValue.instance)
|
||||||
|
).addHint(CardsDrawnThisTurnDynamicValue.getHint()));
|
||||||
|
|
||||||
|
// Whenever you commit a crime, you may draw a card. If you do, discard a card. This ability triggers only once each turn.
|
||||||
|
this.addAbility(new CommittedCrimeTriggeredAbility(
|
||||||
|
new DrawDiscardControllerEffect(1, 1, true), false
|
||||||
|
).setTriggersOnceEachTurn(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DuelistOfTheMind(final DuelistOfTheMind card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DuelistOfTheMind copy() {
|
||||||
|
return new DuelistOfTheMind(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
Mage.Sets/src/mage/cards/f/FreestriderLookout.java
Normal file
47
Mage.Sets/src/mage/cards/f/FreestriderLookout.java
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package mage.cards.f;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.common.CommittedCrimeTriggeredAbility;
|
||||||
|
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
|
||||||
|
import mage.abilities.keyword.ReachAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.PutCards;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.filter.StaticFilters;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class FreestriderLookout extends CardImpl {
|
||||||
|
|
||||||
|
public FreestriderLookout(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.HUMAN);
|
||||||
|
this.subtype.add(SubType.ROGUE);
|
||||||
|
this.power = new MageInt(3);
|
||||||
|
this.toughness = new MageInt(3);
|
||||||
|
|
||||||
|
// Reach
|
||||||
|
this.addAbility(ReachAbility.getInstance());
|
||||||
|
|
||||||
|
// Whenever you commit a crime, look at the top five cards of your library. You may put a land card from among them onto the battlefield tapped. Put the rest on the bottom of your library in a random order. This ability triggers only once each turn.
|
||||||
|
this.addAbility(new CommittedCrimeTriggeredAbility(new LookLibraryAndPickControllerEffect(
|
||||||
|
5, 1, StaticFilters.FILTER_CARD_LAND_A,
|
||||||
|
PutCards.BATTLEFIELD_TAPPED, PutCards.BOTTOM_RANDOM
|
||||||
|
)).setTriggersOnceEachTurn(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FreestriderLookout(final FreestriderLookout card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FreestriderLookout copy() {
|
||||||
|
return new FreestriderLookout(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Mage.Sets/src/mage/cards/h/HardbristleBandit.java
Normal file
42
Mage.Sets/src/mage/cards/h/HardbristleBandit.java
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
package mage.cards.h;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.common.CommittedCrimeTriggeredAbility;
|
||||||
|
import mage.abilities.effects.common.UntapSourceEffect;
|
||||||
|
import mage.abilities.mana.AnyColorManaAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class HardbristleBandit extends CardImpl {
|
||||||
|
|
||||||
|
public HardbristleBandit(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.PLANT);
|
||||||
|
this.subtype.add(SubType.ROGUE);
|
||||||
|
this.power = new MageInt(1);
|
||||||
|
this.toughness = new MageInt(1);
|
||||||
|
|
||||||
|
// {T}: Add one mana of any color.
|
||||||
|
this.addAbility(new AnyColorManaAbility());
|
||||||
|
|
||||||
|
// Whenever you commit a crime, untap Hardbristle Bandit. This ability triggers only once each turn.
|
||||||
|
this.addAbility(new CommittedCrimeTriggeredAbility(new UntapSourceEffect()).setTriggersOnceEachTurn(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private HardbristleBandit(final HardbristleBandit card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HardbristleBandit copy() {
|
||||||
|
return new HardbristleBandit(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Mage.Sets/src/mage/cards/i/IntimidationCampaign.java
Normal file
44
Mage.Sets/src/mage/cards/i/IntimidationCampaign.java
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package mage.cards.i;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.CommittedCrimeTriggeredAbility;
|
||||||
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
|
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||||
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
|
import mage.abilities.effects.common.LoseLifeOpponentsEffect;
|
||||||
|
import mage.abilities.effects.common.ReturnToHandSourceEffect;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class IntimidationCampaign extends CardImpl {
|
||||||
|
|
||||||
|
public IntimidationCampaign(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{B}");
|
||||||
|
|
||||||
|
// When Intimidation Campaign enters the battlefield, each opponent loses 1 life, you gain 1 life, and you draw a card.
|
||||||
|
Ability ability = new EntersBattlefieldTriggeredAbility(new LoseLifeOpponentsEffect(1));
|
||||||
|
ability.addEffect(new GainLifeEffect(1).concatBy(","));
|
||||||
|
ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy(", and you"));
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
// Whenever you commit a crime, you may return Intimidation Campaign to its owner's hand.
|
||||||
|
this.addAbility(new CommittedCrimeTriggeredAbility(
|
||||||
|
new ReturnToHandSourceEffect(true), true
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntimidationCampaign(final IntimidationCampaign card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntimidationCampaign copy() {
|
||||||
|
return new IntimidationCampaign(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
Mage.Sets/src/mage/cards/m/MaraudingSphinx.java
Normal file
51
Mage.Sets/src/mage/cards/m/MaraudingSphinx.java
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
package mage.cards.m;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.common.CommittedCrimeTriggeredAbility;
|
||||||
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
|
import mage.abilities.effects.keyword.SurveilEffect;
|
||||||
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
|
import mage.abilities.keyword.VigilanceAbility;
|
||||||
|
import mage.abilities.keyword.WardAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class MaraudingSphinx extends CardImpl {
|
||||||
|
|
||||||
|
public MaraudingSphinx(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.SPHINX);
|
||||||
|
this.subtype.add(SubType.ROGUE);
|
||||||
|
this.power = new MageInt(3);
|
||||||
|
this.toughness = new MageInt(5);
|
||||||
|
|
||||||
|
// Flying
|
||||||
|
this.addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
|
// Vigilance
|
||||||
|
this.addAbility(VigilanceAbility.getInstance());
|
||||||
|
|
||||||
|
// Ward {2}
|
||||||
|
this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}")));
|
||||||
|
|
||||||
|
// Whenever you commit a crime, surveil 2. This ability triggers only once each turn.
|
||||||
|
this.addAbility(new CommittedCrimeTriggeredAbility(new SurveilEffect(2), false).setTriggersOnceEachTurn(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private MaraudingSphinx(final MaraudingSphinx card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MaraudingSphinx copy() {
|
||||||
|
return new MaraudingSphinx(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
142
Mage.Sets/src/mage/cards/o/OkoTheRingleader.java
Normal file
142
Mage.Sets/src/mage/cards/o/OkoTheRingleader.java
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
package mage.cards.o;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.LoyaltyAbility;
|
||||||
|
import mage.abilities.common.BeginningOfCombatTriggeredAbility;
|
||||||
|
import mage.abilities.condition.common.CommittedCrimeCondition;
|
||||||
|
import mage.abilities.decorator.ConditionalOneShotEffect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
|
||||||
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
|
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||||
|
import mage.abilities.effects.common.discard.DiscardControllerEffect;
|
||||||
|
import mage.abilities.keyword.HexproofAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.filter.FilterPermanent;
|
||||||
|
import mage.filter.common.FilterNonlandPermanent;
|
||||||
|
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.token.ElkToken;
|
||||||
|
import mage.target.common.TargetControlledCreaturePermanent;
|
||||||
|
import mage.util.functions.CopyApplier;
|
||||||
|
import mage.watchers.common.CommittedCrimeWatcher;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class OkoTheRingleader extends CardImpl {
|
||||||
|
|
||||||
|
public OkoTheRingleader(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{G}{U}");
|
||||||
|
|
||||||
|
this.supertype.add(SuperType.LEGENDARY);
|
||||||
|
this.subtype.add(SubType.OKO);
|
||||||
|
this.setStartingLoyalty(3);
|
||||||
|
|
||||||
|
// At the beginning of combat on your turn, Oko, the Ringleader becomes a copy of up to one target creature you control until end of turn, except he has hexproof.
|
||||||
|
Ability ability = new BeginningOfCombatTriggeredAbility(
|
||||||
|
new OkoTheRingleaderCopySelfEffect(), TargetController.YOU, false
|
||||||
|
);
|
||||||
|
ability.addTarget(new TargetControlledCreaturePermanent(0, 1));
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
// +1: Draw two cards. If you've committed a crime this turn, discard a card. Otherwise, discard two cards.
|
||||||
|
ability = new LoyaltyAbility(new DrawCardSourceControllerEffect(2), 1);
|
||||||
|
ability.addEffect(new ConditionalOneShotEffect(
|
||||||
|
new DiscardControllerEffect(1), new DiscardControllerEffect(2),
|
||||||
|
CommittedCrimeCondition.instance, "if you've committed a crime this turn, " +
|
||||||
|
"discard a card. Otherwise, discard two cards"
|
||||||
|
));
|
||||||
|
this.addAbility(ability.addHint(CommittedCrimeCondition.getHint()), new CommittedCrimeWatcher());
|
||||||
|
|
||||||
|
// -1: Create a 3/3 green Elk creature token.
|
||||||
|
this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new ElkToken()), -1));
|
||||||
|
|
||||||
|
// -5: For each other nonland permanent you control, create a token that's a copy of that permanent.
|
||||||
|
this.addAbility(new LoyaltyAbility(new OkoTheRingleaderCopyTokenEffect(), -5));
|
||||||
|
}
|
||||||
|
|
||||||
|
private OkoTheRingleader(final OkoTheRingleader card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OkoTheRingleader copy() {
|
||||||
|
return new OkoTheRingleader(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OkoTheRingleaderCopySelfEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
private static final CopyApplier applier = new CopyApplier() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, MageObject blueprint, Ability source, UUID targetObjectId) {
|
||||||
|
blueprint.getAbilities().add(HexproofAbility.getInstance());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
OkoTheRingleaderCopySelfEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
staticText = "{this} becomes a copy of up to one target creature " +
|
||||||
|
"you control until end of turn, except he has hexproof";
|
||||||
|
}
|
||||||
|
|
||||||
|
private OkoTheRingleaderCopySelfEffect(final OkoTheRingleaderCopySelfEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OkoTheRingleaderCopySelfEffect copy() {
|
||||||
|
return new OkoTheRingleaderCopySelfEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
|
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
|
if (permanent == null || creature == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
game.copyPermanent(Duration.EndOfTurn, creature, permanent.getId(), source, applier);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OkoTheRingleaderCopyTokenEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
private static final FilterPermanent filter = new FilterNonlandPermanent();
|
||||||
|
|
||||||
|
static {
|
||||||
|
filter.add(AnotherPredicate.instance);
|
||||||
|
filter.add(TargetController.YOU.getControllerPredicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
OkoTheRingleaderCopyTokenEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
staticText = "for each other nonland permanent you control, create a token that's a copy of that permanent";
|
||||||
|
}
|
||||||
|
|
||||||
|
private OkoTheRingleaderCopyTokenEffect(final OkoTheRingleaderCopyTokenEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OkoTheRingleaderCopyTokenEffect copy() {
|
||||||
|
return new OkoTheRingleaderCopyTokenEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) {
|
||||||
|
new CreateTokenCopyTargetEffect().setSavedPermanent(permanent).apply(game, source);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,17 +41,21 @@ public final class OutlawsOfThunderJunction extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Creosote Heath", 255, Rarity.COMMON, mage.cards.c.CreosoteHeath.class));
|
cards.add(new SetCardInfo("Creosote Heath", 255, Rarity.COMMON, mage.cards.c.CreosoteHeath.class));
|
||||||
cards.add(new SetCardInfo("Cunning Coyote", 118, Rarity.UNCOMMON, mage.cards.c.CunningCoyote.class));
|
cards.add(new SetCardInfo("Cunning Coyote", 118, Rarity.UNCOMMON, mage.cards.c.CunningCoyote.class));
|
||||||
cards.add(new SetCardInfo("Desperate Bloodseeker", 86, Rarity.COMMON, mage.cards.d.DesperateBloodseeker.class));
|
cards.add(new SetCardInfo("Desperate Bloodseeker", 86, Rarity.COMMON, mage.cards.d.DesperateBloodseeker.class));
|
||||||
|
cards.add(new SetCardInfo("Duelist of the Mind", 45, Rarity.RARE, mage.cards.d.DuelistOfTheMind.class));
|
||||||
cards.add(new SetCardInfo("Eroded Canyon", 256, Rarity.COMMON, mage.cards.e.ErodedCanyon.class));
|
cards.add(new SetCardInfo("Eroded Canyon", 256, Rarity.COMMON, mage.cards.e.ErodedCanyon.class));
|
||||||
cards.add(new SetCardInfo("Festering Gulch", 257, Rarity.COMMON, mage.cards.f.FesteringGulch.class));
|
cards.add(new SetCardInfo("Festering Gulch", 257, Rarity.COMMON, mage.cards.f.FesteringGulch.class));
|
||||||
cards.add(new SetCardInfo("Forest", 276, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Forest", 276, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Forlorn Flats", 258, Rarity.COMMON, mage.cards.f.ForlornFlats.class));
|
cards.add(new SetCardInfo("Forlorn Flats", 258, Rarity.COMMON, mage.cards.f.ForlornFlats.class));
|
||||||
cards.add(new SetCardInfo("Form a Posse", 204, Rarity.UNCOMMON, mage.cards.f.FormAPosse.class));
|
cards.add(new SetCardInfo("Form a Posse", 204, Rarity.UNCOMMON, mage.cards.f.FormAPosse.class));
|
||||||
|
cards.add(new SetCardInfo("Freestrider Lookout", 163, Rarity.RARE, mage.cards.f.FreestriderLookout.class));
|
||||||
cards.add(new SetCardInfo("Frontier Seeker", 13, Rarity.UNCOMMON, mage.cards.f.FrontierSeeker.class));
|
cards.add(new SetCardInfo("Frontier Seeker", 13, Rarity.UNCOMMON, mage.cards.f.FrontierSeeker.class));
|
||||||
|
cards.add(new SetCardInfo("Hardbristle Bandit", 168, Rarity.COMMON, mage.cards.h.HardbristleBandit.class));
|
||||||
cards.add(new SetCardInfo("Hell to Pay", 126, Rarity.RARE, mage.cards.h.HellToPay.class));
|
cards.add(new SetCardInfo("Hell to Pay", 126, Rarity.RARE, mage.cards.h.HellToPay.class));
|
||||||
cards.add(new SetCardInfo("High Noon", 15, Rarity.RARE, mage.cards.h.HighNoon.class));
|
cards.add(new SetCardInfo("High Noon", 15, Rarity.RARE, mage.cards.h.HighNoon.class));
|
||||||
cards.add(new SetCardInfo("Holy Cow", 16, Rarity.COMMON, mage.cards.h.HolyCow.class));
|
cards.add(new SetCardInfo("Holy Cow", 16, Rarity.COMMON, mage.cards.h.HolyCow.class));
|
||||||
cards.add(new SetCardInfo("Honest Rutstein", 207, Rarity.UNCOMMON, mage.cards.h.HonestRutstein.class));
|
cards.add(new SetCardInfo("Honest Rutstein", 207, Rarity.UNCOMMON, mage.cards.h.HonestRutstein.class));
|
||||||
cards.add(new SetCardInfo("Inspiring Vantage", 269, Rarity.RARE, mage.cards.i.InspiringVantage.class));
|
cards.add(new SetCardInfo("Inspiring Vantage", 269, Rarity.RARE, mage.cards.i.InspiringVantage.class));
|
||||||
|
cards.add(new SetCardInfo("Intimidation Campaign", 208, Rarity.UNCOMMON, mage.cards.i.IntimidationCampaign.class));
|
||||||
cards.add(new SetCardInfo("Island", 273, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Island", 273, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Jagged Barrens", 259, Rarity.COMMON, mage.cards.j.JaggedBarrens.class));
|
cards.add(new SetCardInfo("Jagged Barrens", 259, Rarity.COMMON, mage.cards.j.JaggedBarrens.class));
|
||||||
cards.add(new SetCardInfo("Jolene, Plundering Pugilist", 210, Rarity.UNCOMMON, mage.cards.j.JolenePlunderingPugilist.class));
|
cards.add(new SetCardInfo("Jolene, Plundering Pugilist", 210, Rarity.UNCOMMON, mage.cards.j.JolenePlunderingPugilist.class));
|
||||||
|
|
@ -60,7 +64,9 @@ public final class OutlawsOfThunderJunction extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Loan Shark", 55, Rarity.COMMON, mage.cards.l.LoanShark.class));
|
cards.add(new SetCardInfo("Loan Shark", 55, Rarity.COMMON, mage.cards.l.LoanShark.class));
|
||||||
cards.add(new SetCardInfo("Lonely Arroyo", 260, Rarity.COMMON, mage.cards.l.LonelyArroyo.class));
|
cards.add(new SetCardInfo("Lonely Arroyo", 260, Rarity.COMMON, mage.cards.l.LonelyArroyo.class));
|
||||||
cards.add(new SetCardInfo("Lush Oasis", 261, Rarity.COMMON, mage.cards.l.LushOasis.class));
|
cards.add(new SetCardInfo("Lush Oasis", 261, Rarity.COMMON, mage.cards.l.LushOasis.class));
|
||||||
|
cards.add(new SetCardInfo("Marauding Sphinx", 56, Rarity.UNCOMMON, mage.cards.m.MaraudingSphinx.class));
|
||||||
cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Oko, the Ringleader", 223, Rarity.MYTHIC, mage.cards.o.OkoTheRingleader.class));
|
||||||
cards.add(new SetCardInfo("Plains", 272, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 272, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Plan the Heist", 62, Rarity.UNCOMMON, mage.cards.p.PlanTheHeist.class));
|
cards.add(new SetCardInfo("Plan the Heist", 62, Rarity.UNCOMMON, mage.cards.p.PlanTheHeist.class));
|
||||||
cards.add(new SetCardInfo("Rakish Crew", 99, Rarity.UNCOMMON, mage.cards.r.RakishCrew.class));
|
cards.add(new SetCardInfo("Rakish Crew", 99, Rarity.UNCOMMON, mage.cards.r.RakishCrew.class));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,275 @@
|
||||||
|
package org.mage.test.cards.abilities.keywords;
|
||||||
|
|
||||||
|
import mage.abilities.common.CommittedCrimeTriggeredAbility;
|
||||||
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public class CommittedCrimeTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
private void makeTester() {
|
||||||
|
addCustomCardWithAbility(
|
||||||
|
"tester", playerA, new CommittedCrimeTriggeredAbility(new GainLifeEffect(1), false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String spike = "Lava Spike";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpikeOpponent() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||||
|
addCard(Zone.HAND, playerA, spike);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, spike, playerB);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20 - 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpikeSelf() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||||
|
addCard(Zone.HAND, playerA, spike);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, spike, playerA);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20 - 3);
|
||||||
|
assertLife(playerB, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String voidslime = "Voidslime";
|
||||||
|
private static final String sanctifier = "Cathedral Sanctifier";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCounterSpellOpponent() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 3);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Plains");
|
||||||
|
addCard(Zone.HAND, playerA, voidslime);
|
||||||
|
addCard(Zone.HAND, playerB, sanctifier);
|
||||||
|
|
||||||
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, sanctifier);
|
||||||
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, voidslime, sanctifier);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(2, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCounterAbilityOpponent() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 3);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Plains");
|
||||||
|
addCard(Zone.HAND, playerA, voidslime);
|
||||||
|
addCard(Zone.HAND, playerB, sanctifier);
|
||||||
|
|
||||||
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, sanctifier);
|
||||||
|
waitStackResolved(2, PhaseStep.PRECOMBAT_MAIN, true);
|
||||||
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, voidslime, "stack");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(2, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCounterSpellSelf() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 3);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains");
|
||||||
|
addCard(Zone.HAND, playerA, voidslime);
|
||||||
|
addCard(Zone.HAND, playerA, sanctifier);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sanctifier);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, voidslime, sanctifier);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCounterAbilitySelf() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 3);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains");
|
||||||
|
addCard(Zone.HAND, playerA, voidslime);
|
||||||
|
addCard(Zone.HAND, playerA, sanctifier);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sanctifier);
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, voidslime, "stack");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String bear = "Grizzly Bears";
|
||||||
|
private static final String murder = "Murder";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMurderOpponent() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, bear);
|
||||||
|
addCard(Zone.HAND, playerA, murder);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, murder, bear);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerB, bear, 0);
|
||||||
|
assertGraveyardCount(playerB, bear, 1);
|
||||||
|
assertGraveyardCount(playerA, murder, 1);
|
||||||
|
assertLife(playerA, 20 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMurderSelf() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, bear);
|
||||||
|
addCard(Zone.HAND, playerA, murder);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, murder, bear);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, bear, 0);
|
||||||
|
assertGraveyardCount(playerA, bear, 1);
|
||||||
|
assertGraveyardCount(playerA, murder, 1);
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String purge = "Coffin Purge";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGraveyardOpponent() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp");
|
||||||
|
addCard(Zone.HAND, playerA, purge);
|
||||||
|
addCard(Zone.GRAVEYARD, playerB, bear);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, purge, bear);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerB, bear, 0);
|
||||||
|
assertExileCount(playerB, bear, 1);
|
||||||
|
assertLife(playerA, 20 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGraveyardSelf() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp");
|
||||||
|
addCard(Zone.HAND, playerA, purge);
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, bear);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, purge, bear);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerA, bear, 0);
|
||||||
|
assertExileCount(playerA, bear, 1);
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String desert = "Sunscorched Desert";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTriggerOpponent() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.HAND, playerA, desert);
|
||||||
|
|
||||||
|
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, desert);
|
||||||
|
addTarget(playerA, playerB);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20 - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTriggerSelf() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.HAND, playerA, desert);
|
||||||
|
|
||||||
|
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, desert);
|
||||||
|
addTarget(playerA, playerA);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20 - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String fireslinger = "Goblin Fireslinger";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testActivateOpponent() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, fireslinger);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}", playerB);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20 + 1);
|
||||||
|
assertLife(playerB, 20 - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testActivateSelf() {
|
||||||
|
makeTester();
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, fireslinger);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}", playerA);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerA, 20 - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -142,14 +142,14 @@ public class VerifyCardDataTest {
|
||||||
skipListAddName(SKIP_LIST_TYPE, "UNH", "Old Fogey"); // uses summon word as a joke card
|
skipListAddName(SKIP_LIST_TYPE, "UNH", "Old Fogey"); // uses summon word as a joke card
|
||||||
skipListAddName(SKIP_LIST_TYPE, "UND", "Old Fogey");
|
skipListAddName(SKIP_LIST_TYPE, "UND", "Old Fogey");
|
||||||
skipListAddName(SKIP_LIST_TYPE, "UST", "capital offense"); // uses "instant" instead "Instant" as a joke card
|
skipListAddName(SKIP_LIST_TYPE, "UST", "capital offense"); // uses "instant" instead "Instant" as a joke card
|
||||||
skipListAddName(SKIP_LIST_TYPE, "OTJ", "Lonely Arroyo"); // temporary
|
skipListAddName(SKIP_LIST_TYPE, "OTJ", "Arid Archway"); // temporary
|
||||||
|
|
||||||
// subtype
|
// subtype
|
||||||
// skipListAddName(SKIP_LIST_SUBTYPE, set, cardName);
|
// skipListAddName(SKIP_LIST_SUBTYPE, set, cardName);
|
||||||
skipListAddName(SKIP_LIST_SUBTYPE, "UGL", "Miss Demeanor"); // uses multiple types as a joke card: Lady, of, Proper, Etiquette
|
skipListAddName(SKIP_LIST_SUBTYPE, "UGL", "Miss Demeanor"); // uses multiple types as a joke card: Lady, of, Proper, Etiquette
|
||||||
skipListAddName(SKIP_LIST_SUBTYPE, "UGL", "Elvish Impersonators"); // subtype is "Elves" pun
|
skipListAddName(SKIP_LIST_SUBTYPE, "UGL", "Elvish Impersonators"); // subtype is "Elves" pun
|
||||||
skipListAddName(SKIP_LIST_SUBTYPE, "UND", "Elvish Impersonators");
|
skipListAddName(SKIP_LIST_SUBTYPE, "UND", "Elvish Impersonators");
|
||||||
skipListAddName(SKIP_LIST_SUBTYPE, "OTJ", "Lonely Arroyo"); // temporary
|
skipListAddName(SKIP_LIST_SUBTYPE, "OTJ", "Arid Archway"); // temporary
|
||||||
|
|
||||||
// number
|
// number
|
||||||
// skipListAddName(SKIP_LIST_NUMBER, set, cardName);
|
// skipListAddName(SKIP_LIST_NUMBER, set, cardName);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
package mage.abilities.common;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Controllable;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.Ownerable;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
import mage.game.stack.StackObject;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public class CommittedCrimeTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
|
public CommittedCrimeTriggeredAbility(Effect effect) {
|
||||||
|
this(effect, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommittedCrimeTriggeredAbility(Effect effect, boolean optional) {
|
||||||
|
super(Zone.BATTLEFIELD, effect, optional);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommittedCrimeTriggeredAbility(final CommittedCrimeTriggeredAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommittedCrimeTriggeredAbility copy() {
|
||||||
|
return new CommittedCrimeTriggeredAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkEventType(GameEvent event, Game game) {
|
||||||
|
switch (event.getType()) {
|
||||||
|
case SPELL_CAST:
|
||||||
|
case ACTIVATED_ABILITY:
|
||||||
|
case TRIGGERED_ABILITY:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
return isControlledBy(getCriminal(event, game));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UUID getCriminal(GameEvent event, Game game) {
|
||||||
|
UUID controllerId;
|
||||||
|
Ability ability;
|
||||||
|
switch (event.getType()) {
|
||||||
|
case SPELL_CAST:
|
||||||
|
Spell spell = game.getSpell(event.getTargetId());
|
||||||
|
if (spell == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
controllerId = spell.getControllerId();
|
||||||
|
ability = spell.getSpellAbility();
|
||||||
|
break;
|
||||||
|
case ACTIVATED_ABILITY:
|
||||||
|
case TRIGGERED_ABILITY:
|
||||||
|
StackObject stackObject = game.getStack().getStackObject(event.getTargetId());
|
||||||
|
if (stackObject == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
controllerId = stackObject.getControllerId();
|
||||||
|
ability = stackObject.getStackAbility();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (controllerId == null || ability == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Set<UUID> opponents = game.getOpponents(controllerId);
|
||||||
|
Set<UUID> targets = CardUtil.getAllSelectedTargets(ability, game);
|
||||||
|
// an opponent
|
||||||
|
if (targets
|
||||||
|
.stream()
|
||||||
|
.anyMatch(opponents::contains)
|
||||||
|
// an opponent's permanent
|
||||||
|
|| targets
|
||||||
|
.stream()
|
||||||
|
.map(game::getPermanent)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(Controllable::getControllerId)
|
||||||
|
.anyMatch(opponents::contains)
|
||||||
|
// an opponent's spell or ability
|
||||||
|
|| targets
|
||||||
|
.stream()
|
||||||
|
.map(game.getStack()::getStackObject)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(Controllable::getControllerId)
|
||||||
|
.anyMatch(opponents::contains)
|
||||||
|
// a card in an opponent's graveyard
|
||||||
|
|| targets
|
||||||
|
.stream()
|
||||||
|
.filter(uuid -> Zone.GRAVEYARD.match(game.getState().getZone(uuid)))
|
||||||
|
.map(game::getCard)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(Ownerable::getOwnerId)
|
||||||
|
.anyMatch(opponents::contains)) {
|
||||||
|
return controllerId;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package mage.abilities.condition.common;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.condition.Condition;
|
||||||
|
import mage.abilities.hint.ConditionHint;
|
||||||
|
import mage.abilities.hint.Hint;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.watchers.common.CommittedCrimeWatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* requires CommittedCrimeWatcher
|
||||||
|
*
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public enum CommittedCrimeCondition implements Condition {
|
||||||
|
instance;
|
||||||
|
private static final Hint hint = new ConditionHint(instance, "You committed a crime this turn");
|
||||||
|
|
||||||
|
public static Hint getHint() {
|
||||||
|
return hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
return CommittedCrimeWatcher.checkCriminality(game, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "you've committed a crime this turn";
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Mage/src/main/java/mage/game/permanent/token/ElkToken.java
Normal file
28
Mage/src/main/java/mage/game/permanent/token/ElkToken.java
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package mage.game.permanent.token;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class ElkToken extends TokenImpl {
|
||||||
|
|
||||||
|
public ElkToken() {
|
||||||
|
super("Elk Token", "3/3 green Elk creature token");
|
||||||
|
cardType.add(CardType.CREATURE);
|
||||||
|
color.setGreen(true);
|
||||||
|
subtype.add(SubType.ELK);
|
||||||
|
power = new MageInt(3);
|
||||||
|
toughness = new MageInt(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ElkToken(final ElkToken token) {
|
||||||
|
super(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElkToken copy() {
|
||||||
|
return new ElkToken(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
package mage.watchers.common;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.CommittedCrimeTriggeredAbility;
|
||||||
|
import mage.constants.WatcherScope;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.watchers.Watcher;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public class CommittedCrimeWatcher extends Watcher {
|
||||||
|
|
||||||
|
// players who committed a crime this turn
|
||||||
|
private final Set<UUID> criminals = new HashSet<>();
|
||||||
|
|
||||||
|
public CommittedCrimeWatcher() {
|
||||||
|
super(WatcherScope.GAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void watch(GameEvent event, Game game) {
|
||||||
|
switch (event.getType()) {
|
||||||
|
case SPELL_CAST:
|
||||||
|
case ACTIVATED_ABILITY:
|
||||||
|
case TRIGGERED_ABILITY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Optional.ofNullable(CommittedCrimeTriggeredAbility.getCriminal(event, game)).ifPresent(criminals::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
super.reset();
|
||||||
|
criminals.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkCriminality(Game game, Ability source) {
|
||||||
|
return game
|
||||||
|
.getState()
|
||||||
|
.getWatcher(CommittedCrimeWatcher.class)
|
||||||
|
.criminals
|
||||||
|
.contains(source.getControllerId());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue