mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
Merge branch 'master' into subtypes
This commit is contained in:
commit
9e78410fff
12 changed files with 159 additions and 52 deletions
|
|
@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
|
|||
public final static int MAGE_VERSION_MAJOR = 1;
|
||||
public final static int MAGE_VERSION_MINOR = 4;
|
||||
public final static int MAGE_VERSION_PATCH = 23;
|
||||
public final static String MAGE_VERSION_MINOR_PATCH = "V5";
|
||||
public final static String MAGE_VERSION_MINOR_PATCH = "V6";
|
||||
public final static String MAGE_VERSION_INFO = "";
|
||||
|
||||
private final int major;
|
||||
|
|
|
|||
|
|
@ -727,7 +727,23 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
return target.isChosen();
|
||||
}
|
||||
|
||||
if (target.getOriginalTarget() instanceof TargetActivatedAbility) {
|
||||
List<StackObject> stackObjects = new ArrayList<>();
|
||||
for (UUID uuid : ((TargetActivatedAbility) target).possibleTargets(source.getSourceId(), source.getControllerId(), game)) {
|
||||
StackObject stackObject = game.getStack().getStackObject(uuid);
|
||||
if (stackObject != null) {
|
||||
stackObjects.add(stackObject);
|
||||
}
|
||||
}
|
||||
while (!target.isChosen() && !stackObjects.isEmpty()) {
|
||||
StackObject pick = stackObjects.get(0);
|
||||
if (pick != null) {
|
||||
target.addTarget(pick.getId(), source, game);
|
||||
stackObjects.remove(0);
|
||||
}
|
||||
}
|
||||
return target.isChosen();
|
||||
}
|
||||
throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ public final class SystemUtil {
|
|||
gameZone = Zone.LIBRARY;
|
||||
} else if ("token".equalsIgnoreCase(zone)) {
|
||||
gameZone = Zone.BATTLEFIELD;
|
||||
} else if ("emblem".equalsIgnoreCase(zone)) {
|
||||
gameZone = Zone.COMMAND;
|
||||
} else {
|
||||
continue; // go parse next line
|
||||
}
|
||||
|
|
@ -103,6 +105,17 @@ public final class SystemUtil {
|
|||
Object token = cons.newInstance();
|
||||
if (token != null && token instanceof mage.game.permanent.token.Token) {
|
||||
((mage.game.permanent.token.Token) token).putOntoBattlefield(amount, game, null, player.getId(), false, false);
|
||||
continue;
|
||||
}
|
||||
} else if ("emblem".equalsIgnoreCase(zone)) {
|
||||
// eg: emblem:Human:ElspethSunsChampionEmblem:1
|
||||
Class<?> c = Class.forName("mage.game.command.emblems." + cardName);
|
||||
Constructor<?> cons = c.getConstructor();
|
||||
Object emblem = cons.newInstance();
|
||||
if (emblem != null && emblem instanceof mage.game.command.Emblem) {
|
||||
((mage.game.command.Emblem) emblem).setControllerId(player.getId());
|
||||
game.addEmblem((mage.game.command.Emblem) emblem, null, player.getId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
logger.warn("Couldn't find a card: " + cardName);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
*/
|
||||
package mage.cards.b;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksOrBlocksTriggeredAbility;
|
||||
|
|
@ -39,6 +42,8 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.CardIdPredicate;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.filter.predicate.other.AuraCardCanAttachToPermanentId;
|
||||
|
|
@ -50,14 +55,13 @@ import mage.target.Target;
|
|||
import mage.target.TargetCard;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
/**
|
||||
* @author noxx
|
||||
*/
|
||||
public class BrunaLightOfAlabaster extends CardImpl {
|
||||
|
||||
public BrunaLightOfAlabaster(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}{U}");
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add("Angel");
|
||||
|
||||
|
|
@ -100,8 +104,8 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
UUID bruna = source.getSourceId();
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
|
||||
FilterPermanent filterAura = new FilterPermanent("Aura");
|
||||
FilterCard filterAuraCard = new FilterCard("Aura card");
|
||||
|
||||
|
|
@ -111,65 +115,86 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
|
|||
filterAuraCard.add(new CardTypePredicate(CardType.ENCHANTMENT));
|
||||
filterAuraCard.add(new SubtypePredicate(SubType.AURA));
|
||||
filterAuraCard.add(new AuraCardCanAttachToPermanentId(bruna));
|
||||
|
||||
if (player == null) {
|
||||
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (sourcePermanent == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int countBattlefield = game.getBattlefield().getAllActivePermanents(filterAura, game).size() - permanent.getAttachments().size();
|
||||
while (player.canRespond()
|
||||
List<Permanent> fromBattlefield = new ArrayList<>();
|
||||
List<Card> fromHandGraveyard = new ArrayList<>();
|
||||
|
||||
int countBattlefield = game.getBattlefield().getAllActivePermanents(filterAura, game).size() - sourcePermanent.getAttachments().size();
|
||||
while (controller.canRespond()
|
||||
&& countBattlefield > 0
|
||||
&& player.chooseUse(Outcome.Benefit, "Attach an Aura from the battlefield?", source, game)) {
|
||||
&& controller.chooseUse(Outcome.Benefit, "Attach an Aura from the battlefield?", source, game)) {
|
||||
Target targetAura = new TargetPermanent(filterAura);
|
||||
if (player.choose(Outcome.Benefit, targetAura, source.getSourceId(), game)) {
|
||||
if (controller.choose(Outcome.Benefit, targetAura, source.getSourceId(), game)) {
|
||||
Permanent aura = game.getPermanent(targetAura.getFirstTarget());
|
||||
if (aura != null) {
|
||||
Permanent attachedTo = game.getPermanent(aura.getAttachedTo());
|
||||
if (attachedTo != null) {
|
||||
attachedTo.removeAttachment(aura.getId(), game);
|
||||
Target target = aura.getSpellAbility().getTargets().get(0);
|
||||
if (target != null && target.canTarget(source.getSourceId(), source, game)) {
|
||||
fromBattlefield.add(aura);
|
||||
filterAura.add(Predicates.not(new CardIdPredicate(aura.getId())));
|
||||
}
|
||||
permanent.addAttachment(aura.getId(), game);
|
||||
}
|
||||
}
|
||||
countBattlefield = game.getBattlefield().getAllActivePermanents(filterAura, game).size() - permanent.getAttachments().size();
|
||||
countBattlefield = game.getBattlefield().getAllActivePermanents(filterAura, game).size() - sourcePermanent.getAttachments().size();
|
||||
}
|
||||
|
||||
int countHand = player.getHand().count(filterAuraCard, game);
|
||||
while (player.canRespond()
|
||||
&& countHand > 0
|
||||
&& player.chooseUse(Outcome.Benefit, "Attach an Aura from your hand?", source, game)) {
|
||||
int countHand = controller.getHand().count(filterAuraCard, game);
|
||||
while (controller.canRespond()
|
||||
&& countHand > 0
|
||||
&& controller.chooseUse(Outcome.Benefit, "Attach an Aura from your hand?", source, game)) {
|
||||
TargetCard targetAura = new TargetCard(Zone.HAND, filterAuraCard);
|
||||
if (player.choose(Outcome.Benefit, player.getHand(), targetAura, game)) {
|
||||
if (controller.choose(Outcome.Benefit, controller.getHand(), targetAura, game)) {
|
||||
Card aura = game.getCard(targetAura.getFirstTarget());
|
||||
if (aura != null) {
|
||||
game.getState().setValue("attachTo:" + aura.getId(), permanent);
|
||||
aura.putOntoBattlefield(game, Zone.HAND, source.getSourceId(), player.getId());
|
||||
permanent.addAttachment(aura.getId(), game);
|
||||
Target target = aura.getSpellAbility().getTargets().get(0);
|
||||
if (target != null && target.canTarget(source.getSourceId(), source, game)) {
|
||||
fromHandGraveyard.add(aura);
|
||||
filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId())));
|
||||
}
|
||||
}
|
||||
}
|
||||
countHand = player.getHand().count(filterAuraCard, game);
|
||||
countHand = controller.getHand().count(filterAuraCard, game);
|
||||
}
|
||||
|
||||
int countGraveyard = player.getGraveyard().count(filterAuraCard, game);
|
||||
while (player.canRespond()
|
||||
&& countGraveyard > 0
|
||||
&& player.chooseUse(Outcome.Benefit, "Attach an Aura from your graveyard?", source, game)) {
|
||||
int countGraveyard = controller.getGraveyard().count(filterAuraCard, game);
|
||||
while (controller.canRespond()
|
||||
&& countGraveyard > 0
|
||||
&& controller.chooseUse(Outcome.Benefit, "Attach an Aura from your graveyard?", source, game)) {
|
||||
TargetCard targetAura = new TargetCard(Zone.GRAVEYARD, filterAuraCard);
|
||||
if (player.choose(Outcome.Benefit, player.getGraveyard(), targetAura, game)) {
|
||||
if (controller.choose(Outcome.Benefit, controller.getGraveyard(), targetAura, game)) {
|
||||
Card aura = game.getCard(targetAura.getFirstTarget());
|
||||
if (aura != null) {
|
||||
game.getState().setValue("attachTo:" + aura.getId(), permanent);
|
||||
aura.putOntoBattlefield(game, Zone.GRAVEYARD, source.getSourceId(), player.getId());
|
||||
permanent.addAttachment(aura.getId(), game);
|
||||
Target target = aura.getSpellAbility().getTargets().get(0);
|
||||
if (target != null && target.canTarget(source.getSourceId(), source, game)) {
|
||||
fromHandGraveyard.add(aura);
|
||||
filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId())));
|
||||
}
|
||||
}
|
||||
}
|
||||
countGraveyard = player.getGraveyard().count(filterAuraCard, game);
|
||||
countGraveyard = controller.getGraveyard().count(filterAuraCard, game);
|
||||
}
|
||||
// Move permanents
|
||||
for (Permanent aura : fromBattlefield) {
|
||||
Permanent attachedTo = game.getPermanent(aura.getAttachedTo());
|
||||
if (attachedTo != null) {
|
||||
attachedTo.removeAttachment(aura.getId(), game);
|
||||
}
|
||||
sourcePermanent.addAttachment(aura.getId(), game);
|
||||
}
|
||||
// Move cards
|
||||
for (Card aura : fromHandGraveyard) {
|
||||
if (aura != null) {
|
||||
game.getState().setValue("attachTo:" + aura.getId(), sourcePermanent);
|
||||
controller.moveCards(aura, Zone.BATTLEFIELD, source, game);
|
||||
sourcePermanent.addAttachment(aura.getId(), game);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.CardImpl;
|
||||
|
|
@ -42,8 +43,6 @@ import mage.game.permanent.Permanent;
|
|||
import mage.players.Player;
|
||||
import mage.target.common.TargetNonlandPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
|
|
@ -51,7 +50,7 @@ import java.util.UUID;
|
|||
public class CompellingDeterrence extends CardImpl {
|
||||
|
||||
public CompellingDeterrence(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}");
|
||||
|
||||
// Return target nonland permanent to its owner's hand. Then that player discards a card if you control a Zombie.
|
||||
this.getSpellAbility().addEffect(new CompellingDeterrenceEffect());
|
||||
|
|
@ -91,6 +90,7 @@ class CompellingDeterrenceEffect extends OneShotEffect {
|
|||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null && player != null) {
|
||||
player.moveCards(target, Zone.HAND, source, game);
|
||||
game.applyEffects();
|
||||
FilterPermanent FILTER = new FilterPermanent();
|
||||
FILTER.add(new SubtypePredicate(SubType.ZOMBIE));
|
||||
if (game.getState().getBattlefield().countAll(FILTER, controller.getId(), game) > 0) {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.mageobject.NamePredicate;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.filter.predicate.permanent.TokenPredicate;
|
||||
import mage.game.permanent.token.ReflectionToken;
|
||||
|
|
@ -51,9 +50,12 @@ import mage.target.TargetPermanent;
|
|||
*/
|
||||
public class SpiritMirror extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filterToken = new FilterPermanent("Reflection", "Reflection token");
|
||||
private static final FilterPermanent filter = new FilterPermanent("Reflection");
|
||||
|
||||
static {
|
||||
filterToken.add(new SubtypePredicate(SubType.REFLECTION));
|
||||
filterToken.add(new TokenPredicate());
|
||||
filter.add(new SubtypePredicate(SubType.REFLECTION));
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +65,7 @@ public class SpiritMirror extends CardImpl {
|
|||
// At the beginning of your upkeep, if there are no Reflection tokens on the battlefield, create a 2/2 white Reflection creature token.
|
||||
this.addAbility(new ConditionalTriggeredAbility(
|
||||
new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new ReflectionToken()), TargetController.YOU, false),
|
||||
new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0, false),
|
||||
new PermanentsOnTheBattlefieldCondition(filterToken, ComparisonType.EQUAL_TO, 0, false),
|
||||
"At the beginning of your upkeep, if there are no Reflection tokens on the battlefield, create a 2/2 white Reflection creature token"));
|
||||
|
||||
// {0}: Destroy target Reflection.
|
||||
|
|
|
|||
|
|
@ -28,12 +28,12 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.constants.CardType;
|
||||
import mage.abilities.common.EntersBattlefieldTappedAbility;
|
||||
import mage.abilities.keyword.TransmuteAbility;
|
||||
import mage.abilities.mana.BlueManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -42,11 +42,11 @@ import mage.cards.CardSetInfo;
|
|||
public class TolariaWest extends CardImpl {
|
||||
|
||||
public TolariaWest(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
|
||||
|
||||
// Tolaria West enters the battlefield tapped.
|
||||
this.addAbility(new EntersBattlefieldTappedAbility());
|
||||
// {tap}: Add {U} to your mana pool.
|
||||
// {T}: Add {U} to your mana pool.
|
||||
this.addAbility(new BlueManaAbility());
|
||||
// Transmute {1}{U}{U}
|
||||
this.addAbility(new TransmuteAbility("{1}{U}{U}"));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.mage.test.cards.abilities.oneshot.counterspell;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CounterActivatedAbilityTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* The Card 'Sqelch' is bugged. In a game versus a human I tried to counter
|
||||
* a Toloria West activation as well as a Elspeth Sun's Champion activation
|
||||
* to make the game roll back to the begining of the turn and to show a pop
|
||||
* pup with an error message which I cannot post here due to forum
|
||||
* limitations.
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testSquelch() {
|
||||
// +1: Create three 1/1 white Soldier creature tokens.
|
||||
// -3: Destroy all creatures with power 4 or greater.
|
||||
// -7: You get an emblem with "Creatures you control get +2/+2 and have flying."
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Elspeth, Sun's Champion", 1);
|
||||
|
||||
// Counter target activated ability
|
||||
addCard(Zone.HAND, playerB, "Squelch", 1); // Instant {1}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Squelch");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerB, "Squelch", 1);
|
||||
assertPermanentCount(playerA, "Soldier", 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ public class CastOnlyDuringPhaseStepSourceEffect extends ContinuousRuleModifying
|
|||
return true;
|
||||
}
|
||||
}
|
||||
return false; // casr not prevented by this effect
|
||||
return false; // cast not prevented by this effect
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public enum CardRepository {
|
|||
// raise this if db structure was changed
|
||||
private static final long CARD_DB_VERSION = 51;
|
||||
// raise this if new cards were added to the server
|
||||
private static final long CARD_CONTENT_VERSION = 80;
|
||||
private static final long CARD_CONTENT_VERSION = 81;
|
||||
private final TreeSet<String> landTypes = new TreeSet<>();
|
||||
private Dao<CardInfo, Object> cardDao;
|
||||
private Set<String> classNames;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ public class ElspethSunsChampionEmblem extends Emblem {
|
|||
|
||||
public ElspethSunsChampionEmblem() {
|
||||
this.setName("Emblem Elspeth");
|
||||
this.setExpansionSetCodeForImage("THS");
|
||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new BoostControlledEffect(2, 2, Duration.EndOfGame, filter, false));
|
||||
ability.addEffect(new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.EndOfGame, filter));
|
||||
this.getAbilities().add(ability);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ public class TargetActivatedAbility extends TargetObject {
|
|||
}
|
||||
StackObject stackObject = game.getStack().getStackObject(id);
|
||||
return stackObject != null && stackObject.getStackAbility() != null && stackObject.getStackAbility().getAbilityType() == AbilityType.ACTIVATED
|
||||
&& filter.match(((ActivatedAbility) stackObject), game);
|
||||
&& filter.match(((ActivatedAbility) stackObject.getStackAbility()), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -104,7 +104,7 @@ public class TargetActivatedAbility extends TargetObject {
|
|||
for (StackObject stackObject : game.getStack()) {
|
||||
if (stackObject.getStackAbility().getAbilityType() == AbilityType.ACTIVATED
|
||||
&& game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getStackAbility().getControllerId())
|
||||
&& filter.match(((ActivatedAbility) stackObject), game)) {
|
||||
&& filter.match(((StackAbility) stackObject), game)) {
|
||||
possibleTargets.add(stackObject.getStackAbility().getId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue