mirror of
https://github.com/correl/mage.git
synced 2024-12-25 03:00:15 +00:00
Reworking goad effects (ready for review) (#8034)
* changing goad to designation, refactored goad effects to be continuous * [AFC] Implemented Vengeful Ancestor * reworked effects which goad an attached creature * updated goading implementation * updated combat with new goad logic * some more changes, added a test * another fix * update to test, still fails * added more failing tests * more failing tests * added additional goad check * small fix to two tests (still failing * added a regular combat test (passes and fails randomly) * fixed bug in computer player random selection * some changes to how TargetDefender is handled * removed unnecessary class * more combat fixes, tests pass now * removed tests which no longer work due to combat changes * small merge fix * [NEC] Implemented Komainu Battle Armor * [NEC] Implemented Kaima, the Fractured Calm * [NEC] added all variants
This commit is contained in:
parent
5725873aeb
commit
4591ac07cc
30 changed files with 812 additions and 438 deletions
|
@ -976,24 +976,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.getOriginalTarget() instanceof TargetDefender) {
|
if (target.getOriginalTarget() instanceof TargetDefender) {
|
||||||
// TODO: Improve, now planeswalker is always chosen if it exits
|
UUID randomDefender = RandomUtil.randomFromCollection(possibleTargets);
|
||||||
List<Permanent> targets;
|
target.addTarget(randomDefender, source, game);
|
||||||
targets = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_PLANESWALKER, randomOpponentId, game);
|
|
||||||
if (targets != null && !targets.isEmpty()) {
|
|
||||||
for (Permanent planeswalker : targets) {
|
|
||||||
if (target.canTarget(abilityControllerId, planeswalker.getId(), source, game)) {
|
|
||||||
target.addTarget(planeswalker.getId(), source, game);
|
|
||||||
}
|
|
||||||
if (target.isChosen()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!target.isChosen()) {
|
|
||||||
if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
|
|
||||||
target.addTarget(randomOpponentId, source, game);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return target.isChosen();
|
return target.isChosen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2997,21 +2981,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private UUID getRandomOpponent(UUID abilityControllerId, Game game) {
|
private UUID getRandomOpponent(UUID abilityControllerId, Game game) {
|
||||||
UUID randomOpponentId = null;
|
return RandomUtil.randomFromCollection(game.getOpponents(abilityControllerId));
|
||||||
Set<UUID> opponents = game.getOpponents(abilityControllerId);
|
|
||||||
if (opponents.size() > 1) {
|
|
||||||
int rand = RandomUtil.nextInt(opponents.size());
|
|
||||||
int count = 0;
|
|
||||||
for (UUID currentId : opponents) {
|
|
||||||
if (count == rand) {
|
|
||||||
randomOpponentId = currentId;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (opponents.size() == 1) {
|
|
||||||
randomOpponentId = game.getOpponents(abilityControllerId).iterator().next();
|
|
||||||
}
|
|
||||||
return randomOpponentId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1737,7 +1737,6 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
TargetDefender target = new TargetDefender(possibleDefender, attackerId);
|
TargetDefender target = new TargetDefender(possibleDefender, attackerId);
|
||||||
target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player
|
|
||||||
if (forcedToAttack) {
|
if (forcedToAttack) {
|
||||||
StringBuilder sb = new StringBuilder(target.getTargetName());
|
StringBuilder sb = new StringBuilder(target.getTargetName());
|
||||||
Permanent attacker = game.getPermanent(attackerId);
|
Permanent attacker = game.getPermanent(attackerId);
|
||||||
|
@ -1757,7 +1756,6 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
|
|
||||||
protected UUID selectDefenderForAllAttack(Set<UUID> defenders, Game game) {
|
protected UUID selectDefenderForAllAttack(Set<UUID> defenders, Game game) {
|
||||||
TargetDefender target = new TargetDefender(defenders, null);
|
TargetDefender target = new TargetDefender(defenders, null);
|
||||||
target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player
|
|
||||||
if (chooseTarget(Outcome.Damage, target, null, game)) {
|
if (chooseTarget(Outcome.Damage, target, null, game)) {
|
||||||
return getFixedResponseUUID(game);
|
return getFixedResponseUUID(game);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ class AgitatorAntEffect extends OneShotEffect {
|
||||||
if (permanent == null || !permanent.addCounters(CounterType.P1P1.createInstance(2), player.getId(), source, game)) {
|
if (permanent == null || !permanent.addCounters(CounterType.P1P1.createInstance(2), player.getId(), source, game)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)).apply(game, source);
|
game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
package mage.cards.b;
|
package mage.cards.b;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.ContinuousEffect;
|
|
||||||
import mage.abilities.effects.Effect;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.UntapTargetEffect;
|
import mage.abilities.effects.common.UntapTargetEffect;
|
||||||
import mage.abilities.effects.common.combat.GoadTargetEffect;
|
import mage.abilities.effects.common.combat.GoadTargetEffect;
|
||||||
|
@ -20,8 +17,9 @@ import mage.target.common.TargetCreaturePermanent;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
import mage.target.targetpointer.TargetPointer;
|
import mage.target.targetpointer.TargetPointer;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class Besmirch extends CardImpl {
|
public final class Besmirch extends CardImpl {
|
||||||
|
@ -66,24 +64,19 @@ class BesmirchEffect extends OneShotEffect {
|
||||||
TargetPointer target = new FixedTarget(source.getFirstTarget(), game);
|
TargetPointer target = new FixedTarget(source.getFirstTarget(), game);
|
||||||
|
|
||||||
// gain control
|
// gain control
|
||||||
ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfTurn);
|
game.addEffect(new GainControlTargetEffect(Duration.EndOfTurn)
|
||||||
effect.setTargetPointer(target);
|
.setTargetPointer(target), source);
|
||||||
game.addEffect(effect, source);
|
|
||||||
|
|
||||||
// haste
|
// haste
|
||||||
effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn);
|
game.addEffect(new GainAbilityTargetEffect(
|
||||||
effect.setTargetPointer(target);
|
HasteAbility.getInstance(), Duration.EndOfTurn
|
||||||
game.addEffect(effect, source);
|
).setTargetPointer(target), source);
|
||||||
|
|
||||||
// goad
|
// goad
|
||||||
Effect effect2 = new GoadTargetEffect();
|
game.addEffect(new GoadTargetEffect().setTargetPointer(target), source);
|
||||||
effect2.setTargetPointer(target);
|
|
||||||
effect2.apply(game, source);
|
|
||||||
|
|
||||||
// untap
|
// untap
|
||||||
effect2 = new UntapTargetEffect();
|
new UntapTargetEffect().setTargetPointer(target).apply(game, source);
|
||||||
effect2.setTargetPointer(target);
|
|
||||||
effect2.apply(game, source);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,10 @@ package mage.cards.b;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
|
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
|
||||||
import mage.abilities.common.GoadAttachedAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.mana.GenericManaCost;
|
import mage.abilities.costs.mana.GenericManaCost;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
|
import mage.abilities.effects.common.combat.GoadAttachedEffect;
|
||||||
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
|
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
@ -27,10 +28,12 @@ public final class BloodthirstyBlade extends CardImpl {
|
||||||
this.subtype.add(SubType.EQUIPMENT);
|
this.subtype.add(SubType.EQUIPMENT);
|
||||||
|
|
||||||
// Equipped creature gets +2/+0 and is goaded.
|
// Equipped creature gets +2/+0 and is goaded.
|
||||||
this.addAbility(new GoadAttachedAbility(new BoostEquippedEffect(2, 0)));
|
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 0));
|
||||||
|
ability.addEffect(new GoadAttachedEffect());
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
// {1}: Attach Bloodthirsty Blade to target creature an opponent controls. Active this ability only any time you could cast a sorcery.
|
// {1}: Attach Bloodthirsty Blade to target creature an opponent controls. Active this ability only any time you could cast a sorcery.
|
||||||
Ability ability = new ActivateAsSorceryActivatedAbility(
|
ability = new ActivateAsSorceryActivatedAbility(
|
||||||
Zone.BATTLEFIELD,
|
Zone.BATTLEFIELD,
|
||||||
new AttachEffect(
|
new AttachEffect(
|
||||||
Outcome.Detriment, "Attach {this} to target creature an opponent controls"
|
Outcome.Detriment, "Attach {this} to target creature an opponent controls"
|
||||||
|
|
|
@ -74,7 +74,7 @@ class GeodeRagerEffect extends OneShotEffect {
|
||||||
if (permanent == null) {
|
if (permanent == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)).apply(game, source);
|
game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
94
Mage.Sets/src/mage/cards/k/KaimaTheFracturedCalm.java
Normal file
94
Mage.Sets/src/mage/cards/k/KaimaTheFracturedCalm.java
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
package mage.cards.k;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.combat.GoadTargetEffect;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import mage.filter.StaticFilters;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class KaimaTheFracturedCalm extends CardImpl {
|
||||||
|
|
||||||
|
public KaimaTheFracturedCalm(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}");
|
||||||
|
|
||||||
|
this.addSuperType(SuperType.LEGENDARY);
|
||||||
|
this.subtype.add(SubType.SPIRIT);
|
||||||
|
this.power = new MageInt(3);
|
||||||
|
this.toughness = new MageInt(3);
|
||||||
|
|
||||||
|
// At the beginning of your end step, goad each creature your opponents control that's enchanted by an Aura you control. Put a +1/+1 counter on Kaima, the Fractured Calm for each creature goaded this way.
|
||||||
|
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
|
||||||
|
new KaimaTheFracturedCalmEffect(), TargetController.YOU, false
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private KaimaTheFracturedCalm(final KaimaTheFracturedCalm card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KaimaTheFracturedCalm copy() {
|
||||||
|
return new KaimaTheFracturedCalm(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KaimaTheFracturedCalmEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
KaimaTheFracturedCalmEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
staticText = "goad each creature your opponents control that's enchanted by an Aura you control. " +
|
||||||
|
"Put a +1/+1 counter on {this} for each creature goaded this way";
|
||||||
|
}
|
||||||
|
|
||||||
|
private KaimaTheFracturedCalmEffect(final KaimaTheFracturedCalmEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KaimaTheFracturedCalmEffect copy() {
|
||||||
|
return new KaimaTheFracturedCalmEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
int goaded = 0;
|
||||||
|
for (Permanent permanent : game.getBattlefield().getActivePermanents(
|
||||||
|
StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE,
|
||||||
|
source.getControllerId(), source.getSourceId(), game
|
||||||
|
)) {
|
||||||
|
if (permanent
|
||||||
|
.getAttachments()
|
||||||
|
.stream()
|
||||||
|
.map(game::getPermanent)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.noneMatch(p -> p.isControlledBy(source.getControllerId())
|
||||||
|
&& p.hasSubtype(SubType.AURA, game))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source);
|
||||||
|
goaded++;
|
||||||
|
}
|
||||||
|
if (goaded < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
|
if (permanent != null) {
|
||||||
|
permanent.addCounters(CounterType.P1P1.createInstance(goaded), source, game);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
137
Mage.Sets/src/mage/cards/k/KomainuBattleArmor.java
Normal file
137
Mage.Sets/src/mage/cards/k/KomainuBattleArmor.java
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
package mage.cards.k;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.combat.GoadTargetEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||||
|
import mage.abilities.keyword.MenaceAbility;
|
||||||
|
import mage.abilities.keyword.ReconfigureAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.filter.StaticFilters;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.DamagedEvent;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class KomainuBattleArmor extends CardImpl {
|
||||||
|
|
||||||
|
public KomainuBattleArmor(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{R}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.EQUIPMENT);
|
||||||
|
this.subtype.add(SubType.DOG);
|
||||||
|
this.power = new MageInt(2);
|
||||||
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
|
// Menace
|
||||||
|
this.addAbility(new MenaceAbility(false));
|
||||||
|
|
||||||
|
// Equipped creature gets +2/+2 and has menace.
|
||||||
|
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2));
|
||||||
|
ability.addEffect(new GainAbilityAttachedEffect(
|
||||||
|
new MenaceAbility(false), AttachmentType.EQUIPMENT
|
||||||
|
).setText("and has menace"));
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
// Whenever Komainu Battle Armor or equipped creature deals combat damage to a player, goad each creature that player controls.
|
||||||
|
this.addAbility(new KomainuBattleArmorTriggeredAbility());
|
||||||
|
|
||||||
|
// Reconfigure {4}
|
||||||
|
this.addAbility(new ReconfigureAbility("{4}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private KomainuBattleArmor(final KomainuBattleArmor card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KomainuBattleArmor copy() {
|
||||||
|
return new KomainuBattleArmor(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KomainuBattleArmorTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
|
KomainuBattleArmorTriggeredAbility() {
|
||||||
|
super(Zone.BATTLEFIELD, new KomainuBattleArmorEffect());
|
||||||
|
}
|
||||||
|
|
||||||
|
private KomainuBattleArmorTriggeredAbility(final KomainuBattleArmorTriggeredAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KomainuBattleArmorTriggeredAbility copy() {
|
||||||
|
return new KomainuBattleArmorTriggeredAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkEventType(GameEvent event, Game game) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
if (!((DamagedEvent) event).isCombatDamage()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getSourceId().equals(event.getSourceId())) {
|
||||||
|
getEffects().setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Permanent permanent = getSourcePermanentOrLKI(game);
|
||||||
|
if (permanent != null && event.getSourceId().equals(permanent.getAttachedTo())) {
|
||||||
|
getEffects().setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
return "Whenever {this} or equipped creature deals combat damage to a player, goad each creature that player controls.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KomainuBattleArmorEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
KomainuBattleArmorEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private KomainuBattleArmorEffect(final KomainuBattleArmorEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KomainuBattleArmorEffect copy() {
|
||||||
|
return new KomainuBattleArmorEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
UUID playerId = getTargetPointer().getFirst(game, source);
|
||||||
|
if (playerId == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Permanent permanent : game.getBattlefield().getActivePermanents(
|
||||||
|
StaticFilters.FILTER_CONTROLLED_CREATURE,
|
||||||
|
playerId, source.getSourceId(), game
|
||||||
|
)) {
|
||||||
|
game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,10 @@
|
||||||
package mage.cards.m;
|
package mage.cards.m;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
|
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
import mage.abilities.effects.Effect;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.combat.GoadTargetEffect;
|
import mage.abilities.effects.common.combat.GoadTargetEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -15,8 +13,11 @@ import mage.constants.*;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
|
@ -86,8 +87,6 @@ class MarisiBreakerOfTheCoilSpellEffect extends ContinuousRuleModifyingEffectImp
|
||||||
|
|
||||||
class MarisiBreakerOfTheCoilEffect extends OneShotEffect {
|
class MarisiBreakerOfTheCoilEffect extends OneShotEffect {
|
||||||
|
|
||||||
private static final Effect effect = new GoadTargetEffect();
|
|
||||||
|
|
||||||
MarisiBreakerOfTheCoilEffect() {
|
MarisiBreakerOfTheCoilEffect() {
|
||||||
super(Outcome.Benefit);
|
super(Outcome.Benefit);
|
||||||
staticText = "goad each creature that player controls "
|
staticText = "goad each creature that player controls "
|
||||||
|
@ -105,13 +104,12 @@ class MarisiBreakerOfTheCoilEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
game.getBattlefield().getAllActivePermanents(
|
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(
|
||||||
StaticFilters.FILTER_PERMANENT_CREATURE,
|
StaticFilters.FILTER_PERMANENT_CREATURE,
|
||||||
targetPointer.getFirst(game, source), game
|
targetPointer.getFirst(game, source), game
|
||||||
).stream().forEach(permanent -> {
|
)) {
|
||||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source);
|
||||||
effect.apply(game, source);
|
}
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,9 @@ package mage.cards.m;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
||||||
import mage.abilities.common.GoadAttachedAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
|
import mage.abilities.effects.common.combat.GoadAttachedEffect;
|
||||||
import mage.abilities.effects.common.continuous.BoostAllEffect;
|
import mage.abilities.effects.common.continuous.BoostAllEffect;
|
||||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||||
import mage.abilities.keyword.EnchantAbility;
|
import mage.abilities.keyword.EnchantAbility;
|
||||||
|
@ -44,7 +45,9 @@ public final class MartialImpetus extends CardImpl {
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Enchanted creature gets +1/+1 and is goaded.
|
// Enchanted creature gets +1/+1 and is goaded.
|
||||||
this.addAbility(new GoadAttachedAbility(new BoostEnchantedEffect(1, 1)));
|
ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1));
|
||||||
|
ability.addEffect(new GoadAttachedEffect());
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Whenever enchanted creature attacks, each other creature that's attacking one of your opponents gets +1/+1 until end of turn.
|
// Whenever enchanted creature attacks, each other creature that's attacking one of your opponents gets +1/+1 until end of turn.
|
||||||
this.addAbility(new AttacksAttachedTriggeredAbility(
|
this.addAbility(new AttacksAttachedTriggeredAbility(
|
||||||
|
@ -78,7 +81,7 @@ enum MartialImpetusPredicate implements ObjectSourcePlayerPredicate<Permanent> {
|
||||||
&& input.getObject() != attachedTo // must be other creature
|
&& input.getObject() != attachedTo // must be other creature
|
||||||
&& input.getObject().isAttacking() // attacking
|
&& input.getObject().isAttacking() // attacking
|
||||||
&& game.getOpponents(auraControllerId) // check for opponents of aura's controller
|
&& game.getOpponents(auraControllerId) // check for opponents of aura's controller
|
||||||
.contains(game.getCombat().getDefendingPlayerId(input.getObject().getId(), game))) {
|
.contains(game.getCombat().getDefendingPlayerId(input.getObject().getId(), game))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,11 @@ package mage.cards.p;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
||||||
import mage.abilities.common.GoadAttachedAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
import mage.abilities.effects.common.GainLifeEffect;
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
import mage.abilities.effects.common.LoseLifeControllerAttachedEffect;
|
import mage.abilities.effects.common.LoseLifeControllerAttachedEffect;
|
||||||
|
import mage.abilities.effects.common.combat.GoadAttachedEffect;
|
||||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||||
import mage.abilities.keyword.EnchantAbility;
|
import mage.abilities.keyword.EnchantAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -37,7 +38,9 @@ public final class ParasiticImpetus extends CardImpl {
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Enchanted creature gets +2/+2 and is goaded.
|
// Enchanted creature gets +2/+2 and is goaded.
|
||||||
this.addAbility(new GoadAttachedAbility(new BoostEnchantedEffect(2, 2)));
|
ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2));
|
||||||
|
ability.addEffect(new GoadAttachedEffect());
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Whenever enchanted creature attacks, its controller loses 2 life and you gain 2 life.
|
// Whenever enchanted creature attacks, its controller loses 2 life and you gain 2 life.
|
||||||
ability = new AttacksAttachedTriggeredAbility(
|
ability = new AttacksAttachedTriggeredAbility(
|
||||||
|
|
|
@ -109,7 +109,6 @@ class PortalMageEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
// Select the new defender
|
// Select the new defender
|
||||||
TargetDefender target = new TargetDefender(defenders, null);
|
TargetDefender target = new TargetDefender(defenders, null);
|
||||||
target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player
|
|
||||||
if (controller.chooseTarget(Outcome.Damage, target, source, game)) {
|
if (controller.chooseTarget(Outcome.Damage, target, source, game)) {
|
||||||
if (!combatGroupTarget.getDefenderId().equals(target.getFirstTarget())) {
|
if (!combatGroupTarget.getDefenderId().equals(target.getFirstTarget())) {
|
||||||
if (combatGroupTarget.changeDefenderPostDeclaration(target.getFirstTarget(), game)) {
|
if (combatGroupTarget.changeDefenderPostDeclaration(target.getFirstTarget(), game)) {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package mage.cards.p;
|
package mage.cards.p;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.GoadAttachedAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.RequirementEffect;
|
import mage.abilities.effects.RequirementEffect;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
|
import mage.abilities.effects.common.combat.GoadAttachedEffect;
|
||||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||||
import mage.abilities.keyword.EnchantAbility;
|
import mage.abilities.keyword.EnchantAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -37,11 +38,10 @@ public final class PredatoryImpetus extends CardImpl {
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Enchanted creature gets +3/+3, must be blocked if able, and is goaded.
|
// Enchanted creature gets +3/+3, must be blocked if able, and is goaded.
|
||||||
this.addAbility(new GoadAttachedAbility(
|
ability = new SimpleStaticAbility(new BoostEnchantedEffect(3, 3));
|
||||||
new BoostEnchantedEffect(3, 3)
|
ability.addEffect(new PredatoryImpetusEffect());
|
||||||
.setText("Enchanted creature gets +3/+3"),
|
ability.addEffect(new GoadAttachedEffect().concatBy(","));
|
||||||
new PredatoryImpetusEffect()
|
this.addAbility(ability);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PredatoryImpetus(final PredatoryImpetus card) {
|
private PredatoryImpetus(final PredatoryImpetus card) {
|
||||||
|
|
|
@ -2,8 +2,9 @@ package mage.cards.p;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
||||||
import mage.abilities.common.GoadAttachedAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
|
import mage.abilities.effects.common.combat.GoadAttachedEffect;
|
||||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||||
import mage.abilities.effects.keyword.ScryEffect;
|
import mage.abilities.effects.keyword.ScryEffect;
|
||||||
import mage.abilities.keyword.EnchantAbility;
|
import mage.abilities.keyword.EnchantAbility;
|
||||||
|
@ -36,7 +37,9 @@ public final class PsychicImpetus extends CardImpl {
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Enchanted creature gets +2/+2 and is goaded.
|
// Enchanted creature gets +2/+2 and is goaded.
|
||||||
this.addAbility(new GoadAttachedAbility(new BoostEnchantedEffect(2, 2)));
|
ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2));
|
||||||
|
ability.addEffect(new GoadAttachedEffect());
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Whenever enchanted creature attacks, you scry 2.
|
// Whenever enchanted creature attacks, you scry 2.
|
||||||
this.addAbility(new AttacksAttachedTriggeredAbility(
|
this.addAbility(new AttacksAttachedTriggeredAbility(
|
||||||
|
|
|
@ -2,9 +2,10 @@ package mage.cards.s;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
import mage.abilities.common.AttacksAttachedTriggeredAbility;
|
||||||
import mage.abilities.common.GoadAttachedAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
|
import mage.abilities.effects.common.combat.GoadAttachedEffect;
|
||||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||||
import mage.abilities.keyword.EnchantAbility;
|
import mage.abilities.keyword.EnchantAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -37,7 +38,9 @@ public final class ShinyImpetus extends CardImpl {
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Enchanted creature gets +2/+2 and is goaded.
|
// Enchanted creature gets +2/+2 and is goaded.
|
||||||
this.addAbility(new GoadAttachedAbility(new BoostEnchantedEffect(2, 2)));
|
ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2));
|
||||||
|
ability.addEffect(new GoadAttachedEffect());
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Whenever enchanted creature attacks, you create a Treasure token.
|
// Whenever enchanted creature attacks, you create a Treasure token.
|
||||||
this.addAbility(new AttacksAttachedTriggeredAbility(
|
this.addAbility(new AttacksAttachedTriggeredAbility(
|
||||||
|
|
106
Mage.Sets/src/mage/cards/v/VengefulAncestor.java
Normal file
106
Mage.Sets/src/mage/cards/v/VengefulAncestor.java
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
package mage.cards.v;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.AttacksAllTriggeredAbility;
|
||||||
|
import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.combat.GoadTargetEffect;
|
||||||
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SetTargetPointer;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
|
import mage.filter.predicate.Predicate;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public final class VengefulAncestor extends CardImpl {
|
||||||
|
|
||||||
|
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a goaded creature");
|
||||||
|
|
||||||
|
static {
|
||||||
|
filter.add(VengefulAncestorPredicate.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VengefulAncestor(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.SPIRIT);
|
||||||
|
this.subtype.add(SubType.DRAGON);
|
||||||
|
this.power = new MageInt(3);
|
||||||
|
this.toughness = new MageInt(4);
|
||||||
|
|
||||||
|
// Flying
|
||||||
|
this.addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
|
// Whenever Vengeful Ancestor enters the battlefield or attacks, goad target creature.
|
||||||
|
Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GoadTargetEffect());
|
||||||
|
ability.addTarget(new TargetCreaturePermanent());
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
// Whenever a goaded creature attacks, it deals 1 damage to its controller.
|
||||||
|
this.addAbility(new AttacksAllTriggeredAbility(
|
||||||
|
new VengefulAncestorEffect(), false, filter,
|
||||||
|
SetTargetPointer.NONE, false
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private VengefulAncestor(final VengefulAncestor card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VengefulAncestor copy() {
|
||||||
|
return new VengefulAncestor(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum VengefulAncestorPredicate implements Predicate<Permanent> {
|
||||||
|
instance;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Permanent input, Game game) {
|
||||||
|
return !input.getGoadingPlayers().isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VengefulAncestorEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
VengefulAncestorEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
staticText = "it deals 1 damage to its controller";
|
||||||
|
}
|
||||||
|
|
||||||
|
private VengefulAncestorEffect(final VengefulAncestorEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VengefulAncestorEffect copy() {
|
||||||
|
return new VengefulAncestorEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Permanent permanent = (Permanent) getValue("attacker");
|
||||||
|
if (permanent == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Player player = game.getPlayer(permanent.getControllerId());
|
||||||
|
if (player == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return player.damage(1, permanent.getId(), source, game) > 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -273,6 +273,7 @@ public final class ForgottenRealmsCommander extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Valorous Stance", 76, Rarity.UNCOMMON, mage.cards.v.ValorousStance.class));
|
cards.add(new SetCardInfo("Valorous Stance", 76, Rarity.UNCOMMON, mage.cards.v.ValorousStance.class));
|
||||||
cards.add(new SetCardInfo("Vandalblast", 148, Rarity.UNCOMMON, mage.cards.v.Vandalblast.class));
|
cards.add(new SetCardInfo("Vandalblast", 148, Rarity.UNCOMMON, mage.cards.v.Vandalblast.class));
|
||||||
cards.add(new SetCardInfo("Vanish into Memory", 196, Rarity.UNCOMMON, mage.cards.v.VanishIntoMemory.class));
|
cards.add(new SetCardInfo("Vanish into Memory", 196, Rarity.UNCOMMON, mage.cards.v.VanishIntoMemory.class));
|
||||||
|
cards.add(new SetCardInfo("Vengeful Ancestor", 35, Rarity.RARE, mage.cards.v.VengefulAncestor.class));
|
||||||
cards.add(new SetCardInfo("Verdant Embrace", 173, Rarity.RARE, mage.cards.v.VerdantEmbrace.class));
|
cards.add(new SetCardInfo("Verdant Embrace", 173, Rarity.RARE, mage.cards.v.VerdantEmbrace.class));
|
||||||
cards.add(new SetCardInfo("Victimize", 112, Rarity.UNCOMMON, mage.cards.v.Victimize.class));
|
cards.add(new SetCardInfo("Victimize", 112, Rarity.UNCOMMON, mage.cards.v.Victimize.class));
|
||||||
cards.add(new SetCardInfo("Viridian Longbow", 221, Rarity.COMMON, mage.cards.v.ViridianLongbow.class));
|
cards.add(new SetCardInfo("Viridian Longbow", 221, Rarity.COMMON, mage.cards.v.ViridianLongbow.class));
|
||||||
|
|
|
@ -19,16 +19,20 @@ public final class NeonDynastyCommander extends ExpansionSet {
|
||||||
super("Neon Dynasty Commander", "NEC", ExpansionSet.buildDate(2022, 2, 18), SetType.SUPPLEMENTAL);
|
super("Neon Dynasty Commander", "NEC", ExpansionSet.buildDate(2022, 2, 18), SetType.SUPPLEMENTAL);
|
||||||
this.hasBasicLands = false;
|
this.hasBasicLands = false;
|
||||||
|
|
||||||
cards.add(new SetCardInfo("Access Denied", 11, Rarity.RARE, mage.cards.a.AccessDenied.class));
|
cards.add(new SetCardInfo("Access Denied", 11, Rarity.RARE, mage.cards.a.AccessDenied.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Access Denied", 47, Rarity.RARE, mage.cards.a.AccessDenied.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Acidic Slime", 112, Rarity.UNCOMMON, mage.cards.a.AcidicSlime.class));
|
cards.add(new SetCardInfo("Acidic Slime", 112, Rarity.UNCOMMON, mage.cards.a.AcidicSlime.class));
|
||||||
cards.add(new SetCardInfo("Aerial Surveyor", 5, Rarity.RARE, mage.cards.a.AerialSurveyor.class));
|
cards.add(new SetCardInfo("Aerial Surveyor", 39, Rarity.RARE, mage.cards.a.AerialSurveyor.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Aerial Surveyor", 5, Rarity.RARE, mage.cards.a.AerialSurveyor.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Aeronaut Admiral", 79, Rarity.UNCOMMON, mage.cards.a.AeronautAdmiral.class));
|
cards.add(new SetCardInfo("Aeronaut Admiral", 79, Rarity.UNCOMMON, mage.cards.a.AeronautAdmiral.class));
|
||||||
cards.add(new SetCardInfo("Agitator Ant", 102, Rarity.RARE, mage.cards.a.AgitatorAnt.class));
|
cards.add(new SetCardInfo("Agitator Ant", 102, Rarity.RARE, mage.cards.a.AgitatorAnt.class));
|
||||||
cards.add(new SetCardInfo("Akki Battle Squad", 18, Rarity.RARE, mage.cards.a.AkkiBattleSquad.class));
|
cards.add(new SetCardInfo("Akki Battle Squad", 18, Rarity.RARE, mage.cards.a.AkkiBattleSquad.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Akki Battle Squad", 57, Rarity.RARE, mage.cards.a.AkkiBattleSquad.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Arcane Signet", 144, Rarity.COMMON, mage.cards.a.ArcaneSignet.class));
|
cards.add(new SetCardInfo("Arcane Signet", 144, Rarity.COMMON, mage.cards.a.ArcaneSignet.class));
|
||||||
cards.add(new SetCardInfo("Arcanist's Owl", 135, Rarity.UNCOMMON, mage.cards.a.ArcanistsOwl.class));
|
cards.add(new SetCardInfo("Arcanist's Owl", 135, Rarity.UNCOMMON, mage.cards.a.ArcanistsOwl.class));
|
||||||
cards.add(new SetCardInfo("Armed and Armored", 80, Rarity.UNCOMMON, mage.cards.a.ArmedAndArmored.class));
|
cards.add(new SetCardInfo("Armed and Armored", 80, Rarity.UNCOMMON, mage.cards.a.ArmedAndArmored.class));
|
||||||
cards.add(new SetCardInfo("Ascendant Acolyte", 24, Rarity.RARE, mage.cards.a.AscendantAcolyte.class));
|
cards.add(new SetCardInfo("Ascendant Acolyte", 24, Rarity.RARE, mage.cards.a.AscendantAcolyte.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Ascendant Acolyte", 64, Rarity.RARE, mage.cards.a.AscendantAcolyte.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Azorius Signet", 145, Rarity.UNCOMMON, mage.cards.a.AzoriusSignet.class));
|
cards.add(new SetCardInfo("Azorius Signet", 145, Rarity.UNCOMMON, mage.cards.a.AzoriusSignet.class));
|
||||||
cards.add(new SetCardInfo("Bear Umbra", 113, Rarity.RARE, mage.cards.b.BearUmbra.class));
|
cards.add(new SetCardInfo("Bear Umbra", 113, Rarity.RARE, mage.cards.b.BearUmbra.class));
|
||||||
cards.add(new SetCardInfo("Beast Within", 114, Rarity.UNCOMMON, mage.cards.b.BeastWithin.class));
|
cards.add(new SetCardInfo("Beast Within", 114, Rarity.UNCOMMON, mage.cards.b.BeastWithin.class));
|
||||||
|
@ -38,19 +42,25 @@ public final class NeonDynastyCommander extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Chain Reaction", 103, Rarity.RARE, mage.cards.c.ChainReaction.class));
|
cards.add(new SetCardInfo("Chain Reaction", 103, Rarity.RARE, mage.cards.c.ChainReaction.class));
|
||||||
cards.add(new SetCardInfo("Champion of Lambholt", 115, Rarity.RARE, mage.cards.c.ChampionOfLambholt.class));
|
cards.add(new SetCardInfo("Champion of Lambholt", 115, Rarity.RARE, mage.cards.c.ChampionOfLambholt.class));
|
||||||
cards.add(new SetCardInfo("Chaos Warp", 104, Rarity.RARE, mage.cards.c.ChaosWarp.class));
|
cards.add(new SetCardInfo("Chaos Warp", 104, Rarity.RARE, mage.cards.c.ChaosWarp.class));
|
||||||
cards.add(new SetCardInfo("Chishiro, the Shattered Blade", 1, Rarity.MYTHIC, mage.cards.c.ChishiroTheShatteredBlade.class));
|
cards.add(new SetCardInfo("Chishiro, the Shattered Blade", 1, Rarity.MYTHIC, mage.cards.c.ChishiroTheShatteredBlade.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Chishiro, the Shattered Blade", 73, Rarity.MYTHIC, mage.cards.c.ChishiroTheShatteredBlade.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Chishiro, the Shattered Blade", 77, Rarity.MYTHIC, mage.cards.c.ChishiroTheShatteredBlade.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Cinder Glade", 166, Rarity.RARE, mage.cards.c.CinderGlade.class));
|
cards.add(new SetCardInfo("Cinder Glade", 166, Rarity.RARE, mage.cards.c.CinderGlade.class));
|
||||||
cards.add(new SetCardInfo("Collision of Realms", 19, Rarity.RARE, mage.cards.c.CollisionOfRealms.class));
|
cards.add(new SetCardInfo("Collision of Realms", 19, Rarity.RARE, mage.cards.c.CollisionOfRealms.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Collision of Realms", 58, Rarity.RARE, mage.cards.c.CollisionOfRealms.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Colossal Plow", 148, Rarity.UNCOMMON, mage.cards.c.ColossalPlow.class));
|
cards.add(new SetCardInfo("Colossal Plow", 148, Rarity.UNCOMMON, mage.cards.c.ColossalPlow.class));
|
||||||
cards.add(new SetCardInfo("Command Tower", 167, Rarity.COMMON, mage.cards.c.CommandTower.class));
|
cards.add(new SetCardInfo("Command Tower", 167, Rarity.COMMON, mage.cards.c.CommandTower.class));
|
||||||
cards.add(new SetCardInfo("Concord with the Kami", 25, Rarity.RARE, mage.cards.c.ConcordWithTheKami.class));
|
cards.add(new SetCardInfo("Concord with the Kami", 25, Rarity.RARE, mage.cards.c.ConcordWithTheKami.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Concord with the Kami", 65, Rarity.RARE, mage.cards.c.ConcordWithTheKami.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Crush Contraband", 82, Rarity.UNCOMMON, mage.cards.c.CrushContraband.class));
|
cards.add(new SetCardInfo("Crush Contraband", 82, Rarity.UNCOMMON, mage.cards.c.CrushContraband.class));
|
||||||
cards.add(new SetCardInfo("Cultivator's Caravan", 149, Rarity.RARE, mage.cards.c.CultivatorsCaravan.class));
|
cards.add(new SetCardInfo("Cultivator's Caravan", 149, Rarity.RARE, mage.cards.c.CultivatorsCaravan.class));
|
||||||
cards.add(new SetCardInfo("Cyberdrive Awakener", 12, Rarity.RARE, mage.cards.c.CyberdriveAwakener.class));
|
cards.add(new SetCardInfo("Cyberdrive Awakener", 12, Rarity.RARE, mage.cards.c.CyberdriveAwakener.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Cyberdrive Awakener", 48, Rarity.RARE, mage.cards.c.CyberdriveAwakener.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Dance of the Manse", 136, Rarity.RARE, mage.cards.d.DanceOfTheManse.class));
|
cards.add(new SetCardInfo("Dance of the Manse", 136, Rarity.RARE, mage.cards.d.DanceOfTheManse.class));
|
||||||
cards.add(new SetCardInfo("Decimate", 137, Rarity.RARE, mage.cards.d.Decimate.class));
|
cards.add(new SetCardInfo("Decimate", 137, Rarity.RARE, mage.cards.d.Decimate.class));
|
||||||
cards.add(new SetCardInfo("Dispatch", 83, Rarity.UNCOMMON, mage.cards.d.Dispatch.class));
|
cards.add(new SetCardInfo("Dispatch", 83, Rarity.UNCOMMON, mage.cards.d.Dispatch.class));
|
||||||
cards.add(new SetCardInfo("Drumbellower", 6, Rarity.RARE, mage.cards.d.Drumbellower.class));
|
cards.add(new SetCardInfo("Drumbellower", 40, Rarity.RARE, mage.cards.d.Drumbellower.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Drumbellower", 6, Rarity.RARE, mage.cards.d.Drumbellower.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Elemental Mastery", 105, Rarity.RARE, mage.cards.e.ElementalMastery.class));
|
cards.add(new SetCardInfo("Elemental Mastery", 105, Rarity.RARE, mage.cards.e.ElementalMastery.class));
|
||||||
cards.add(new SetCardInfo("Emry, Lurker of the Loch", 91, Rarity.RARE, mage.cards.e.EmryLurkerOfTheLoch.class));
|
cards.add(new SetCardInfo("Emry, Lurker of the Loch", 91, Rarity.RARE, mage.cards.e.EmryLurkerOfTheLoch.class));
|
||||||
cards.add(new SetCardInfo("Etherium Sculptor", 92, Rarity.COMMON, mage.cards.e.EtheriumSculptor.class));
|
cards.add(new SetCardInfo("Etherium Sculptor", 92, Rarity.COMMON, mage.cards.e.EtheriumSculptor.class));
|
||||||
|
@ -63,41 +73,61 @@ public final class NeonDynastyCommander extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Game Trail", 169, Rarity.RARE, mage.cards.g.GameTrail.class));
|
cards.add(new SetCardInfo("Game Trail", 169, Rarity.RARE, mage.cards.g.GameTrail.class));
|
||||||
cards.add(new SetCardInfo("Generous Gift", 84, Rarity.UNCOMMON, mage.cards.g.GenerousGift.class));
|
cards.add(new SetCardInfo("Generous Gift", 84, Rarity.UNCOMMON, mage.cards.g.GenerousGift.class));
|
||||||
cards.add(new SetCardInfo("Genesis Hydra", 118, Rarity.RARE, mage.cards.g.GenesisHydra.class));
|
cards.add(new SetCardInfo("Genesis Hydra", 118, Rarity.RARE, mage.cards.g.GenesisHydra.class));
|
||||||
cards.add(new SetCardInfo("Go-Shintai of Life's Origin", 37, Rarity.MYTHIC, mage.cards.g.GoShintaiOfLifesOrigin.class));
|
cards.add(new SetCardInfo("Go-Shintai of Life's Origin", 37, Rarity.MYTHIC, mage.cards.g.GoShintaiOfLifesOrigin.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Go-Shintai of Life's Origin", 66, Rarity.MYTHIC, mage.cards.g.GoShintaiOfLifesOrigin.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Goblin Razerunners", 106, Rarity.RARE, mage.cards.g.GoblinRazerunners.class));
|
cards.add(new SetCardInfo("Goblin Razerunners", 106, Rarity.RARE, mage.cards.g.GoblinRazerunners.class));
|
||||||
cards.add(new SetCardInfo("Gold Myr", 153, Rarity.COMMON, mage.cards.g.GoldMyr.class));
|
cards.add(new SetCardInfo("Gold Myr", 153, Rarity.COMMON, mage.cards.g.GoldMyr.class));
|
||||||
cards.add(new SetCardInfo("Grumgully, the Generous", 138, Rarity.UNCOMMON, mage.cards.g.GrumgullyTheGenerous.class));
|
cards.add(new SetCardInfo("Grumgully, the Generous", 138, Rarity.UNCOMMON, mage.cards.g.GrumgullyTheGenerous.class));
|
||||||
cards.add(new SetCardInfo("Gruul Turf", 170, Rarity.UNCOMMON, mage.cards.g.GruulTurf.class));
|
cards.add(new SetCardInfo("Gruul Turf", 170, Rarity.UNCOMMON, mage.cards.g.GruulTurf.class));
|
||||||
cards.add(new SetCardInfo("Hanna, Ship's Navigator", 139, Rarity.RARE, mage.cards.h.HannaShipsNavigator.class));
|
cards.add(new SetCardInfo("Hanna, Ship's Navigator", 139, Rarity.RARE, mage.cards.h.HannaShipsNavigator.class));
|
||||||
cards.add(new SetCardInfo("Hunter's Insight", 119, Rarity.UNCOMMON, mage.cards.h.HuntersInsight.class));
|
cards.add(new SetCardInfo("Hunter's Insight", 119, Rarity.UNCOMMON, mage.cards.h.HuntersInsight.class));
|
||||||
cards.add(new SetCardInfo("Imposter Mech", 13, Rarity.RARE, mage.cards.i.ImposterMech.class));
|
cards.add(new SetCardInfo("Imposter Mech", 13, Rarity.RARE, mage.cards.i.ImposterMech.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Imposter Mech", 49, Rarity.RARE, mage.cards.i.ImposterMech.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Indomitable Archangel", 85, Rarity.MYTHIC, mage.cards.i.IndomitableArchangel.class));
|
cards.add(new SetCardInfo("Indomitable Archangel", 85, Rarity.MYTHIC, mage.cards.i.IndomitableArchangel.class));
|
||||||
cards.add(new SetCardInfo("Ironsoul Enforcer", 7, Rarity.RARE, mage.cards.i.IronsoulEnforcer.class));
|
cards.add(new SetCardInfo("Ironsoul Enforcer", 41, Rarity.RARE, mage.cards.i.IronsoulEnforcer.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Ironsoul Enforcer", 7, Rarity.RARE, mage.cards.i.IronsoulEnforcer.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Jace, Architect of Thought", 93, Rarity.MYTHIC, mage.cards.j.JaceArchitectOfThought.class));
|
cards.add(new SetCardInfo("Jace, Architect of Thought", 93, Rarity.MYTHIC, mage.cards.j.JaceArchitectOfThought.class));
|
||||||
cards.add(new SetCardInfo("Kami of Celebration", 20, Rarity.RARE, mage.cards.k.KamiOfCelebration.class));
|
cards.add(new SetCardInfo("Kaima, the Fractured Calm", 3, Rarity.MYTHIC, mage.cards.k.KaimaTheFracturedCalm.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Kappa Cannoneer", 14, Rarity.RARE, mage.cards.k.KappaCannoneer.class));
|
cards.add(new SetCardInfo("Kaima, the Fractured Calm", 74, Rarity.MYTHIC, mage.cards.k.KaimaTheFracturedCalm.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Katsumasa, the Animator", 15, Rarity.RARE, mage.cards.k.KatsumasaTheAnimator.class));
|
cards.add(new SetCardInfo("Kami of Celebration", 20, Rarity.RARE, mage.cards.k.KamiOfCelebration.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Kami of Celebration", 59, Rarity.RARE, mage.cards.k.KamiOfCelebration.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Kappa Cannoneer", 14, Rarity.RARE, mage.cards.k.KappaCannoneer.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Kappa Cannoneer", 50, Rarity.RARE, mage.cards.k.KappaCannoneer.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Katsumasa, the Animator", 15, Rarity.RARE, mage.cards.k.KatsumasaTheAnimator.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Katsumasa, the Animator", 51, Rarity.RARE, mage.cards.k.KatsumasaTheAnimator.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Kodama's Reach", 120, Rarity.COMMON, mage.cards.k.KodamasReach.class));
|
cards.add(new SetCardInfo("Kodama's Reach", 120, Rarity.COMMON, mage.cards.k.KodamasReach.class));
|
||||||
cards.add(new SetCardInfo("Kosei, Penitent Warlord", 26, Rarity.RARE, mage.cards.k.KoseiPenitentWarlord.class));
|
cards.add(new SetCardInfo("Komainu Battle Armor", 21, Rarity.RARE, mage.cards.k.KomainuBattleArmor.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Kotori, Pilot Prodigy", 2, Rarity.MYTHIC, mage.cards.k.KotoriPilotProdigy.class));
|
cards.add(new SetCardInfo("Komainu Battle Armor", 60, Rarity.RARE, mage.cards.k.KomainuBattleArmor.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Kosei, Penitent Warlord", 26, Rarity.RARE, mage.cards.k.KoseiPenitentWarlord.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Kosei, Penitent Warlord", 67, Rarity.RARE, mage.cards.k.KoseiPenitentWarlord.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Kotori, Pilot Prodigy", 2, Rarity.MYTHIC, mage.cards.k.KotoriPilotProdigy.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Kotori, Pilot Prodigy", 75, Rarity.MYTHIC, mage.cards.k.KotoriPilotProdigy.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Kotori, Pilot Prodigy", 78, Rarity.MYTHIC, mage.cards.k.KotoriPilotProdigy.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Krenko, Tin Street Kingpin", 107, Rarity.RARE, mage.cards.k.KrenkoTinStreetKingpin.class));
|
cards.add(new SetCardInfo("Krenko, Tin Street Kingpin", 107, Rarity.RARE, mage.cards.k.KrenkoTinStreetKingpin.class));
|
||||||
cards.add(new SetCardInfo("Loyal Guardian", 121, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class));
|
cards.add(new SetCardInfo("Loyal Guardian", 121, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class));
|
||||||
cards.add(new SetCardInfo("Mage Slayer", 140, Rarity.UNCOMMON, mage.cards.m.MageSlayer.class));
|
cards.add(new SetCardInfo("Mage Slayer", 140, Rarity.UNCOMMON, mage.cards.m.MageSlayer.class));
|
||||||
cards.add(new SetCardInfo("Master of Etherium", 94, Rarity.RARE, mage.cards.m.MasterOfEtherium.class));
|
cards.add(new SetCardInfo("Master of Etherium", 94, Rarity.RARE, mage.cards.m.MasterOfEtherium.class));
|
||||||
cards.add(new SetCardInfo("Mirage Mirror", 154, Rarity.RARE, mage.cards.m.MirageMirror.class));
|
cards.add(new SetCardInfo("Mirage Mirror", 154, Rarity.RARE, mage.cards.m.MirageMirror.class));
|
||||||
cards.add(new SetCardInfo("Mossfire Valley", 171, Rarity.RARE, mage.cards.m.MossfireValley.class));
|
cards.add(new SetCardInfo("Mossfire Valley", 171, Rarity.RARE, mage.cards.m.MossfireValley.class));
|
||||||
cards.add(new SetCardInfo("Myojin of Blooming Dawn", 31, Rarity.RARE, mage.cards.m.MyojinOfBloomingDawn.class));
|
cards.add(new SetCardInfo("Myojin of Blooming Dawn", 31, Rarity.RARE, mage.cards.m.MyojinOfBloomingDawn.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Myojin of Cryptic Dreams", 33, Rarity.RARE, mage.cards.m.MyojinOfCrypticDreams.class));
|
cards.add(new SetCardInfo("Myojin of Blooming Dawn", 42, Rarity.RARE, mage.cards.m.MyojinOfBloomingDawn.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Myojin of Grim Betrayal", 34, Rarity.RARE, mage.cards.m.MyojinOfGrimBetrayal.class));
|
cards.add(new SetCardInfo("Myojin of Cryptic Dreams", 33, Rarity.RARE, mage.cards.m.MyojinOfCrypticDreams.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Myojin of Roaring Blades", 36, Rarity.RARE, mage.cards.m.MyojinOfRoaringBlades.class));
|
cards.add(new SetCardInfo("Myojin of Cryptic Dreams", 52, Rarity.RARE, mage.cards.m.MyojinOfCrypticDreams.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Myojin of Towering Might", 38, Rarity.RARE, mage.cards.m.MyojinOfToweringMight.class));
|
cards.add(new SetCardInfo("Myojin of Grim Betrayal", 34, Rarity.RARE, mage.cards.m.MyojinOfGrimBetrayal.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Myojin of Grim Betrayal", 55, Rarity.RARE, mage.cards.m.MyojinOfGrimBetrayal.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Myojin of Roaring Blades", 36, Rarity.RARE, mage.cards.m.MyojinOfRoaringBlades.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Myojin of Roaring Blades", 61, Rarity.RARE, mage.cards.m.MyojinOfRoaringBlades.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Myojin of Towering Might", 38, Rarity.RARE, mage.cards.m.MyojinOfToweringMight.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Myojin of Towering Might", 68, Rarity.RARE, mage.cards.m.MyojinOfToweringMight.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Myrsmith", 86, Rarity.UNCOMMON, mage.cards.m.Myrsmith.class));
|
cards.add(new SetCardInfo("Myrsmith", 86, Rarity.UNCOMMON, mage.cards.m.Myrsmith.class));
|
||||||
cards.add(new SetCardInfo("Nissa, Voice of Zendikar", 122, Rarity.MYTHIC, mage.cards.n.NissaVoiceOfZendikar.class));
|
cards.add(new SetCardInfo("Nissa, Voice of Zendikar", 122, Rarity.MYTHIC, mage.cards.n.NissaVoiceOfZendikar.class));
|
||||||
cards.add(new SetCardInfo("One with the Kami", 27, Rarity.RARE, mage.cards.o.OneWithTheKami.class));
|
cards.add(new SetCardInfo("One with the Kami", 27, Rarity.RARE, mage.cards.o.OneWithTheKami.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("One with the Kami", 69, Rarity.RARE, mage.cards.o.OneWithTheKami.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Opal Palace", 172, Rarity.COMMON, mage.cards.o.OpalPalace.class));
|
cards.add(new SetCardInfo("Opal Palace", 172, Rarity.COMMON, mage.cards.o.OpalPalace.class));
|
||||||
cards.add(new SetCardInfo("Oran-Rief, the Vastwood", 173, Rarity.RARE, mage.cards.o.OranRiefTheVastwood.class));
|
cards.add(new SetCardInfo("Oran-Rief, the Vastwood", 173, Rarity.RARE, mage.cards.o.OranRiefTheVastwood.class));
|
||||||
cards.add(new SetCardInfo("Ordeal of Nylea", 123, Rarity.UNCOMMON, mage.cards.o.OrdealOfNylea.class));
|
cards.add(new SetCardInfo("Ordeal of Nylea", 123, Rarity.UNCOMMON, mage.cards.o.OrdealOfNylea.class));
|
||||||
cards.add(new SetCardInfo("Organic Extinction", 8, Rarity.RARE, mage.cards.o.OrganicExtinction.class));
|
cards.add(new SetCardInfo("Organic Extinction", 43, Rarity.RARE, mage.cards.o.OrganicExtinction.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Organic Extinction", 8, Rarity.RARE, mage.cards.o.OrganicExtinction.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Ox of Agonas", 108, Rarity.MYTHIC, mage.cards.o.OxOfAgonas.class));
|
cards.add(new SetCardInfo("Ox of Agonas", 108, Rarity.MYTHIC, mage.cards.o.OxOfAgonas.class));
|
||||||
cards.add(new SetCardInfo("Parhelion II", 87, Rarity.RARE, mage.cards.p.ParhelionII.class));
|
cards.add(new SetCardInfo("Parhelion II", 87, Rarity.RARE, mage.cards.p.ParhelionII.class));
|
||||||
cards.add(new SetCardInfo("Peacewalker Colossus", 155, Rarity.RARE, mage.cards.p.PeacewalkerColossus.class));
|
cards.add(new SetCardInfo("Peacewalker Colossus", 155, Rarity.RARE, mage.cards.p.PeacewalkerColossus.class));
|
||||||
|
@ -108,26 +138,33 @@ public final class NeonDynastyCommander extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Raging Ravine", 176, Rarity.RARE, mage.cards.r.RagingRavine.class));
|
cards.add(new SetCardInfo("Raging Ravine", 176, Rarity.RARE, mage.cards.r.RagingRavine.class));
|
||||||
cards.add(new SetCardInfo("Raiders' Karve", 156, Rarity.COMMON, mage.cards.r.RaidersKarve.class));
|
cards.add(new SetCardInfo("Raiders' Karve", 156, Rarity.COMMON, mage.cards.r.RaidersKarve.class));
|
||||||
cards.add(new SetCardInfo("Rampant Growth", 125, Rarity.COMMON, mage.cards.r.RampantGrowth.class));
|
cards.add(new SetCardInfo("Rampant Growth", 125, Rarity.COMMON, mage.cards.r.RampantGrowth.class));
|
||||||
cards.add(new SetCardInfo("Rampant Rejuvenator", 28, Rarity.RARE, mage.cards.r.RampantRejuvenator.class));
|
cards.add(new SetCardInfo("Rampant Rejuvenator", 28, Rarity.RARE, mage.cards.r.RampantRejuvenator.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Rampant Rejuvenator", 70, Rarity.RARE, mage.cards.r.RampantRejuvenator.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Reality Shift", 95, Rarity.UNCOMMON, mage.cards.r.RealityShift.class));
|
cards.add(new SetCardInfo("Reality Shift", 95, Rarity.UNCOMMON, mage.cards.r.RealityShift.class));
|
||||||
cards.add(new SetCardInfo("Release to Memory", 9, Rarity.RARE, mage.cards.r.ReleaseToMemory.class));
|
cards.add(new SetCardInfo("Release to Memory", 44, Rarity.RARE, mage.cards.r.ReleaseToMemory.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Research Thief", 16, Rarity.RARE, mage.cards.r.ResearchThief.class));
|
cards.add(new SetCardInfo("Release to Memory", 9, Rarity.RARE, mage.cards.r.ReleaseToMemory.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Research Thief", 16, Rarity.RARE, mage.cards.r.ResearchThief.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Research Thief", 53, Rarity.RARE, mage.cards.r.ResearchThief.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Rhythm of the Wild", 142, Rarity.UNCOMMON, mage.cards.r.RhythmOfTheWild.class));
|
cards.add(new SetCardInfo("Rhythm of the Wild", 142, Rarity.UNCOMMON, mage.cards.r.RhythmOfTheWild.class));
|
||||||
cards.add(new SetCardInfo("Riddlesmith", 96, Rarity.UNCOMMON, mage.cards.r.Riddlesmith.class));
|
cards.add(new SetCardInfo("Riddlesmith", 96, Rarity.UNCOMMON, mage.cards.r.Riddlesmith.class));
|
||||||
cards.add(new SetCardInfo("Rishkar's Expertise", 127, Rarity.RARE, mage.cards.r.RishkarsExpertise.class));
|
cards.add(new SetCardInfo("Rishkar's Expertise", 127, Rarity.RARE, mage.cards.r.RishkarsExpertise.class));
|
||||||
cards.add(new SetCardInfo("Rishkar, Peema Renegade", 126, Rarity.RARE, mage.cards.r.RishkarPeemaRenegade.class));
|
cards.add(new SetCardInfo("Rishkar, Peema Renegade", 126, Rarity.RARE, mage.cards.r.RishkarPeemaRenegade.class));
|
||||||
cards.add(new SetCardInfo("Ruthless Technomancer", 35, Rarity.RARE, mage.cards.r.RuthlessTechnomancer.class));
|
cards.add(new SetCardInfo("Ruthless Technomancer", 35, Rarity.RARE, mage.cards.r.RuthlessTechnomancer.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Ruthless Technomancer", 56, Rarity.RARE, mage.cards.r.RuthlessTechnomancer.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Sai, Master Thopterist", 97, Rarity.RARE, mage.cards.s.SaiMasterThopterist.class));
|
cards.add(new SetCardInfo("Sai, Master Thopterist", 97, Rarity.RARE, mage.cards.s.SaiMasterThopterist.class));
|
||||||
cards.add(new SetCardInfo("Sakura-Tribe Elder", 128, Rarity.COMMON, mage.cards.s.SakuraTribeElder.class));
|
cards.add(new SetCardInfo("Sakura-Tribe Elder", 128, Rarity.COMMON, mage.cards.s.SakuraTribeElder.class));
|
||||||
cards.add(new SetCardInfo("Shamanic Revelation", 129, Rarity.RARE, mage.cards.s.ShamanicRevelation.class));
|
cards.add(new SetCardInfo("Shamanic Revelation", 129, Rarity.RARE, mage.cards.s.ShamanicRevelation.class));
|
||||||
cards.add(new SetCardInfo("Shifting Shadow", 109, Rarity.RARE, mage.cards.s.ShiftingShadow.class));
|
cards.add(new SetCardInfo("Shifting Shadow", 109, Rarity.RARE, mage.cards.s.ShiftingShadow.class));
|
||||||
cards.add(new SetCardInfo("Shimmer Myr", 157, Rarity.UNCOMMON, mage.cards.s.ShimmerMyr.class));
|
cards.add(new SetCardInfo("Shimmer Myr", 157, Rarity.UNCOMMON, mage.cards.s.ShimmerMyr.class));
|
||||||
cards.add(new SetCardInfo("Shorikai, Genesis Engine", 4, Rarity.MYTHIC, mage.cards.s.ShorikaiGenesisEngine.class));
|
cards.add(new SetCardInfo("Shorikai, Genesis Engine", 4, Rarity.MYTHIC, mage.cards.s.ShorikaiGenesisEngine.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Silkguard", 29, Rarity.RARE, mage.cards.s.Silkguard.class));
|
cards.add(new SetCardInfo("Shorikai, Genesis Engine", 76, Rarity.MYTHIC, mage.cards.s.ShorikaiGenesisEngine.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Silkguard", 29, Rarity.RARE, mage.cards.s.Silkguard.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Silkguard", 71, Rarity.RARE, mage.cards.s.Silkguard.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Silver Myr", 158, Rarity.COMMON, mage.cards.s.SilverMyr.class));
|
cards.add(new SetCardInfo("Silver Myr", 158, Rarity.COMMON, mage.cards.s.SilverMyr.class));
|
||||||
cards.add(new SetCardInfo("Skycloud Expanse", 177, Rarity.RARE, mage.cards.s.SkycloudExpanse.class));
|
cards.add(new SetCardInfo("Skycloud Expanse", 177, Rarity.RARE, mage.cards.s.SkycloudExpanse.class));
|
||||||
cards.add(new SetCardInfo("Skysovereign, Consul Flagship", 159, Rarity.MYTHIC, mage.cards.s.SkysovereignConsulFlagship.class));
|
cards.add(new SetCardInfo("Skysovereign, Consul Flagship", 159, Rarity.MYTHIC, mage.cards.s.SkysovereignConsulFlagship.class));
|
||||||
cards.add(new SetCardInfo("Smoke Spirits' Aid", 22, Rarity.RARE, mage.cards.s.SmokeSpiritsAid.class));
|
cards.add(new SetCardInfo("Smoke Spirits' Aid", 22, Rarity.RARE, mage.cards.s.SmokeSpiritsAid.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Smoke Spirits' Aid", 62, Rarity.RARE, mage.cards.s.SmokeSpiritsAid.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Smuggler's Copter", 160, Rarity.RARE, mage.cards.s.SmugglersCopter.class));
|
cards.add(new SetCardInfo("Smuggler's Copter", 160, Rarity.RARE, mage.cards.s.SmugglersCopter.class));
|
||||||
cards.add(new SetCardInfo("Snake Umbra", 130, Rarity.UNCOMMON, mage.cards.s.SnakeUmbra.class));
|
cards.add(new SetCardInfo("Snake Umbra", 130, Rarity.UNCOMMON, mage.cards.s.SnakeUmbra.class));
|
||||||
cards.add(new SetCardInfo("Sol Ring", 161, Rarity.UNCOMMON, mage.cards.s.SolRing.class));
|
cards.add(new SetCardInfo("Sol Ring", 161, Rarity.UNCOMMON, mage.cards.s.SolRing.class));
|
||||||
|
@ -137,11 +174,13 @@ public final class NeonDynastyCommander extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Spire of Industry", 178, Rarity.RARE, mage.cards.s.SpireOfIndustry.class));
|
cards.add(new SetCardInfo("Spire of Industry", 178, Rarity.RARE, mage.cards.s.SpireOfIndustry.class));
|
||||||
cards.add(new SetCardInfo("Sram, Senior Edificer", 88, Rarity.RARE, mage.cards.s.SramSeniorEdificer.class));
|
cards.add(new SetCardInfo("Sram, Senior Edificer", 88, Rarity.RARE, mage.cards.s.SramSeniorEdificer.class));
|
||||||
cards.add(new SetCardInfo("Starstorm", 110, Rarity.RARE, mage.cards.s.Starstorm.class));
|
cards.add(new SetCardInfo("Starstorm", 110, Rarity.RARE, mage.cards.s.Starstorm.class));
|
||||||
cards.add(new SetCardInfo("Swift Reconfiguration", 10, Rarity.RARE, mage.cards.s.SwiftReconfiguration.class));
|
cards.add(new SetCardInfo("Swift Reconfiguration", 10, Rarity.RARE, mage.cards.s.SwiftReconfiguration.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Swift Reconfiguration", 45, Rarity.RARE, mage.cards.s.SwiftReconfiguration.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Swiftfoot Boots", 163, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class));
|
cards.add(new SetCardInfo("Swiftfoot Boots", 163, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class));
|
||||||
cards.add(new SetCardInfo("Sword of Vengeance", 164, Rarity.RARE, mage.cards.s.SwordOfVengeance.class));
|
cards.add(new SetCardInfo("Sword of Vengeance", 164, Rarity.RARE, mage.cards.s.SwordOfVengeance.class));
|
||||||
cards.add(new SetCardInfo("Swords to Plowshares", 89, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class));
|
cards.add(new SetCardInfo("Swords to Plowshares", 89, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class));
|
||||||
cards.add(new SetCardInfo("Tanuki Transplanter", 30, Rarity.RARE, mage.cards.t.TanukiTransplanter.class));
|
cards.add(new SetCardInfo("Tanuki Transplanter", 30, Rarity.RARE, mage.cards.t.TanukiTransplanter.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Tanuki Transplanter", 72, Rarity.RARE, mage.cards.t.TanukiTransplanter.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Taurean Mauler", 111, Rarity.RARE, mage.cards.t.TaureanMauler.class));
|
cards.add(new SetCardInfo("Taurean Mauler", 111, Rarity.RARE, mage.cards.t.TaureanMauler.class));
|
||||||
cards.add(new SetCardInfo("Temple of Abandon", 179, Rarity.RARE, mage.cards.t.TempleOfAbandon.class));
|
cards.add(new SetCardInfo("Temple of Abandon", 179, Rarity.RARE, mage.cards.t.TempleOfAbandon.class));
|
||||||
cards.add(new SetCardInfo("Temple of Enlightenment", 180, Rarity.RARE, mage.cards.t.TempleOfEnlightenment.class));
|
cards.add(new SetCardInfo("Temple of Enlightenment", 180, Rarity.RARE, mage.cards.t.TempleOfEnlightenment.class));
|
||||||
|
@ -149,13 +188,16 @@ public final class NeonDynastyCommander extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Thopter Spy Network", 98, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class));
|
cards.add(new SetCardInfo("Thopter Spy Network", 98, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class));
|
||||||
cards.add(new SetCardInfo("Thoughtcast", 99, Rarity.COMMON, mage.cards.t.Thoughtcast.class));
|
cards.add(new SetCardInfo("Thoughtcast", 99, Rarity.COMMON, mage.cards.t.Thoughtcast.class));
|
||||||
cards.add(new SetCardInfo("Ulasht, the Hate Seed", 143, Rarity.RARE, mage.cards.u.UlashtTheHateSeed.class));
|
cards.add(new SetCardInfo("Ulasht, the Hate Seed", 143, Rarity.RARE, mage.cards.u.UlashtTheHateSeed.class));
|
||||||
cards.add(new SetCardInfo("Universal Surveillance", 17, Rarity.RARE, mage.cards.u.UniversalSurveillance.class));
|
cards.add(new SetCardInfo("Universal Surveillance", 17, Rarity.RARE, mage.cards.u.UniversalSurveillance.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Unquenchable Fury", 23, Rarity.RARE, mage.cards.u.UnquenchableFury.class));
|
cards.add(new SetCardInfo("Universal Surveillance", 54, Rarity.RARE, mage.cards.u.UniversalSurveillance.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Unquenchable Fury", 23, Rarity.RARE, mage.cards.u.UnquenchableFury.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Unquenchable Fury", 63, Rarity.RARE, mage.cards.u.UnquenchableFury.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Vastwood Surge", 133, Rarity.UNCOMMON, mage.cards.v.VastwoodSurge.class));
|
cards.add(new SetCardInfo("Vastwood Surge", 133, Rarity.UNCOMMON, mage.cards.v.VastwoodSurge.class));
|
||||||
cards.add(new SetCardInfo("Vedalken Engineer", 100, Rarity.COMMON, mage.cards.v.VedalkenEngineer.class));
|
cards.add(new SetCardInfo("Vedalken Engineer", 100, Rarity.COMMON, mage.cards.v.VedalkenEngineer.class));
|
||||||
cards.add(new SetCardInfo("Weatherlight", 165, Rarity.MYTHIC, mage.cards.w.Weatherlight.class));
|
cards.add(new SetCardInfo("Weatherlight", 165, Rarity.MYTHIC, mage.cards.w.Weatherlight.class));
|
||||||
cards.add(new SetCardInfo("Whiptongue Hydra", 134, Rarity.RARE, mage.cards.w.WhiptongueHydra.class));
|
cards.add(new SetCardInfo("Whiptongue Hydra", 134, Rarity.RARE, mage.cards.w.WhiptongueHydra.class));
|
||||||
cards.add(new SetCardInfo("Whirler Rogue", 101, Rarity.UNCOMMON, mage.cards.w.WhirlerRogue.class));
|
cards.add(new SetCardInfo("Whirler Rogue", 101, Rarity.UNCOMMON, mage.cards.w.WhirlerRogue.class));
|
||||||
cards.add(new SetCardInfo("Yoshimaru, Ever Faithful", 32, Rarity.MYTHIC, mage.cards.y.YoshimaruEverFaithful.class));
|
cards.add(new SetCardInfo("Yoshimaru, Ever Faithful", 32, Rarity.MYTHIC, mage.cards.y.YoshimaruEverFaithful.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Yoshimaru, Ever Faithful", 46, Rarity.MYTHIC, mage.cards.y.YoshimaruEverFaithful.class, NON_FULL_USE_VARIOUS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package org.mage.test.cards.abilities.keywords;
|
package org.mage.test.cards.abilities.keywords;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import mage.constants.MultiplayerAttackOption;
|
import mage.constants.MultiplayerAttackOption;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.RangeOfInfluence;
|
import mage.constants.RangeOfInfluence;
|
||||||
|
@ -10,16 +9,29 @@ import mage.game.Game;
|
||||||
import mage.game.GameException;
|
import mage.game.GameException;
|
||||||
import mage.game.mulligan.MulliganType;
|
import mage.game.mulligan.MulliganType;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.players.Player;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mage.test.player.TestPlayer;
|
||||||
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
|
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class GoadTest extends CardTestMultiPlayerBase {
|
public class GoadTest extends CardTestMultiPlayerBase {
|
||||||
|
|
||||||
|
private static final String marisi = "Marisi, Breaker of the Coil";
|
||||||
|
private static final String griffin = "Abbey Griffin";
|
||||||
|
private static final String ray = "Ray of Command";
|
||||||
|
private static final String homunculus = "Jeering Homunculus";
|
||||||
|
private static final String lion = "Silvercoat Lion";
|
||||||
|
private static final String archon = "Blazing Archon";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
|
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
|
||||||
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
|
Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40);
|
||||||
|
@ -31,85 +43,155 @@ public class GoadTest extends CardTestMultiPlayerBase {
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertAttacking(String attacker, TestPlayer... players) {
|
||||||
|
Assert.assertTrue("At least one player should be provided", players.length > 0);
|
||||||
|
Permanent permanent = getPermanent(attacker);
|
||||||
|
Assert.assertTrue("Creature should be tapped", permanent.isTapped());
|
||||||
|
Assert.assertTrue("Creature should be attacking", permanent.isAttacking());
|
||||||
|
UUID defenderId = currentGame.getCombat().getDefenderId(permanent.getId());
|
||||||
|
Assert.assertTrue(
|
||||||
|
"Creature should be attacking one the following players: "
|
||||||
|
+ Arrays
|
||||||
|
.stream(players)
|
||||||
|
.map(Player::getName)
|
||||||
|
.reduce((a, b) -> a + ", " + b)
|
||||||
|
.orElse(""),
|
||||||
|
Arrays.stream(players)
|
||||||
|
.map(TestPlayer::getId)
|
||||||
|
.anyMatch(defenderId::equals)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertGoaded(String attacker, TestPlayer... players) {
|
||||||
|
Assert.assertTrue("At least one player should be provided", players.length > 0);
|
||||||
|
Permanent permanent = getPermanent(attacker);
|
||||||
|
Assert.assertEquals(
|
||||||
|
"Creature should be goaded by "
|
||||||
|
+ Arrays
|
||||||
|
.stream(players)
|
||||||
|
.map(Player::getName)
|
||||||
|
.reduce((a, b) -> a + ", " + b).orElse(""),
|
||||||
|
permanent.getGoadingPlayers(),
|
||||||
|
Arrays.stream(players)
|
||||||
|
.map(TestPlayer::getId)
|
||||||
|
.collect(Collectors.toSet())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void goadWithOwnedCreatureTest() {
|
public void testCantAttackGoadingPlayer() {
|
||||||
// Your opponents can't cast spells during combat.
|
addCard(Zone.HAND, playerA, homunculus);
|
||||||
// Whenever a creature you control deals combat damage to a player, goad each creature that player controls
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
// (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.)
|
addCard(Zone.BATTLEFIELD, playerD, lion);
|
||||||
addCard(Zone.BATTLEFIELD, playerD, "Marisi, Breaker of the Coil", 1); // Creature 5/4
|
|
||||||
|
|
||||||
addCard(Zone.BATTLEFIELD, playerC, "Abbey Griffin", 3); // Creature 2/2
|
addTarget(playerA, lion);
|
||||||
|
setChoice(playerA, "Yes");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus);
|
||||||
|
|
||||||
attack(2, playerD, "Marisi, Breaker of the Coil", playerC);
|
setStopAt(2, PhaseStep.DECLARE_BLOCKERS);
|
||||||
|
|
||||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
|
||||||
execute();
|
execute();
|
||||||
assertAllCommandsUsed();
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
Permanent griffinPermanent = getPermanent("Abbey Griffin");
|
assertGoaded(lion, playerA);
|
||||||
|
assertAttacking(lion, playerB, playerC);
|
||||||
Assert.assertFalse("Griffin can attack playerD but should not be able",
|
|
||||||
griffinPermanent.canAttack(playerD.getId(), currentGame));
|
|
||||||
Assert.assertTrue("Griffin can't attack playerA but should be able",
|
|
||||||
griffinPermanent.canAttack(playerA.getId(), currentGame));
|
|
||||||
Assert.assertTrue("Griffin can't attack playerB but should be able",
|
|
||||||
griffinPermanent.canAttack(playerB.getId(), currentGame));
|
|
||||||
|
|
||||||
assertLife(playerC, 35);
|
|
||||||
assertLife(playerD, 40); // player D can not be attacked from C because the creatures are goaded
|
|
||||||
assertLife(playerA, 40);
|
|
||||||
assertLife(playerB, 40);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* In a game of commander, my opponent gained control of Marisi, Breaker of
|
|
||||||
* Coils (until end of turn) and did combat damage to another player. This
|
|
||||||
* caused the creatures damaged by Marisi's controller to be goaded.
|
|
||||||
* However, when the goaded creatures went to attack, they could not attack
|
|
||||||
* me but could attack the (former) controller of Marisi.
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public void goadWithNotOwnedCreatureTest() {
|
public void testCanOnlyAttackOnePlayer() {
|
||||||
// Your opponents can't cast spells during combat.
|
addCard(Zone.HAND, playerA, homunculus);
|
||||||
// Whenever a creature you control deals combat damage to a player, goad each creature that player controls
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
// (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.)
|
addCard(Zone.BATTLEFIELD, playerD, lion);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Marisi, Breaker of the Coil", 1); // Creature 5/4
|
addCard(Zone.BATTLEFIELD, playerB, archon);
|
||||||
|
|
||||||
// Untap target creature an opponent controls and gain control of it until end of turn.
|
addTarget(playerA, lion);
|
||||||
// That creature gains haste until end of turn.
|
setChoice(playerA, "Yes");
|
||||||
// When you lose control of the creature, tap it.
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus);
|
||||||
addCard(Zone.HAND, playerD, "Ray of Command"); // Instant {3}{U}
|
|
||||||
addCard(Zone.BATTLEFIELD, playerD, "Island", 4);
|
|
||||||
|
|
||||||
addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion", 1); // Creature 2/2
|
setStopAt(2, PhaseStep.DECLARE_BLOCKERS);
|
||||||
|
|
||||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Ray of Command", "Marisi, Breaker of the Coil");
|
|
||||||
|
|
||||||
attack(2, playerD, "Marisi, Breaker of the Coil", playerC);
|
|
||||||
|
|
||||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
|
||||||
setStrictChooseMode(true);
|
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertAllCommandsUsed();
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
assertGraveyardCount(playerD, "Ray of Command", 1);
|
assertGoaded(lion, playerA);
|
||||||
assertPermanentCount(playerA, "Marisi, Breaker of the Coil", 1);
|
assertAttacking(lion, playerC);
|
||||||
|
|
||||||
Permanent lion = getPermanent("Silvercoat Lion", playerC);
|
|
||||||
|
|
||||||
Assert.assertFalse("Silvercoat lion shouldn't be able to attack player D but can", lion.canAttack(playerD.getId(), currentGame));
|
|
||||||
Assert.assertTrue("Silvercoat lion should be able to attack player A but can't", lion.canAttack(playerA.getId(), currentGame));
|
|
||||||
Assert.assertTrue("Silvercoat lion should be able to attack player B but can't", lion.canAttack(playerB.getId(), currentGame));
|
|
||||||
|
|
||||||
assertLife(playerD, 40);
|
|
||||||
assertLife(playerC, 35);
|
|
||||||
assertLife(playerA, 40);
|
|
||||||
assertLife(playerB, 40);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMustAttackGoader() {
|
||||||
|
addCard(Zone.HAND, playerA, homunculus);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerD, lion);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, archon);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerC, archon);
|
||||||
|
|
||||||
|
addTarget(playerA, lion);
|
||||||
|
setChoice(playerA, "Yes");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus);
|
||||||
|
|
||||||
|
setStopAt(2, PhaseStep.DECLARE_BLOCKERS);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertGoaded(lion, playerA);
|
||||||
|
assertAttacking(lion, playerA);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleGoad() {
|
||||||
|
addCard(Zone.HAND, playerA, homunculus);
|
||||||
|
addCard(Zone.HAND, playerD, homunculus);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerD, "Island", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerC, lion);
|
||||||
|
|
||||||
|
addTarget(playerA, lion);
|
||||||
|
setChoice(playerA, "Yes");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus);
|
||||||
|
|
||||||
|
addTarget(playerD, lion);
|
||||||
|
setChoice(playerD, "Yes");
|
||||||
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, homunculus);
|
||||||
|
|
||||||
|
setStopAt(3, PhaseStep.DECLARE_BLOCKERS);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertGoaded(lion, playerA, playerD);
|
||||||
|
assertAttacking(lion, playerB);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleGoadRestriction() {
|
||||||
|
addCard(Zone.HAND, playerA, homunculus);
|
||||||
|
addCard(Zone.HAND, playerD, homunculus);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerD, "Island", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, archon);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerC, lion);
|
||||||
|
|
||||||
|
addTarget(playerA, lion);
|
||||||
|
setChoice(playerA, "Yes");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus);
|
||||||
|
|
||||||
|
addTarget(playerD, lion);
|
||||||
|
setChoice(playerD, "Yes");
|
||||||
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, homunculus);
|
||||||
|
|
||||||
|
setStopAt(3, PhaseStep.DECLARE_BLOCKERS);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertGoaded(lion, playerA, playerD);
|
||||||
|
assertAttacking(lion, playerA, playerD);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegularCombatRequirement() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Berserkers of Blood Ridge");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.DECLARE_BLOCKERS);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertAttacking("Berserkers of Blood Ridge", playerB, playerC, playerD);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package mage.abilities.common;
|
package mage.abilities.common;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.constants.SetTargetPointer;
|
import mage.constants.SetTargetPointer;
|
||||||
|
@ -11,9 +10,11 @@ import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
@ -74,18 +75,15 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
getEffects().setValue("attacker", permanent);
|
||||||
switch (setTargetPointer) {
|
switch (setTargetPointer) {
|
||||||
case PERMANENT:
|
case PERMANENT:
|
||||||
for (Effect effect : getEffects()) {
|
getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case PLAYER:
|
case PLAYER:
|
||||||
UUID playerId = controller ? permanent.getControllerId() : game.getCombat().getDefendingPlayerId(permanent.getId(), game);
|
UUID playerId = controller ? permanent.getControllerId() : game.getCombat().getDefendingPlayerId(permanent.getId(), game);
|
||||||
if (playerId != null) {
|
if (playerId != null) {
|
||||||
for (Effect effect : getEffects()) {
|
getEffects().setTargetPointer(new FixedTarget(playerId));
|
||||||
effect.setTargetPointer(new FixedTarget(playerId));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -101,10 +99,8 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTriggerPhrase() {
|
public String getTriggerPhrase() {
|
||||||
return "Whenever " + (filter.getMessage().startsWith("an") ? "" : "a ")
|
return "Whenever " + CardUtil.addArticle(filter.getMessage()) + " attacks"
|
||||||
+ filter.getMessage() + " attacks"
|
+ (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "") + ", ";
|
||||||
+ (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "")
|
|
||||||
+ ", " ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
package mage.abilities.common;
|
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.StaticAbility;
|
|
||||||
import mage.abilities.effects.Effect;
|
|
||||||
import mage.abilities.effects.RestrictionEffect;
|
|
||||||
import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect;
|
|
||||||
import mage.constants.AttachmentType;
|
|
||||||
import mage.constants.Duration;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.game.Game;
|
|
||||||
import mage.game.permanent.Permanent;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author TheElk801
|
|
||||||
*/
|
|
||||||
public class GoadAttachedAbility extends StaticAbility {
|
|
||||||
|
|
||||||
public GoadAttachedAbility(Effect... effects) {
|
|
||||||
super(Zone.BATTLEFIELD, null);
|
|
||||||
for (Effect effect : effects) {
|
|
||||||
this.addEffect(effect);
|
|
||||||
}
|
|
||||||
this.addEffect(new AttacksIfAbleAttachedEffect(
|
|
||||||
Duration.WhileOnBattlefield, AttachmentType.AURA
|
|
||||||
).setText((getEffects().size() > 1 ? ", " : " ") + "and is goaded. <i>(It attacks each combat if able"));
|
|
||||||
this.addEffect(new GoadAttackEffect());
|
|
||||||
}
|
|
||||||
|
|
||||||
private GoadAttachedAbility(final GoadAttachedAbility ability) {
|
|
||||||
super(ability);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GoadAttachedAbility copy() {
|
|
||||||
return new GoadAttachedAbility(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GoadAttackEffect extends RestrictionEffect {
|
|
||||||
|
|
||||||
GoadAttackEffect() {
|
|
||||||
super(Duration.WhileOnBattlefield);
|
|
||||||
staticText = "and attacks a player other than you if able.)</i>";
|
|
||||||
}
|
|
||||||
|
|
||||||
private GoadAttackEffect(final GoadAttackEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GoadAttackEffect copy() {
|
|
||||||
return new GoadAttackEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
|
||||||
Permanent attachment = game.getPermanent(source.getSourceId());
|
|
||||||
return attachment != null && attachment.getAttachedTo() != null
|
|
||||||
&& permanent.getId().equals(attachment.getAttachedTo());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) {
|
|
||||||
if (defenderId == null
|
|
||||||
|| game.getState().getPlayersInRange(attacker.getControllerId(), game).size() == 2) { // just 2 players left, so it may attack you
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// A planeswalker controlled by the controller is the defender
|
|
||||||
if (game.getPermanent(defenderId) != null) {
|
|
||||||
return !game.getPermanent(defenderId).getControllerId().equals(source.getControllerId());
|
|
||||||
}
|
|
||||||
// The controller is the defender
|
|
||||||
return !defenderId.equals(source.getControllerId());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package mage.abilities.effects.common.combat;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.effects.RestrictionEffect;
|
|
||||||
import mage.constants.Duration;
|
|
||||||
import mage.game.Game;
|
|
||||||
import mage.game.permanent.Permanent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author TheElk801
|
|
||||||
*/
|
|
||||||
public class CantAttackControllerDueToGoadEffect extends RestrictionEffect {
|
|
||||||
|
|
||||||
public CantAttackControllerDueToGoadEffect(Duration duration) {
|
|
||||||
super(duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CantAttackControllerDueToGoadEffect(final CantAttackControllerDueToGoadEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CantAttackControllerDueToGoadEffect copy() {
|
|
||||||
return new CantAttackControllerDueToGoadEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
|
||||||
return this.getTargetPointer().getTargets(game, source).contains(permanent.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) {
|
|
||||||
if (defenderId == null
|
|
||||||
|| game.getState().getPlayersInRange(attacker.getControllerId(), game).size() == 2) { // just 2 players left, so it may attack you
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// A planeswalker controlled by the controller is the defender
|
|
||||||
if (game.getPermanent(defenderId) != null) {
|
|
||||||
return !game.getPermanent(defenderId).getControllerId().equals(source.getControllerId());
|
|
||||||
}
|
|
||||||
// The controller is the defender
|
|
||||||
return !defenderId.equals(source.getControllerId());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package mage.abilities.effects.common.combat;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Layer;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubLayer;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheElk801
|
||||||
|
*/
|
||||||
|
public class GoadAttachedEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
|
public GoadAttachedEffect() {
|
||||||
|
super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment);
|
||||||
|
staticText = "and is goaded";
|
||||||
|
}
|
||||||
|
|
||||||
|
private GoadAttachedEffect(final GoadAttachedEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||||
|
if (permanent == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Permanent attached = game.getPermanent(permanent.getAttachedTo());
|
||||||
|
if (attached == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
attached.addGoadingPlayer(source.getControllerId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GoadAttachedEffect copy() {
|
||||||
|
return new GoadAttachedEffect(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,19 +2,19 @@ package mage.abilities.effects.common.combat;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.Mode;
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.effects.ContinuousEffect;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Layer;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubLayer;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public class GoadTargetEffect extends OneShotEffect {
|
public class GoadTargetEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 701.36. Goad
|
* 701.36. Goad
|
||||||
|
@ -24,10 +24,10 @@ public class GoadTargetEffect extends OneShotEffect {
|
||||||
* each combat if able and attacks a player other than that player if able.
|
* each combat if able and attacks a player other than that player if able.
|
||||||
*/
|
*/
|
||||||
public GoadTargetEffect() {
|
public GoadTargetEffect() {
|
||||||
super(Outcome.Detriment);
|
super(Duration.UntilYourNextTurn, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GoadTargetEffect(final GoadTargetEffect effect) {
|
private GoadTargetEffect(final GoadTargetEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,26 +37,22 @@ public class GoadTargetEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game);
|
||||||
Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (targetCreature != null && controller != null) {
|
if (targetCreature != null && controller != null) {
|
||||||
// TODO: Allow goad to target controller, current AttacksIfAbleTargetEffect does not support it
|
|
||||||
// https://github.com/magefree/mage/issues/5283
|
|
||||||
/*
|
|
||||||
If the creature doesn’t meet any of the above exceptions and can attack, it must attack a player other than
|
|
||||||
the controller of the spell or ability that goaded it if able. If the creature can’t attack any of those
|
|
||||||
players but could otherwise attack, it must attack an opposing planeswalker (controlled by any opponent)
|
|
||||||
or the player that goaded it. (2016-08-23)
|
|
||||||
*/
|
|
||||||
ContinuousEffect effect = new AttacksIfAbleTargetEffect(Duration.UntilYourNextTurn);
|
|
||||||
effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source), game));
|
|
||||||
game.addEffect(effect, source);
|
|
||||||
effect = new CantAttackControllerDueToGoadEffect(Duration.UntilYourNextTurn); // remember current controller
|
|
||||||
effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source), game));
|
|
||||||
game.addEffect(effect, source);
|
|
||||||
game.informPlayers(controller.getLogName() + " is goading " + targetCreature.getLogName());
|
game.informPlayers(controller.getLogName() + " is goading " + targetCreature.getLogName());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
|
if (targetCreature == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
targetCreature.addGoadingPlayer(source.getControllerId());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -440,65 +440,76 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
for (Permanent creature : player.getAvailableAttackers(game)) {
|
for (Permanent creature : player.getAvailableAttackers(game)) {
|
||||||
boolean mustAttack = false;
|
boolean mustAttack = false;
|
||||||
Set<UUID> defendersForcedToAttack = new HashSet<>();
|
Set<UUID> defendersForcedToAttack = new HashSet<>();
|
||||||
|
if (creature.getGoadingPlayers().isEmpty()) {
|
||||||
// check if a creature has to attack
|
// check if a creature has to attack
|
||||||
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, false, game).entrySet()) {
|
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, false, game).entrySet()) {
|
||||||
RequirementEffect effect = entry.getKey();
|
RequirementEffect effect = entry.getKey();
|
||||||
if (effect.mustAttack(game)
|
if (!effect.mustAttack(game)) {
|
||||||
&& checkAttackRestrictions(player, game)) { // needed for Goad Effect
|
continue;
|
||||||
|
}
|
||||||
mustAttack = true;
|
mustAttack = true;
|
||||||
for (Ability ability : entry.getValue()) {
|
for (Ability ability : entry.getValue()) {
|
||||||
UUID defenderId = effect.mustAttackDefender(ability, game);
|
UUID defenderId = effect.mustAttackDefender(ability, game);
|
||||||
if (defenderId != null) {
|
if (defenderId != null && defenders.contains(defenderId)) {
|
||||||
if (defenders.contains(defenderId)) {
|
defendersForcedToAttack.add(defenderId);
|
||||||
defendersForcedToAttack.add(defenderId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// if creature is goaded then we start with assumption that it needs to attack any player
|
||||||
|
mustAttack = true;
|
||||||
|
defendersForcedToAttack.addAll(defenders);
|
||||||
}
|
}
|
||||||
if (mustAttack) {
|
if (!mustAttack) {
|
||||||
// check which defenders the forced to attack creature can attack without paying a cost
|
continue;
|
||||||
Set<UUID> defendersCostlessAttackable = new HashSet<>(defenders);
|
}
|
||||||
for (UUID defenderId : defenders) {
|
// check which defenders the forced to attack creature can attack without paying a cost
|
||||||
if (game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects(
|
Set<UUID> defendersCostlessAttackable = new HashSet<>(defenders);
|
||||||
new DeclareAttackerEvent(defenderId, creature.getId(), creature.getControllerId()), game)) {
|
for (UUID defenderId : defenders) {
|
||||||
defendersCostlessAttackable.remove(defenderId);
|
if (game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects(
|
||||||
defendersForcedToAttack.remove(defenderId);
|
new DeclareAttackerEvent(defenderId, creature.getId(), creature.getControllerId()), game
|
||||||
}
|
)) {
|
||||||
}
|
defendersCostlessAttackable.remove(defenderId);
|
||||||
// force attack only if a defender can be attacked without paying a cost
|
defendersForcedToAttack.remove(defenderId);
|
||||||
if (!defendersCostlessAttackable.isEmpty()) {
|
continue;
|
||||||
creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack);
|
}
|
||||||
// No need to attack a special defender
|
for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(creature, game).entrySet()) {
|
||||||
if (defendersForcedToAttack.isEmpty()) {
|
if (entry
|
||||||
if (defendersCostlessAttackable.size() == 1) {
|
.getValue()
|
||||||
player.declareAttacker(creature.getId(), defendersCostlessAttackable.iterator().next(), game, false);
|
.stream()
|
||||||
} else {
|
.anyMatch(ability -> entry.getKey().canAttack(
|
||||||
TargetDefender target = new TargetDefender(defendersCostlessAttackable, creature.getId());
|
creature, defenderId, ability, game, false
|
||||||
target.setRequired(true);
|
))) {
|
||||||
target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack (must attack effect)");
|
continue;
|
||||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
}
|
||||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
|
defendersCostlessAttackable.remove(defenderId);
|
||||||
}
|
defendersForcedToAttack.remove(defenderId);
|
||||||
}
|
break;
|
||||||
} else {
|
}
|
||||||
if (defendersForcedToAttack.size() == 1) {
|
}
|
||||||
player.declareAttacker(creature.getId(), defendersForcedToAttack.iterator().next(), game, false);
|
// if creature can attack someone other than a player that goaded them
|
||||||
} else {
|
// then they attack one of those players, otherwise they attack any player
|
||||||
TargetDefender target = new TargetDefender(defendersForcedToAttack, creature.getId());
|
if (!defendersForcedToAttack.stream().allMatch(creature.getGoadingPlayers()::contains)) {
|
||||||
target.setRequired(true);
|
defendersForcedToAttack.removeAll(creature.getGoadingPlayers());
|
||||||
target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack (must attack effect)");
|
}
|
||||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
// force attack only if a defender can be attacked without paying a cost
|
||||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
|
if (defendersCostlessAttackable.isEmpty()) {
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
}
|
creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack);
|
||||||
}
|
// No need to attack a special defender
|
||||||
|
Set<UUID> defendersToChooseFrom = defendersForcedToAttack.isEmpty() ? defendersCostlessAttackable : defendersForcedToAttack;
|
||||||
|
if (defendersToChooseFrom.size() == 1) {
|
||||||
|
player.declareAttacker(creature.getId(), defendersToChooseFrom.iterator().next(), game, false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TargetDefender target = new TargetDefender(defendersToChooseFrom, creature.getId());
|
||||||
|
target.setRequired(true);
|
||||||
|
target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack (must attack effect)");
|
||||||
|
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
||||||
|
player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,28 +540,30 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) {
|
for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) {
|
||||||
RestrictionEffect effect = entry.getKey();
|
RestrictionEffect effect = entry.getKey();
|
||||||
for (Ability ability : entry.getValue()) {
|
for (Ability ability : entry.getValue()) {
|
||||||
if (!effect.canAttackCheckAfter(numberAttackers, ability, game, true)) {
|
if (effect.canAttackCheckAfter(numberAttackers, ability, game, true)) {
|
||||||
MageObject sourceObject = ability.getSourceObject(game);
|
continue;
|
||||||
if (attackingPlayer.isHuman()) {
|
|
||||||
attackingPlayer.resetPlayerPassedActions();
|
|
||||||
game.informPlayer(attackingPlayer, attackingCreature.getIdName() + " can't attack this way (" + (sourceObject == null ? "null" : sourceObject.getIdName()) + ')');
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// remove attacking creatures for AI that are not allowed to attack
|
|
||||||
// can create possible not allowed attack scenarios, but not sure how to solve this
|
|
||||||
for (CombatGroup combatGroup : this.getGroups()) {
|
|
||||||
if (combatGroup.getAttackers().contains(attackingCreatureId)) {
|
|
||||||
attackerToRemove = attackingCreatureId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
check = true; // do the check again
|
|
||||||
if (numberOfChecks > 50) {
|
|
||||||
logger.error("Seems to be an AI declare attacker lock (reached 50 check iterations) " + (sourceObject == null ? "null" : sourceObject.getIdName()));
|
|
||||||
return true; // break the check
|
|
||||||
}
|
|
||||||
continue Check;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
MageObject sourceObject = ability.getSourceObject(game);
|
||||||
|
if (attackingPlayer.isHuman()) {
|
||||||
|
attackingPlayer.resetPlayerPassedActions();
|
||||||
|
game.informPlayer(attackingPlayer, attackingCreature.getIdName() + " can't attack this way (" + (sourceObject == null ? "null" : sourceObject.getIdName()) + ')');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// remove attacking creatures for AI that are not allowed to attack
|
||||||
|
// can create possible not allowed attack scenarios, but not sure how to solve this
|
||||||
|
if (this.getGroups()
|
||||||
|
.stream()
|
||||||
|
.map(CombatGroup::getAttackers)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.anyMatch(attackingCreatureId::equals)) {
|
||||||
|
attackerToRemove = attackingCreatureId;
|
||||||
|
}
|
||||||
|
check = true; // do the check again
|
||||||
|
if (numberOfChecks > 50) {
|
||||||
|
logger.error("Seems to be an AI declare attacker lock (reached 50 check iterations) " + (sourceObject == null ? "null" : sourceObject.getIdName()));
|
||||||
|
return true; // break the check
|
||||||
|
}
|
||||||
|
continue Check;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1300,21 +1313,20 @@ public class Combat implements Serializable, Copyable<Combat> {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public boolean declareAttacker(UUID creatureId, UUID defenderId, UUID playerId, Game game) {
|
public boolean declareAttacker(UUID creatureId, UUID defenderId, UUID playerId, Game game) {
|
||||||
Permanent attacker = game.getPermanent(creatureId);
|
Permanent attacker = game.getPermanent(creatureId);
|
||||||
if (attacker != null) {
|
if (attacker == null
|
||||||
if (!game.replaceEvent(new DeclareAttackerEvent(defenderId, creatureId, playerId))) {
|
|| game.replaceEvent(new DeclareAttackerEvent(defenderId, creatureId, playerId))
|
||||||
if (addAttackerToCombat(creatureId, defenderId, game)) {
|
|| !addAttackerToCombat(creatureId, defenderId, game)) {
|
||||||
if (!attacker.hasAbility(VigilanceAbility.getInstance(), game)
|
return false;
|
||||||
&& !attacker.hasAbility(JohanVigilanceAbility.getInstance(), game)) {
|
|
||||||
if (!attacker.isTapped()) {
|
|
||||||
attacker.setTapped(true);
|
|
||||||
attackersTappedByAttack.add(attacker.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
if (attacker.hasAbility(VigilanceAbility.getInstance(), game)
|
||||||
|
|| attacker.hasAbility(JohanVigilanceAbility.getInstance(), game)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!attacker.isTapped()) {
|
||||||
|
attacker.setTapped(true);
|
||||||
|
attackersTappedByAttack.add(attacker.getId());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addAttackerToCombat(UUID attackerId, UUID defenderId, Game game) {
|
public boolean addAttackerToCombat(UUID attackerId, UUID defenderId, Game game) {
|
||||||
|
|
|
@ -87,6 +87,10 @@ public interface Permanent extends Card, Controllable {
|
||||||
*/
|
*/
|
||||||
boolean setClassLevel(int classLevel);
|
boolean setClassLevel(int classLevel);
|
||||||
|
|
||||||
|
void addGoadingPlayer(UUID playerId);
|
||||||
|
|
||||||
|
Set<UUID> getGoadingPlayers();
|
||||||
|
|
||||||
void setCardNumber(String cid);
|
void setCardNumber(String cid);
|
||||||
|
|
||||||
void setExpansionSetCode(String expansionSetCode);
|
void setExpansionSetCode(String expansionSetCode);
|
||||||
|
|
|
@ -72,6 +72,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
protected boolean manifested = false;
|
protected boolean manifested = false;
|
||||||
protected boolean morphed = false;
|
protected boolean morphed = false;
|
||||||
protected int classLevel = 1;
|
protected int classLevel = 1;
|
||||||
|
protected final Set<UUID> goadingPlayers = new HashSet<>();
|
||||||
protected UUID originalControllerId;
|
protected UUID originalControllerId;
|
||||||
protected UUID controllerId;
|
protected UUID controllerId;
|
||||||
protected UUID beforeResetControllerId;
|
protected UUID beforeResetControllerId;
|
||||||
|
@ -165,6 +166,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
this.monstrous = permanent.monstrous;
|
this.monstrous = permanent.monstrous;
|
||||||
this.renowned = permanent.renowned;
|
this.renowned = permanent.renowned;
|
||||||
this.classLevel = permanent.classLevel;
|
this.classLevel = permanent.classLevel;
|
||||||
|
this.goadingPlayers.addAll(permanent.goadingPlayers);
|
||||||
this.pairedPermanent = permanent.pairedPermanent;
|
this.pairedPermanent = permanent.pairedPermanent;
|
||||||
this.bandedCards.addAll(permanent.bandedCards);
|
this.bandedCards.addAll(permanent.bandedCards);
|
||||||
this.timesLoyaltyUsed = permanent.timesLoyaltyUsed;
|
this.timesLoyaltyUsed = permanent.timesLoyaltyUsed;
|
||||||
|
@ -209,6 +211,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
this.minBlockedBy = 1;
|
this.minBlockedBy = 1;
|
||||||
this.maxBlockedBy = 0;
|
this.maxBlockedBy = 0;
|
||||||
this.copy = false;
|
this.copy = false;
|
||||||
|
this.goadingPlayers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1345,14 +1348,10 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
}
|
}
|
||||||
//20101001 - 508.1c
|
//20101001 - 508.1c
|
||||||
if (defenderId == null) {
|
if (defenderId == null) {
|
||||||
boolean oneCanBeAttacked = false;
|
if (game.getCombat()
|
||||||
for (UUID defenderToCheckId : game.getCombat().getDefenders()) {
|
.getDefenders()
|
||||||
if (canAttackCheckRestrictionEffects(defenderToCheckId, game)) {
|
.stream()
|
||||||
oneCanBeAttacked = true;
|
.noneMatch(defenderToCheckId -> canAttackCheckRestrictionEffects(defenderToCheckId, game))) {
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!oneCanBeAttacked) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!canAttackCheckRestrictionEffects(defenderId, game)) {
|
} else if (!canAttackCheckRestrictionEffects(defenderId, game)) {
|
||||||
|
@ -1582,6 +1581,16 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addGoadingPlayer(UUID playerId) {
|
||||||
|
this.goadingPlayers.add(playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<UUID> getGoadingPlayers() {
|
||||||
|
return goadingPlayers;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPairedCard(MageObjectReference pairedCard) {
|
public void setPairedCard(MageObjectReference pairedCard) {
|
||||||
this.pairedPermanent = pairedCard;
|
this.pairedPermanent = pairedCard;
|
||||||
|
|
|
@ -2625,10 +2625,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
Permanent attacker = game.getPermanent(attackerId);
|
Permanent attacker = game.getPermanent(attackerId);
|
||||||
if (attacker != null
|
if (attacker != null
|
||||||
&& attacker.canAttack(defenderId, game)
|
&& attacker.canAttack(defenderId, game)
|
||||||
&& attacker.isControlledBy(playerId)) {
|
&& attacker.isControlledBy(playerId)
|
||||||
if (!game.getCombat().declareAttacker(attackerId, defenderId, playerId, game)) {
|
&& !game.getCombat().declareAttacker(attackerId, defenderId, playerId, game)) {
|
||||||
game.undo(playerId);
|
game.undo(playerId);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ public class TargetDefender extends TargetImpl {
|
||||||
this.filter = new FilterPlaneswalkerOrPlayer(defenders);
|
this.filter = new FilterPlaneswalkerOrPlayer(defenders);
|
||||||
this.targetName = filter.getMessage();
|
this.targetName = filter.getMessage();
|
||||||
this.attackerId = attackerId;
|
this.attackerId = attackerId;
|
||||||
|
this.notTarget = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TargetDefender(final TargetDefender target) {
|
public TargetDefender(final TargetDefender target) {
|
||||||
|
|
|
@ -3,6 +3,8 @@ package mage.util;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by IGOUDT on 5-9-2016.
|
* Created by IGOUDT on 5-9-2016.
|
||||||
|
|
Loading…
Reference in a new issue