Merge remote-tracking branch 'remotes/upstream/master'

This commit is contained in:
ciaccona007 2017-07-27 15:55:31 -04:00
commit b93fe24fde
10024 changed files with 44026 additions and 50188 deletions

View file

@ -30,9 +30,9 @@ package mage.abilities.common;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
@ -51,11 +51,11 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
protected boolean controller;
public AttacksAllTriggeredAbility(Effect effect, boolean optional) {
this(effect, optional, new FilterCreaturePermanent(), SetTargetPointer.NONE, false);
this(effect, optional, StaticFilters.FILTER_PERMANENT_CREATURE, SetTargetPointer.NONE, false);
}
public AttacksAllTriggeredAbility(Effect effect, boolean optional, boolean attacksYouOrYourPlaneswalker) {
this(effect, optional, new FilterCreaturePermanent(), SetTargetPointer.NONE, attacksYouOrYourPlaneswalker);
this(effect, optional, StaticFilters.FILTER_PERMANENT_CREATURE, SetTargetPointer.NONE, attacksYouOrYourPlaneswalker);
}
public AttacksAllTriggeredAbility(Effect effect, boolean optional, FilterCreaturePermanent filter, SetTargetPointer setTargetPointer, boolean attacksYouOrYourPlaneswalker) {

View file

@ -47,6 +47,10 @@ public class ControlsPermanentsControllerTriggeredAbility extends StateTriggered
protected final ComparisonType type;
protected final int value;
public ControlsPermanentsControllerTriggeredAbility(FilterPermanent filter, Effect effect){
this(filter, ComparisonType.MORE_THAN, 0, effect);
}
public ControlsPermanentsControllerTriggeredAbility(FilterPermanent filter, ComparisonType type, int value, Effect effect) {
super(Zone.BATTLEFIELD, effect);
this.filter = filter;

View file

@ -57,12 +57,20 @@ public class DiesTriggeredAbility extends ZoneChangeTriggeredAbility {
public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
// check it was previously on battlefield
Permanent before = ((ZoneChangeEvent) event).getTarget();
if (before == null) {
return false;
}
if (!(before instanceof PermanentToken) && !this.hasSourceObjectAbility(game, before, event)) {
return false;
}
// check now it is in graveyard
Zone after = game.getState().getZone(sourceId);
return before != null && after != null && Zone.GRAVEYARD.match(after);
if (before.getZoneChangeCounter(game) + 1 == game.getState().getZoneChangeCounter(source.getId())) {
Zone after = game.getState().getZone(sourceId);
return after != null && Zone.GRAVEYARD.match(after);
} else {
// Already moved to another zone, so guess it's ok
return true;
}
}
@Override

View file

@ -27,8 +27,13 @@
*/
package mage.abilities.effects;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import mage.MageObject;
import mage.abilities.*;
import mage.abilities.effects.common.continuous.CommanderReplacementEffect;
import mage.abilities.keyword.SpliceOntoArcaneAbility;
import mage.cards.Cards;
import mage.cards.CardsImpl;
@ -49,11 +54,6 @@ import mage.players.Player;
import mage.target.common.TargetCardInHand;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -85,7 +85,6 @@ public class ContinuousEffects implements Serializable {
// note all effect/abilities that were only added temporary
private final Map<ContinuousEffect, Set<Ability>> temporaryEffects = new HashMap<>();
public ContinuousEffects() {
applyCounters = new ApplyCountersEffect();
planeswalkerRedirectionEffect = new PlaneswalkerRedirectionEffect();
@ -241,7 +240,7 @@ public class ContinuousEffects implements Serializable {
}
private List<ContinuousEffect> filterLayeredEffects(List<ContinuousEffect> effects, Layer layer) {
return effects.stream().filter(effect->effect.hasLayer(layer)).collect(Collectors.toList());
return effects.stream().filter(effect -> effect.hasLayer(layer)).collect(Collectors.toList());
}
public Map<RequirementEffect, Set<Ability>> getApplicableRequirementEffects(Permanent permanent, Game game) {
@ -1254,7 +1253,9 @@ public class ContinuousEffects implements Serializable {
}
}
} else {
logger.warn("Ability without sourceId:" + ability.getRule());
if (!(effect instanceof CommanderReplacementEffect)) {
logger.warn("Ability without sourceId:" + ability.getRule());
}
}
}
}

View file

@ -32,6 +32,7 @@ import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -57,7 +58,7 @@ public class CopyPermanentEffect extends OneShotEffect {
}
public CopyPermanentEffect(ApplyToPermanent applier) {
this(new FilterCreaturePermanent(), applier);
this(StaticFilters.FILTER_PERMANENT_CREATURE, applier);
}
public CopyPermanentEffect(FilterPermanent filter) {

View file

@ -4,6 +4,7 @@
*/
package mage.abilities.effects.common;
import java.util.Objects;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
@ -19,8 +20,6 @@ import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player;
import java.util.Objects;
/**
*
* @author jeffwadsworth
@ -36,7 +35,7 @@ import java.util.Objects;
*/
public class EpicEffect extends OneShotEffect {
static final String rule = "<br>Epic <i>(For the rest of the game, you can't cast spells. At the beginning of each of your upkeeps for the rest of the game, copy this spell except for its epic ability. If the spell has targets, you may choose new targets for the copy)";
static final String rule = "<br>Epic <i>(For the rest of the game, you can't cast spells. At the beginning of each of your upkeeps for the rest of the game, copy this spell except for its epic ability. If the spell has targets, you may choose new targets for the copy)";
public EpicEffect() {
super(Outcome.Benefit);
@ -53,6 +52,9 @@ public class EpicEffect extends OneShotEffect {
if (controller != null) {
StackObject stackObject = game.getStack().getStackObject(source.getId());
Spell spell = (Spell) stackObject;
if (spell == null) {
return false;
}
spell = spell.copySpell(source.getControllerId());
// Remove Epic effect from the spell
Effect epicEffect = null;

View file

@ -68,7 +68,8 @@ public class PutTopCardOfLibraryIntoGraveTargetEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if (player != null) {
return player.moveCards(player.getLibrary().getTopCards(game, numberCards.calculate(game, source, this)), Zone.GRAVEYARD, source, game);
player.moveCards(player.getLibrary().getTopCards(game, numberCards.calculate(game, source, this)), Zone.GRAVEYARD, source, game);
return true;
}
return false;
}

View file

@ -74,14 +74,10 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
@Override
public boolean apply(Game game, Ability source) {
if (game.getState().getZone(source.getSourceId()) != Zone.GRAVEYARD) {
return false;
}
Card card = game.getCard(source.getSourceId());
if (card == null) {
return false;
}
Player player;
if (ownerControl) {
player = game.getPlayer(card.getOwnerId());
@ -91,7 +87,10 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
if (player == null) {
return false;
}
return player.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, true, null);
if (game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) {
player.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, true, null);
}
return true;
}
private void setText() {

View file

@ -27,11 +27,11 @@
*/
package mage.abilities.effects.common;
import mage.constants.Outcome;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
@ -45,25 +45,25 @@ import mage.util.CardUtil;
*
* @author maurer.it_at_gmail.com
*/
public class SacrificeEffect extends OneShotEffect{
public class SacrificeEffect extends OneShotEffect {
private FilterPermanent filter;
private String preText;
private DynamicValue count;
public SacrificeEffect (FilterPermanent filter, int count, String preText ) {
public SacrificeEffect(FilterPermanent filter, int count, String preText) {
this(filter, new StaticValue(count), preText);
}
public SacrificeEffect (FilterPermanent filter, DynamicValue count, String preText ) {
public SacrificeEffect(FilterPermanent filter, DynamicValue count, String preText) {
super(Outcome.Sacrifice);
this.filter = filter;
this.count = count;
this.preText = preText;
setText();
}
public SacrificeEffect (final SacrificeEffect effect ) {
public SacrificeEffect(final SacrificeEffect effect) {
super(effect);
this.filter = effect.filter;
this.count = effect.count;
@ -73,7 +73,6 @@ public class SacrificeEffect extends OneShotEffect{
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if (player == null) {
return false;
}
@ -87,24 +86,20 @@ public class SacrificeEffect extends OneShotEffect{
Target target = new TargetPermanent(amount, amount, newFilter, true);
// A spell or ability could have removed the only legal target this player
// had, if thats the case this ability should fizzle.
if (amount > 0 && target.canChoose(source.getSourceId(), player.getId(), game)) {
while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) {
player.chooseTarget(Outcome.Sacrifice, target, source, game);
}
for ( int idx = 0; idx < target.getTargets().size(); idx++) {
for (int idx = 0; idx < target.getTargets().size(); idx++) {
Permanent permanent = game.getPermanent(target.getTargets().get(idx));
if ( permanent != null ) {
if (permanent != null) {
permanent.sacrifice(source.getSourceId(), game);
}
}
return true;
}
return false;
return true;
}
public void setAmount(DynamicValue amount) {
@ -128,7 +123,7 @@ public class SacrificeEffect extends OneShotEffect{
sb.append("sacrifice ");
} else {
sb.append(" sacrifice ");
}
}
}
sb.append(CardUtil.numberToText(count.toString(), "a")).append(' ');
sb.append(filter.getMessage());

View file

@ -24,13 +24,12 @@
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
*/
package mage.abilities.effects.common;
import mage.constants.Outcome;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -41,22 +40,21 @@ import mage.game.permanent.Permanent;
public class UntapSourceEffect extends OneShotEffect {
public UntapSourceEffect() {
super(Outcome.Untap);
staticText = "untap {this}";
}
super(Outcome.Untap);
staticText = "untap {this}";
}
public UntapSourceEffect(final UntapSourceEffect effect) {
super(effect);
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
permanent.untap(game);
return true;
permanent.untap(game);
}
return false;
return true;
}
@Override
@ -64,4 +62,4 @@ public class UntapSourceEffect extends OneShotEffect {
return new UntapSourceEffect(this);
}
}
}

View file

@ -34,8 +34,7 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author JRHerlehy
* Created on 4/8/17.
* @author JRHerlehy Created on 4/8/17.
*/
public class BecomesBlackZombieAdditionEffect extends ContinuousEffectImpl {
@ -55,9 +54,14 @@ public class BecomesBlackZombieAdditionEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Permanent creature = game.getPermanent(source.getTargets().getFirstTarget());
if (creature == null) {
creature = game.getPermanentEntering(source.getTargets().getFirstTarget());
Permanent creature;
if (source.getTargets().getFirstTarget() == null) {
creature = game.getPermanent(getTargetPointer().getFirst(game, source));
} else {
creature = game.getPermanent(source.getTargets().getFirstTarget());
if (creature == null) {
creature = game.getPermanentEntering(source.getTargets().getFirstTarget());
}
}
if (creature != null) {
switch (layer) {

View file

@ -123,7 +123,7 @@ public class AddCountersTargetEffect extends OneShotEffect {
return true;
}
}
return affectedTargets > 0;
return true;
}
return false;
}

View file

@ -76,20 +76,19 @@ public class RemoveCounterTargetEffect extends OneShotEffect {
game.informPlayers("Removed " + toRemove.getCount() + ' ' + toRemove.getName()
+ " counter from " + p.getName());
}
return true;
}
} else {
Card c = game.getCard(targetPointer.getFirst(game, source));
if (c != null && counter != null && c.getCounters(game).getCount(counter.getName()) >= counter.getCount()) {
c.removeCounters(counter.getName(), counter.getCount(), game);
if (!game.isSimulation()) {
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(' ').append(counter.getName())
.append(" counter from ").append(c.getName())
.append(" (").append(c.getCounters(game).getCount(counter.getName())).append(" left)").toString());
}
}
}
Card c = game.getCard(targetPointer.getFirst(game, source));
if (c != null && counter != null && c.getCounters(game).getCount(counter.getName()) >= counter.getCount()) {
c.removeCounters(counter.getName(), counter.getCount(), game);
if (!game.isSimulation()) {
game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(' ').append(counter.getName())
.append(" counter from ").append(c.getName())
.append(" (").append(c.getCounters(game).getCount(counter.getName())).append(" left)").toString());
}
return true;
}
return false;
return true;
}
private Counter selectCounterType(Game game, Ability source, Permanent permanent) {

View file

@ -28,17 +28,17 @@
package mage.abilities.effects.keyword;
import mage.abilities.Ability;
import mage.constants.ComparisonType;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ToughnessPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -52,29 +52,29 @@ import mage.target.targetpointer.FixedTarget;
* @author LevelX2
*/
public class BolsterEffect extends OneShotEffect {
private final DynamicValue amount;
public BolsterEffect(int amount) {
this(new StaticValue(amount));
this(new StaticValue(amount));
}
public BolsterEffect(DynamicValue amount) {
super(Outcome.BoostCreature);
this.amount = amount;
this.staticText = setText();
}
public BolsterEffect(final BolsterEffect effect) {
super(effect);
this.amount = effect.amount;
}
@Override
public BolsterEffect copy() {
return new BolsterEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
@ -84,7 +84,7 @@ public class BolsterEffect extends OneShotEffect {
}
int leastToughness = Integer.MAX_VALUE;
Permanent selectedCreature = null;
for(Permanent permanent: game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), controller.getId(), game)) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game)) {
if (leastToughness > permanent.getToughness().getValue()) {
leastToughness = permanent.getToughness().getValue();
selectedCreature = permanent;
@ -97,7 +97,7 @@ public class BolsterEffect extends OneShotEffect {
if (selectedCreature == null) {
FilterPermanent filter = new FilterControlledCreaturePermanent("creature you control with toughness " + leastToughness);
filter.add(new ToughnessPredicate(ComparisonType.EQUAL_TO, leastToughness));
Target target = new TargetPermanent(1,1, filter, true);
Target target = new TargetPermanent(1, 1, filter, true);
if (controller.chooseTarget(outcome, target, source, game)) {
selectedCreature = game.getPermanent(target.getFirstTarget());
}
@ -106,7 +106,7 @@ public class BolsterEffect extends OneShotEffect {
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(amount.calculate(game, source, this)));
effect.setTargetPointer(new FixedTarget(selectedCreature.getId()));
return effect.apply(game, source);
}
}
}
return true;
}

View file

@ -30,7 +30,6 @@ package mage.abilities.keyword;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.constants.Zone;
@ -79,9 +78,9 @@ public class AnnihilatorAbility extends TriggeredAbilityImpl {
UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(sourceId, game);
if (defendingPlayerId != null) {
// the id has to be set here because the source can be leave battlefield
for (Effect effect : getEffects()) {
getEffects().forEach((effect) -> {
effect.setValue("defendingPlayerId", defendingPlayerId);
}
});
return true;
}
}
@ -125,19 +124,23 @@ class AnnihilatorEffect extends OneShotEffect {
}
if (player != null) {
int amount = Math.min(count, game.getBattlefield().countAll(FILTER, player.getId(), game));
Target target = new TargetControlledPermanent(amount, amount, FILTER, true);
if (target.canChoose(player.getId(), game)) {
while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) {
player.choose(Outcome.Sacrifice, target, source.getSourceId(), game);
}
for (int idx = 0; idx < target.getTargets().size(); idx++) {
Permanent permanent = game.getPermanent(target.getTargets().get(idx));
if (permanent != null) {
permanent.sacrifice(source.getSourceId(), game);
if (amount > 0) {
Target target = new TargetControlledPermanent(amount, amount, FILTER, true);
if (target.canChoose(player.getId(), game)) {
while (player.canRespond()
&& target.canChoose(player.getId(), game)
&& !target.isChosen()) {
player.choose(Outcome.Sacrifice, target, source.getSourceId(), game);
}
for (int idx = 0; idx < target.getTargets().size(); idx++) {
Permanent permanent = game.getPermanent(target.getTargets().get(idx));
if (permanent != null) {
permanent.sacrifice(source.getSourceId(), game);
}
}
}
return true;
}
return true;
}
return false;
}

View file

@ -29,18 +29,17 @@
package mage.abilities.keyword;
import mage.abilities.costs.mana.ManaCosts;
import mage.filter.common.FilterBasicLandCard;
import mage.filter.StaticFilters;
/**
*
* @author Loki
*/
public class BasicLandcyclingAbility extends CyclingAbility{
private static final FilterBasicLandCard filter = new FilterBasicLandCard();
private static final String text = "Basic landcycling";
public BasicLandcyclingAbility(ManaCosts costs) {
super(costs, filter, text);
super(costs, StaticFilters.FILTER_BASIC_LAND_CARD, text);
}
public BasicLandcyclingAbility(final BasicLandcyclingAbility ability) {

View file

@ -24,8 +24,7 @@
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
*/
package mage.abilities.keyword;
import java.util.UUID;
@ -36,6 +35,7 @@ import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.CostsImpl;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.constants.Zone;
@ -54,12 +54,25 @@ public class EchoAbility extends TriggeredAbilityImpl {
protected boolean echoPaid;
protected Costs<Cost> echoCosts = new CostsImpl<>();
private boolean manaEcho = true;
private DynamicValue amount;
private String rule;
public EchoAbility(String manaString) {
super(Zone.BATTLEFIELD, new EchoEffect(new ManaCostsImpl(manaString)), false);
this.echoPaid = false;
this.echoCosts.add(new ManaCostsImpl(manaString));
this.lastController = null;
this.rule = null;
}
public EchoAbility(DynamicValue amount, String rule) {
super(Zone.BATTLEFIELD, new EchoEffect(amount), false);
this.amount = amount;
this.echoPaid = false;
this.echoCosts.add(costs);
this.lastController = null;
this.manaEcho = true;
this.rule = rule;
}
public EchoAbility(Cost echoCost) {
@ -68,6 +81,7 @@ public class EchoAbility extends TriggeredAbilityImpl {
this.echoCosts.add(echoCost);
this.manaEcho = false;
this.lastController = null;
this.rule = null;
}
public EchoAbility(final EchoAbility ability) {
@ -76,6 +90,8 @@ public class EchoAbility extends TriggeredAbilityImpl {
this.echoCosts = ability.echoCosts.copy();
this.manaEcho = ability.manaEcho;
this.lastController = ability.lastController;
this.amount = ability.amount;
this.rule = ability.rule;
}
@Override
@ -85,7 +101,8 @@ public class EchoAbility extends TriggeredAbilityImpl {
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD || event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE;
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD
|| event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE;
}
@Override
@ -93,20 +110,21 @@ public class EchoAbility extends TriggeredAbilityImpl {
// reset the echo paid state back, if creature enteres the battlefield
if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD
&& event.getTargetId().equals(this.getSourceId())) {
this.echoPaid = false;
}
if (event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE) {
if(lastController != null){
if(!lastController.equals(this.controllerId)){
if (lastController != null) {
if (!lastController.equals(this.controllerId)) {
this.echoPaid = false;
}
}
// remember the last controller
lastController = this.getControllerId();
// if echo not paid yet, controller has to pay
if (event.getPlayerId().equals(this.controllerId) &&
lastController.equals(this.controllerId) && !this.echoPaid){
if (event.getPlayerId().equals(this.controllerId)
&& lastController.equals(this.controllerId)
&& !this.echoPaid) {
this.echoPaid = true;
return true;
}
@ -116,45 +134,66 @@ public class EchoAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
StringBuilder sb = new StringBuilder("Echo");
if (manaEcho) {
sb.append(' ');
StringBuilder sb = new StringBuilder();
if (rule != null) {
sb.append(rule);
} else {
sb.append("&mdash;");
sb = new StringBuilder("Echo");
if (manaEcho) {
sb.append(' ');
} else {
sb.append("&mdash;");
}
if (echoCosts != null) {
sb.append(echoCosts.getText());
}
}
sb.append(echoCosts.getText());
sb.append(" <i>(At the beginning of your upkeep, if this came under your control since the beginning of your last upkeep, sacrifice it unless you pay its echo cost.)</i>");
return sb.toString();
}
}
class EchoEffect extends OneShotEffect {
protected Cost cost;
protected DynamicValue amount;
public EchoEffect(Cost costs) {
super(Outcome.Sacrifice);
this.cost = costs;
}
this.amount = null;
}
public EchoEffect(DynamicValue amount) {
super(Outcome.Sacrifice);
this.amount = amount;
this.cost = null;
}
public EchoEffect(final EchoEffect effect) {
super(effect);
this.cost = effect.cost;
this.amount = effect.amount;
}
@Override
public boolean apply(Game game, Ability source) {
if (amount != null) {
cost = new ManaCostsImpl(Integer.toString(amount.calculate(game, source, this)));
}
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && source.getSourceObjectIfItStillExists(game) != null) {
if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() /* + " or sacrifice " + permanent.getName() */ + '?', source, game)) {
cost.clearPaid();
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) {
return true;
}
}
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
permanent.sacrifice(source.getSourceId(), game);
if (controller != null
&& source.getSourceObjectIfItStillExists(game) != null) {
if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + '?', source, game)) {
cost.clearPaid();
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) {
return true;
}
}
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
permanent.sacrifice(source.getSourceId(), game);
}
return true;
}
return false;
@ -167,17 +206,16 @@ class EchoEffect extends OneShotEffect {
@Override
public String getText(Mode mode) {
StringBuilder sb = new StringBuilder("sacrifice {this} unless you ");
String costText = cost.getText();
if (costText.toLowerCase().startsWith("discard")) {
sb.append(costText.substring(0, 1).toLowerCase());
sb.append(costText.substring(1));
}
else {
sb.append("pay ").append(costText);
}
StringBuilder sb = new StringBuilder("sacrifice {this} unless you ");
String costText = cost.getText();
if (costText.toLowerCase().startsWith("discard")) {
sb.append(costText.substring(0, 1).toLowerCase());
sb.append(costText.substring(1));
} else {
sb.append("pay ").append(costText);
}
return sb.toString();
return sb.toString();
}
}

View file

@ -27,6 +27,7 @@
*/
package mage.abilities.keyword;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.costs.Cost;
@ -48,8 +49,6 @@ import mage.game.events.ZoneChangeEvent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
* 702.32. Flashback
*
@ -232,12 +231,10 @@ class FlashbackEffect extends OneShotEffect {
ContinuousEffect effect = new FlashbackReplacementEffect();
effect.setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId())));
game.addEffect(effect, source);
return true;
}
return false;
return true;
}
}
return false;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* Copyright 20 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@ -53,7 +53,11 @@ import mage.players.Player;
public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl {
public AnyColorLandsProduceManaAbility(TargetController targetController) {
super(Zone.BATTLEFIELD, new AnyColorLandsProduceManaEffect(targetController), new TapSourceCost());
this(targetController, true);
}
public AnyColorLandsProduceManaAbility(TargetController targetController, boolean onlyColors) {
super(Zone.BATTLEFIELD, new AnyColorLandsProduceManaEffect(targetController, onlyColors), new TapSourceCost());
}
public AnyColorLandsProduceManaAbility(final AnyColorLandsProduceManaAbility ability) {
@ -80,18 +84,23 @@ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl {
class AnyColorLandsProduceManaEffect extends ManaEffect {
private final FilterPermanent filter;
private final boolean onlyColors; // false if mana types can be produced (also Colorless mana), if false only colors can be produced (no Colorless mana).
public AnyColorLandsProduceManaEffect(TargetController targetController) {
private boolean inManaTypeCalculation = false;
public AnyColorLandsProduceManaEffect(TargetController targetController, boolean onlyColors) {
super();
filter = new FilterLandPermanent();
this.onlyColors = onlyColors;
filter.add(new ControllerPredicate(targetController));
String text = targetController == TargetController.OPPONENT ? "an opponent controls" : "you control";
staticText = "Add to your mana pool one mana of any color that a land " + text + " could produce";
staticText = "Add to your mana pool one mana of any " + (this.onlyColors ? "color" : "type") + " that a land " + text + " could produce";
}
public AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) {
super(effect);
this.filter = effect.filter.copy();
this.onlyColors = effect.onlyColors;
}
@Override
@ -115,12 +124,19 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
if (types.getWhite() > 0) {
choice.getChoices().add("White");
}
if (!onlyColors && types.getColorless() > 0) {
choice.getChoices().add("Colorless");
}
if (types.getAny() > 0) {
choice.getChoices().add("Black");
choice.getChoices().add("Red");
choice.getChoices().add("Blue");
choice.getChoices().add("Green");
choice.getChoices().add("White");
if (!onlyColors) {
choice.getChoices().add("Colorless");
}
}
if (!choice.getChoices().isEmpty()) {
Player player = game.getPlayer(source.getControllerId());
@ -147,6 +163,9 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
case "White":
mana.setWhite(1);
break;
case "Colorless":
mana.setColorless(1);
break;
}
checkToFirePossibleEvents(mana, game, source);
player.getManaPool().addMana(mana, game, source);
@ -161,9 +180,16 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
}
private Mana getManaTypes(Game game, Ability source) {
Mana types = new Mana();
if (game == null || game.getPhase() == null) {
return types;
}
if (inManaTypeCalculation) {
return types;
}
inManaTypeCalculation = true;
// Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "needed to identify endless loop causing cards: {0}", source.getSourceObject(game).getName());
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
Mana types = new Mana();
for (Permanent land : lands) {
Abilities<ActivatedManaAbilityImpl> mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
for (ActivatedManaAbilityImpl ability : mana) {
@ -174,6 +200,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
}
}
}
inManaTypeCalculation = false;
return types;
}

View file

@ -1,18 +1,15 @@
package mage.constants;
import mage.util.SubTypeList;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import mage.util.SubTypeList;
public enum SubType {
//205.3k Instants and sorceries share their lists of subtypes; these subtypes are called spell types.
ARCANE("Arcane", SubTypeSet.SpellType, false),
TRAP("Trap", SubTypeSet.SpellType, false),
// 205.3i: Lands have their own unique set of subtypes; these subtypes are called land types.
// Of that list, Forest, Island, Mountain, Plains, and Swamp are the basic land types.
FOREST("Forest", SubTypeSet.BasicLandType, false),
@ -28,27 +25,25 @@ public enum SubType {
MINE("Mine", SubTypeSet.NonBasicLandType, false),
POWER_PLANT("Power-Plant", SubTypeSet.NonBasicLandType, false),
TOWER("Tower", SubTypeSet.NonBasicLandType, false),
// 205.3h Enchantments have their own unique set of subtypes; these subtypes are called enchantment types.
AURA("Aura", SubTypeSet.EnchantmentType, false),
CARTOUCHE("Cartouche", SubTypeSet.EnchantmentType, false),
CURSE("Curse", SubTypeSet.EnchantmentType, false),
SHRINE("Shrine", SubTypeSet.EnchantmentType, false),
// 205.3g: Artifacts have their own unique set of subtypes; these subtypes are called artifact types.
CLUE("Clue", SubTypeSet.ArtifactType, false),
CONTRAPTION("Contraption", SubTypeSet.ArtifactType, false),
EQUIPMENT("Equipment", SubTypeSet.ArtifactType, false),
FORTIFICATION("Fortification", SubTypeSet.ArtifactType, false),
VEHICLE("Vehicle", SubTypeSet.ArtifactType, false),
// 205.3m : Creatures and tribals share their lists of subtypes; these subtypes are called creature types.
// A
ADVISOR("Advisor", SubTypeSet.CreatureType, false),
AETHERBORN("Aetherborn", SubTypeSet.CreatureType, false),
ALLY("Ally", SubTypeSet.CreatureType, false),
ANGEL("Angel", SubTypeSet.CreatureType, false),
ANTELOPE("Antelope", SubTypeSet.CreatureType, false),
AQUALISH("Aqualish", SubTypeSet.CreatureType, true), // Star Wars
AQUALISH("Aqualish", SubTypeSet.CreatureType, true), // Star Wars
APE("Ape", SubTypeSet.CreatureType, false),
ARCONA("Arcona", SubTypeSet.CreatureType, true),
ARCHER("Archer", SubTypeSet.CreatureType, false),
@ -61,7 +56,7 @@ public enum SubType {
ATAT("AT-AT", SubTypeSet.CreatureType, true),
AUROCHS("Aurochs", SubTypeSet.CreatureType, false),
AVATAR("Avatar", SubTypeSet.CreatureType, false),
// B
BADGER("Badger", SubTypeSet.CreatureType, false),
BARBARIAN("Barbarian", SubTypeSet.CreatureType, false),
BASILISK("Basilisk", SubTypeSet.CreatureType, false),
@ -71,20 +66,20 @@ public enum SubType {
BEEBLE("Beeble", SubTypeSet.CreatureType, false),
BERSERKER("Berserker", SubTypeSet.CreatureType, false),
BIRD("Bird", SubTypeSet.CreatureType, false),
BITH("Bith", SubTypeSet.CreatureType, true), // Star Wars
BITH("Bith", SubTypeSet.CreatureType, true), // Star Wars
BLINKMOTH("Blinkmoth", SubTypeSet.CreatureType, false),
BOAR("Boar", SubTypeSet.CreatureType, false),
BRINGER("Bringer", SubTypeSet.CreatureType, false),
BRUSHWAGG("Brushwagg", SubTypeSet.CreatureType, false),
CALAMARI("Calamari", SubTypeSet.CreatureType, true), // Star Wars
// C
CALAMARI("Calamari", SubTypeSet.CreatureType, true), // Star Wars
CAMARID("Camarid", SubTypeSet.CreatureType, false),
CAMEL("Camel", SubTypeSet.CreatureType, false),
CARIBOU("Caribou", SubTypeSet.CreatureType, false),
CARRIER("Carrier", SubTypeSet.CreatureType, false),
CAT("Cat", SubTypeSet.CreatureType, false),
CENTAUR("Centaur", SubTypeSet.CreatureType, false),
CEREAN("Cerean", SubTypeSet.CreatureType, true), // Star Wars
CEREAN("Cerean", SubTypeSet.CreatureType, true), // Star Wars
CEPHALID("Cephalid", SubTypeSet.CreatureType, false),
CHIMERA("Chimera", SubTypeSet.CreatureType, false),
CHISS("Chiss", SubTypeSet.CreatureType, true),
@ -95,10 +90,10 @@ public enum SubType {
COWARD("Coward", SubTypeSet.CreatureType, false),
CRAB("Crab", SubTypeSet.CreatureType, false),
CROCODILE("Crocodile", SubTypeSet.CreatureType, false),
CYBORG("Cyborg", SubTypeSet.CreatureType, true), // Star Wars
CYBORG("Cyborg", SubTypeSet.CreatureType, true), // Star Wars
CYCLOPS("Cyclops", SubTypeSet.CreatureType, false),
DATHOMIRIAN("Dathomirian", SubTypeSet.CreatureType, true), // Star Wars
// D
DATHOMIRIAN("Dathomirian", SubTypeSet.CreatureType, true), // Star Wars
DAUTHI("Dauthi", SubTypeSet.CreatureType, false),
DEMON("Demon", SubTypeSet.CreatureType, false),
DESERTER("Deserter", SubTypeSet.CreatureType, false),
@ -109,10 +104,10 @@ public enum SubType {
DREADNOUGHT("Dreadnought", SubTypeSet.CreatureType, false),
DRONE("Drone", SubTypeSet.CreatureType, false),
DRUID("Druid", SubTypeSet.CreatureType, false),
DROID("Droid", SubTypeSet.CreatureType, true), // Star Wars
DROID("Droid", SubTypeSet.CreatureType, true), // Star Wars
DRYAD("Dryad", SubTypeSet.CreatureType, false),
DWARF("Dwarf", SubTypeSet.CreatureType, false),
// E
EFREET("Efreet", SubTypeSet.CreatureType, false),
ELDER("Elder", SubTypeSet.CreatureType, false),
ELDRAZI("Eldrazi", SubTypeSet.CreatureType, false),
@ -121,8 +116,8 @@ public enum SubType {
ELF("Elf", SubTypeSet.CreatureType, false),
ELK("Elk", SubTypeSet.CreatureType, false),
EYE("Eye", SubTypeSet.CreatureType, false),
EWOK("Ewok", SubTypeSet.CreatureType, true), // Star Wars
EWOK("Ewok", SubTypeSet.CreatureType, true), // Star Wars
// F
FAERIE("Faerie", SubTypeSet.CreatureType, false),
FERRET("Ferret", SubTypeSet.CreatureType, false),
FISH("Fish", SubTypeSet.CreatureType, false),
@ -130,9 +125,9 @@ public enum SubType {
FOX("Fox", SubTypeSet.CreatureType, false),
FROG("Frog", SubTypeSet.CreatureType, false),
FUNGUS("Fungus", SubTypeSet.CreatureType, false),
GAMORREAN("Gamorrean", SubTypeSet.CreatureType, true), // Star Wars
GAND("Gand", SubTypeSet.CreatureType, true), // Star Wars
// G
GAMORREAN("Gamorrean", SubTypeSet.CreatureType, true), // Star Wars
GAND("Gand", SubTypeSet.CreatureType, true), // Star Wars
GARGOYLE("Gargoyle", SubTypeSet.CreatureType, false),
GERM("Germ", SubTypeSet.CreatureType, false),
GIANT("Giant", SubTypeSet.CreatureType, false),
@ -145,8 +140,8 @@ public enum SubType {
GRAVEBORN("Graveborn", SubTypeSet.CreatureType, false),
GREMLIN("Gremlin", SubTypeSet.CreatureType, false),
GRIFFIN("Griffin", SubTypeSet.CreatureType, false),
GUNGAN("Gungan", SubTypeSet.CreatureType, true), // Star Wars
GUNGAN("Gungan", SubTypeSet.CreatureType, true), // Star Wars
// H
HAG("Hag", SubTypeSet.CreatureType, false),
HARPY("Harpy", SubTypeSet.CreatureType, false),
HELLION("Hellion", SubTypeSet.CreatureType, false),
@ -159,23 +154,23 @@ public enum SubType {
HOUND("Hound", SubTypeSet.CreatureType, false),
HUMAN("Human", SubTypeSet.CreatureType, false),
HUNTER("Hunter", SubTypeSet.CreatureType, false),
HUTT("Hutt", SubTypeSet.CreatureType, true), // Star Wars
HUTT("Hutt", SubTypeSet.CreatureType, true), // Star Wars
HYDRA("Hydra", SubTypeSet.CreatureType, false),
HYENA("Hyena", SubTypeSet.CreatureType, false),
// I
ILLUSION("Illusion", SubTypeSet.CreatureType, false),
IMP("Imp", SubTypeSet.CreatureType, false),
INCARNATION("Incarnation", SubTypeSet.CreatureType, false),
INSECT("Insect", SubTypeSet.CreatureType, false),
ITHORIAN("Ithorian", SubTypeSet.CreatureType, true), // Star Wars
ITHORIAN("Ithorian", SubTypeSet.CreatureType, true), // Star Wars
// J
JACKAL("Jackal", SubTypeSet.CreatureType, false),
JAWA("Jawa", SubTypeSet.CreatureType, true),
JEDI("Jedi", SubTypeSet.CreatureType, true), // Star Wars
JEDI("Jedi", SubTypeSet.CreatureType, true), // Star Wars
JELLYFISH("Jellyfish", SubTypeSet.CreatureType, false),
JUGGERNAUT("Juggernaut", SubTypeSet.CreatureType, false),
KALEESH("Kaleesh", SubTypeSet.CreatureType, true), // Star Wars
// K
KALEESH("Kaleesh", SubTypeSet.CreatureType, true), // Star Wars
KAVU("Kavu", SubTypeSet.CreatureType, false),
KELDOR("KelDor", SubTypeSet.CreatureType, true),
KIRIN("Kirin", SubTypeSet.CreatureType, false),
@ -185,7 +180,7 @@ public enum SubType {
KOORIVAR("Koorivar", SubTypeSet.CreatureType, true),
KOR("Kor", SubTypeSet.CreatureType, false),
KRAKEN("Kraken", SubTypeSet.CreatureType, false),
// L
LAMIA("Lamia", SubTypeSet.CreatureType, false),
LAMMASU("Lammasu", SubTypeSet.CreatureType, false),
LEECH("Leech", SubTypeSet.CreatureType, false),
@ -193,9 +188,8 @@ public enum SubType {
LHURGOYF("Lhurgoyf", SubTypeSet.CreatureType, false),
LICID("Licid", SubTypeSet.CreatureType, false),
LIZARD("Lizard", SubTypeSet.CreatureType, false),
MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
// M
MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
MANTICORE("Manticore", SubTypeSet.CreatureType, false),
MASTICORE("Masticore", SubTypeSet.CreatureType, false),
MERCENARY("Mercenary", SubTypeSet.CreatureType, false),
@ -203,7 +197,7 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
METATHRAN("Metathran", SubTypeSet.CreatureType, false),
MINION("Minion", SubTypeSet.CreatureType, false),
MINOTAUR("Minotaur", SubTypeSet.CreatureType, false),
MIRIALAN("Mirialan", SubTypeSet.CreatureType, true), // Star Wars
MIRIALAN("Mirialan", SubTypeSet.CreatureType, true), // Star Wars
MOLE("Mole", SubTypeSet.CreatureType, false),
MONGER("Monger", SubTypeSet.CreatureType, false),
MONGOOSE("Mongoose", SubTypeSet.CreatureType, false),
@ -213,12 +207,11 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
MUTANT("Mutant", SubTypeSet.CreatureType, false),
MYR("Myr", SubTypeSet.CreatureType, false),
MYSTIC("Mystic", SubTypeSet.CreatureType, false),
// N
NAGA("Naga", SubTypeSet.CreatureType, false),
NAUTILUS("Nautilus", SubTypeSet.CreatureType, false),
NAUTOLAN("Nautolan", SubTypeSet.CreatureType, true), // Star Wars
NEIMOIDIAN("Neimoidian", SubTypeSet.CreatureType, true), // Star Wars
NAUTOLAN("Nautolan", SubTypeSet.CreatureType, true), // Star Wars
NEIMOIDIAN("Neimoidian", SubTypeSet.CreatureType, true), // Star Wars
NEPHILIM("Nephilim", SubTypeSet.CreatureType, false),
NIGHTMARE("Nightmare", SubTypeSet.CreatureType, false),
NIGHTSTALKER("Nightstalker", SubTypeSet.CreatureType, false),
@ -226,7 +219,7 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
NOGGLE("Noggle", SubTypeSet.CreatureType, false),
NOMAD("Nomad", SubTypeSet.CreatureType, false),
NYMPH("Nymph", SubTypeSet.CreatureType, false),
// O
OCTOPUS("Octopus", SubTypeSet.CreatureType, false),
OGRE("Ogre", SubTypeSet.CreatureType, false),
OOZE("Ooze", SubTypeSet.CreatureType, false),
@ -237,7 +230,7 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
OUPHE("Ouphe", SubTypeSet.CreatureType, false),
OX("Ox", SubTypeSet.CreatureType, false),
OYSTER("Oyster", SubTypeSet.CreatureType, false),
// P
PEGASUS("Pegasus", SubTypeSet.CreatureType, false),
PENTAVITE("Pentavite", SubTypeSet.CreatureType, false),
PEST("Pest", SubTypeSet.CreatureType, false),
@ -251,19 +244,18 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
PRISM("Prism", SubTypeSet.CreatureType, false),
PROCESSOR("Processor", SubTypeSet.CreatureType, false),
PUREBLOOD("Pureblood", SubTypeSet.CreatureType, true),
QUARREN("Quarren", SubTypeSet.CreatureType, true), // Star Wars
// Q
QUARREN("Quarren", SubTypeSet.CreatureType, true), // Star Wars
// R
RABBIT("Rabbit", SubTypeSet.CreatureType, false),
RAT("Rat", SubTypeSet.CreatureType, false),
REBEL("Rebel", SubTypeSet.CreatureType, false),
REFLECTION("Reflection", SubTypeSet.CreatureType, false),
RHINO("Rhino", SubTypeSet.CreatureType, false),
RIGGER("Rigger", SubTypeSet.CreatureType, false),
RODIAN("Rodian", SubTypeSet.CreatureType, true), // Star Wars
RODIAN("Rodian", SubTypeSet.CreatureType, true), // Star Wars
ROGUE("Rogue", SubTypeSet.CreatureType, false),
// S
SABLE("Sable", SubTypeSet.CreatureType, false),
SALAMANDER("Salamander", SubTypeSet.CreatureType, false),
SAMURAI("Samurai", SubTypeSet.CreatureType, false),
@ -302,31 +294,32 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
SQUID("Squid", SubTypeSet.CreatureType, false),
SQUIRREL("Squirrel", SubTypeSet.CreatureType, false),
STARFISH("Starfish", SubTypeSet.CreatureType, false),
STARSHIP("Starship", SubTypeSet.CreatureType, true), // Star Wars
SULLUSTAN("Sullustan", SubTypeSet.CreatureType, true), // Star Wars
STARSHIP("Starship", SubTypeSet.CreatureType, true), // Star Wars
SULLUSTAN("Sullustan", SubTypeSet.CreatureType, true), // Star Wars
SURRAKAR("Surrakar", SubTypeSet.CreatureType, false),
SURVIVOR("Survivor", SubTypeSet.CreatureType, false),
// T
TETRAVITE("Tetravite", SubTypeSet.CreatureType, false),
THALAKOS("Thalakos", SubTypeSet.CreatureType, false),
THOPTER("Thopter", SubTypeSet.CreatureType, false),
TRANDOSHAN("Trandoshan", SubTypeSet.CreatureType, true), // Star Wars
TRANDOSHAN("Trandoshan", SubTypeSet.CreatureType, true), // Star Wars
THRULL("Thrull", SubTypeSet.CreatureType, false),
TREEFOLK("Treefolk", SubTypeSet.CreatureType, false),
TRISKELAVITE("Triskelavite", SubTypeSet.CreatureType, false),
TROLL("Troll", SubTypeSet.CreatureType, false),
TURTLE("Turtle", SubTypeSet.CreatureType, false),
TROOPER("Trooper", SubTypeSet.CreatureType, true), // Star Wars
TWILEK("Twi'lek", SubTypeSet.CreatureType, true), // Star Wars
TROOPER("Trooper", SubTypeSet.CreatureType, true), // Star Wars
TWILEK("Twi'lek", SubTypeSet.CreatureType, true), // Star Wars
UGNAUGHT("Ugnaught",SubTypeSet.CreatureType, true),
// U
UGNAUGHT("Ugnaught", SubTypeSet.CreatureType, true),
UNICORN("Unicorn", SubTypeSet.CreatureType, false),
//V
VAMPIRE("Vampire", SubTypeSet.CreatureType, false),
VEDALKEN("Vedalken", SubTypeSet.CreatureType, false),
VIASHINO("Viashino", SubTypeSet.CreatureType, false),
VOLVER("Volver", SubTypeSet.CreatureType, false),
//W
WALL("Wall", SubTypeSet.CreatureType, false),
WARRIOR("Warrior", SubTypeSet.CreatureType, false),
WEEQUAY("Weequay", SubTypeSet.CreatureType, true),
@ -337,27 +330,27 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
WOLF("Wolf", SubTypeSet.CreatureType, false),
WOLVERINE("Wolverine", SubTypeSet.CreatureType, false),
WOMBAT("Wombat", SubTypeSet.CreatureType, false),
WOOKIEE("Wookiee", SubTypeSet.CreatureType, true), // Star Wars
WOOKIEE("Wookiee", SubTypeSet.CreatureType, true), // Star Wars
WORM("Worm", SubTypeSet.CreatureType, false),
WRAITH("Wraith", SubTypeSet.CreatureType, false),
WURM("Wurm", SubTypeSet.CreatureType, false),
// Y
YETI("Yeti", SubTypeSet.CreatureType, false),
ZABRAK("Zabrak", SubTypeSet.CreatureType, true), // Star Wars
// Z
ZABRAK("Zabrak", SubTypeSet.CreatureType, true), // Star Wars
ZOMBIE("Zombie", SubTypeSet.CreatureType, false),
ZUBERA("Zubera", SubTypeSet.CreatureType, false),
// Planeswalker
AJANI("Ajani", SubTypeSet.PlaneswalkerType, false),
ARLINN("Arlinn", SubTypeSet.PlaneswalkerType, false),
ASHIOK("Ashiok", SubTypeSet.PlaneswalkerType, false),
AURRA("Aurra", SubTypeSet.PlaneswalkerType, true), // Star Wars
AURRA("Aurra", SubTypeSet.PlaneswalkerType, true), // Star Wars
BOLAS("Bolas", SubTypeSet.PlaneswalkerType, false),
CHANDRA("Chandra", SubTypeSet.PlaneswalkerType, false),
DACK("Dack", SubTypeSet.PlaneswalkerType, false),
DARETTI("Daretti", SubTypeSet.PlaneswalkerType, false),
DOMRI("Domri", SubTypeSet.PlaneswalkerType, false),
DOOKU("Dooku", SubTypeSet.PlaneswalkerType, true), // Star Wars
DOOKU("Dooku", SubTypeSet.PlaneswalkerType, true), // Star Wars
DOVIN("Dovin", SubTypeSet.PlaneswalkerType, false),
ELSPETH("Elspeth", SubTypeSet.PlaneswalkerType, false),
FREYALISE("Freyalise", SubTypeSet.PlaneswalkerType, false),
@ -373,12 +366,12 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
NARSET("Narset", SubTypeSet.PlaneswalkerType, false),
NISSA("Nissa", SubTypeSet.PlaneswalkerType, false),
NIXILIS("Nixilis", SubTypeSet.PlaneswalkerType, false),
OBI_WAN("Obi-Wan", SubTypeSet.PlaneswalkerType, true), // Star Wars
OBI_WAN("Obi-Wan", SubTypeSet.PlaneswalkerType, true), // Star Wars
RAL("Ral", SubTypeSet.PlaneswalkerType, false),
SAHEELI("Saheeli", SubTypeSet.PlaneswalkerType, false),
SAMUT("Samut", SubTypeSet.PlaneswalkerType, false),
SARKHAN("Sarkhan", SubTypeSet.PlaneswalkerType, false),
SIDIOUS("Sidious", SubTypeSet.PlaneswalkerType, true), // Star Wars
SIDIOUS("Sidious", SubTypeSet.PlaneswalkerType, true), // Star Wars
SORIN("Sorin", SubTypeSet.PlaneswalkerType, false),
TAMIYO("Tamiyo", SubTypeSet.PlaneswalkerType, false),
TEFERI("Teferi", SubTypeSet.PlaneswalkerType, false),
@ -388,7 +381,7 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
VENSER("Venser", SubTypeSet.PlaneswalkerType, false),
VRASKA("Vraska", SubTypeSet.PlaneswalkerType, false),
XENAGOS("Xenagos", SubTypeSet.PlaneswalkerType, false),
YODA("Yoda", SubTypeSet.PlaneswalkerType, true);
YODA("Yoda", SubTypeSet.PlaneswalkerType, true); // Star Wars
private final SubTypeSet subTypeSet;
@ -448,4 +441,3 @@ MANTELLIAN("Mantellian", SubTypeSet.CreatureType, true), // Star Wars
return landTypes;
}
}

View file

@ -22,6 +22,8 @@ public final class StaticFilters {
public static final FilterSpiritOrArcaneCard SPIRIT_OR_ARCANE_CARD = new FilterSpiritOrArcaneCard();
public static final FilterArtifactOrEnchantmentPermanent ARTIFACT_OR_ENCHANTMENT_PERMANENT = new FilterArtifactOrEnchantmentPermanent();
public static final FilterEnchantmentPermanent FILTER_ENCHANTMENT_PERMANENT = new FilterEnchantmentPermanent();
public static final FilterArtifactCard FILTER_CARD_ARTIFACT = new FilterArtifactCard();
public static final FilterNonlandCard FILTER_CARD_NON_LAND = new FilterNonlandCard();
@ -40,7 +42,7 @@ public final class StaticFilters {
public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_NON_LAND = new FilterControlledPermanent("nonland permanent");
public static final FilterLandPermanent FILTER_LAND = new FilterLandPermanent();
public static final FilterLandPermanent FILTER_LANDS = new FilterLandPermanent("lands");
public static final FilterLandPermanent FILTER_BASIC_LAND = new FilterLandPermanent();
public static final FilterBasicLandCard FILTER_BASIC_LAND_CARD = new FilterBasicLandCard();
public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE = new FilterCreaturePermanent();
public static final FilterCreaturePermanent FILTER_PERMANENT_A_CREATURE = new FilterCreaturePermanent("a creature");

View file

@ -27,6 +27,8 @@
*/
package mage.game;
import java.io.Serializable;
import java.util.*;
import mage.cards.decks.DeckValidator;
import mage.constants.TableState;
import mage.game.events.Listener;
@ -38,9 +40,6 @@ import mage.game.tournament.Tournament;
import mage.players.Player;
import mage.players.PlayerType;
import java.io.Serializable;
import java.util.*;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -65,6 +64,7 @@ public class Table implements Serializable {
@FunctionalInterface
public interface TableRecorder {
void record(Table table);
}

View file

@ -27,6 +27,8 @@
*/
package mage.game.combat;
import java.io.Serializable;
import java.util.*;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.RequirementEffect;
@ -34,6 +36,7 @@ import mage.abilities.effects.RestrictionEffect;
import mage.abilities.keyword.VigilanceAbility;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreatureForCombatBlock;
import mage.filter.common.FilterCreaturePermanent;
@ -50,9 +53,6 @@ import mage.util.Copyable;
import mage.util.trace.TraceUtil;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -1212,7 +1212,7 @@ public class Combat implements Serializable, Copyable<Combat> {
}
}
// reset the removeFromCombat flag on all creatures on the battlefield
for (Permanent creaturePermanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), game)) {
for (Permanent creaturePermanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, game)) {
creaturePermanent.setRemovedFromCombat(false);
}
clear();

View file

@ -32,7 +32,7 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.common.SacrificeEffect;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.StaticFilters;
import mage.game.command.Emblem;
/**
@ -45,10 +45,9 @@ public class SorinSolemnVisitorEmblem extends Emblem {
* Emblem: "At the beginning of each opponent's upkeep, that player
* sacrifices a creature."
*/
public SorinSolemnVisitorEmblem() {
this.setName("Emblem Sorin");
Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.COMMAND, new SacrificeEffect(new FilterCreaturePermanent(), 1, "that player"), TargetController.OPPONENT, false, true);
Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.COMMAND, new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "that player"), TargetController.OPPONENT, false, true);
this.getAbilities().add(ability);
}
}

View file

@ -27,6 +27,7 @@
*/
package mage.game.permanent;
import java.util.*;
import mage.MageObject;
import mage.MageObjectReference;
import mage.ObjectColor;
@ -55,8 +56,6 @@ import mage.players.Player;
import mage.util.GameLog;
import mage.util.ThreadLocalStringBuilder;
import java.util.*;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -990,8 +989,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
game.informPlayers(player.getLogName() + " sacrificed " + this.getLogName());
}
game.fireEvent(GameEvent.getEvent(EventType.SACRIFICED_PERMANENT, objectId, sourceId, controllerId));
game.checkStateAndTriggered();
game.applyEffects();
return true;
}
return false;

View file

@ -27,18 +27,20 @@
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.util.RandomUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*
*/
@ -54,7 +56,7 @@ public class ClueArtifactToken extends Token {
super("Clue", "colorless Clue artifact token with \"{2}, Sacrifice this artifact: Draw a card.\"");
availableImageSetCodes = tokenImageSets;
cardType.add(CardType.ARTIFACT);
subtype.add("Clue");
subtype.add(SubType.CLUE);
// {2}, Sacrifice this artifact: Draw a card.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(2));

View file

@ -27,6 +27,10 @@
*/
package mage.game.stack;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.Mana;
@ -59,16 +63,6 @@ import mage.players.Player;
import mage.util.GameLog;
import mage.util.SubTypeList;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
@ -90,6 +84,7 @@ public class Spell extends StackObjImpl implements Card {
private boolean copiedSpell;
private boolean faceDown;
private boolean countered;
private boolean resolving = false;
private boolean doneActivatingManaAbilities; // if this is true, the player is no longer allowed to pay the spell costs with activating of mana abilies
@ -196,6 +191,7 @@ public class Spell extends StackObjImpl implements Card {
if (controller == null) {
return false;
}
this.resolving = true;
if (this.isInstant() || this.isSorcery()) {
int index = 0;
result = false;
@ -262,7 +258,7 @@ public class Spell extends StackObjImpl implements Card {
if (permanent != null && permanent instanceof PermanentCard) {
permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set
card.addCardType(CardType.CREATURE);
card.getSubtype(game).remove("Aura");
card.getSubtype(game).remove(SubType.AURA);
}
}
return ability.resolve(game);
@ -279,7 +275,7 @@ public class Spell extends StackObjImpl implements Card {
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null && permanent instanceof PermanentCard) {
((PermanentCard) permanent).getCard().addCardType(CardType.CREATURE);
((PermanentCard) permanent).getCard().getSubtype(game).remove("Aura");
((PermanentCard) permanent).getCard().getSubtype(game).remove(SubType.AURA);
return true;
}
}
@ -480,7 +476,7 @@ public class Spell extends StackObjImpl implements Card {
@Override
public SubTypeList getSubtype(Game game) {
if (this.getSpellAbility() instanceof BestowAbility) {
SubTypeList subtypes = card.getSubtype(game);
SubTypeList subtypes = card.getSubtype(game);
subtypes.add("Aura");
return subtypes;
}
@ -907,6 +903,10 @@ public class Spell extends StackObjImpl implements Card {
return countered;
}
public boolean isResolving() {
return resolving;
}
@Override
public void checkForCountersToAdd(Permanent permanent, Game game) {
card.checkForCountersToAdd(permanent, game);
@ -923,9 +923,10 @@ public class Spell extends StackObjImpl implements Card {
return copy;
}
public boolean isAllCreatureTypes(){
public boolean isAllCreatureTypes() {
return false;
}
public void setIsAllCreatureTypes(boolean value){}
public void setIsAllCreatureTypes(boolean value) {
}
}

View file

@ -36,8 +36,8 @@ import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureOrPlayer;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@ -126,7 +126,7 @@ public class TargetCreatureOrPlayerAmount extends TargetAmount {
}
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) {
count++;
if (count >= this.minNumberOfTargets) {
@ -149,7 +149,7 @@ public class TargetCreatureOrPlayerAmount extends TargetAmount {
}
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (filter.match(permanent, null, sourceControllerId, game)) {
count++;
if (count >= this.minNumberOfTargets) {
@ -170,7 +170,7 @@ public class TargetCreatureOrPlayerAmount extends TargetAmount {
possibleTargets.add(playerId);
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) {
possibleTargets.add(permanent.getId());
}
@ -187,7 +187,7 @@ public class TargetCreatureOrPlayerAmount extends TargetAmount {
possibleTargets.add(playerId);
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (filter.match(permanent, null, sourceControllerId, game)) {
possibleTargets.add(permanent.getId());
}

View file

@ -27,6 +27,7 @@
*/
package mage.target.common;
import mage.filter.StaticFilters;
import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURE;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPermanent;
@ -46,11 +47,11 @@ public class TargetCreaturePermanent extends TargetPermanent {
}
public TargetCreaturePermanent(int numTargets) {
this(numTargets, numTargets, new FilterCreaturePermanent(), false);
this(numTargets, numTargets, StaticFilters.FILTER_PERMANENT_CREATURE, false);
}
public TargetCreaturePermanent(int minNumTargets, int maxNumTargets) {
this(minNumTargets, maxNumTargets, new FilterCreaturePermanent(), false);
this(minNumTargets, maxNumTargets, StaticFilters.FILTER_PERMANENT_CREATURE, false);
}
public TargetCreaturePermanent(int minNumTargets, int maxNumTargets, FilterCreaturePermanent filter, boolean notTarget) {

View file

@ -27,22 +27,21 @@
*/
package mage.target.common;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetAmount;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author North
@ -99,7 +98,7 @@ public class TargetCreaturePermanentAmount extends TargetAmount {
}
return false;
}
@Override
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
return canTarget(id, source, game);
@ -109,7 +108,7 @@ public class TargetCreaturePermanentAmount extends TargetAmount {
public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) {
int count = 0;
MageObject targetSource = game.getObject(sourceId);
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) {
count++;
if (count >= this.minNumberOfTargets) {
@ -123,7 +122,7 @@ public class TargetCreaturePermanentAmount extends TargetAmount {
@Override
public boolean canChoose(UUID sourceControllerId, Game game) {
int count = 0;
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (filter.match(permanent, null, sourceControllerId, game)) {
count++;
if (count >= this.minNumberOfTargets) {
@ -138,7 +137,7 @@ public class TargetCreaturePermanentAmount extends TargetAmount {
public Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
MageObject targetSource = game.getObject(sourceId);
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) {
possibleTargets.add(permanent.getId());
}
@ -149,7 +148,7 @@ public class TargetCreaturePermanentAmount extends TargetAmount {
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (filter.match(permanent, null, sourceControllerId, game)) {
possibleTargets.add(permanent.getId());
}

View file

@ -24,26 +24,24 @@
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
*/
package mage.target.common;
import mage.constants.Zone;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterPermanentOrPlayer;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetImpl;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author nantuko
@ -114,8 +112,8 @@ public class TargetPermanentOrPlayer extends TargetImpl {
MageObject targetSource = game.getObject(source.getSourceId());
if (permanent != null) {
if (!isNotTarget()) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), source.getControllerId(), game) ||
!permanent.canBeTargetedBy(game.getObject(source.getSourceId()), source.getControllerId(), game)) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), source.getControllerId(), game)
|| !permanent.canBeTargetedBy(game.getObject(source.getSourceId()), source.getControllerId(), game)) {
return false;
}
}
@ -138,19 +136,21 @@ public class TargetPermanentOrPlayer extends TargetImpl {
}
/**
* Checks if there are enough {@link mage.game.permanent.Permanent} or {@link mage.players.Player} that can be chosen. Should only be used
* for Ability targets since this checks for protection, shroud etc.
* Checks if there are enough {@link mage.game.permanent.Permanent} or
* {@link mage.players.Player} that can be chosen. Should only be used for
* Ability targets since this checks for protection, shroud etc.
*
* @param sourceId - the target event source
* @param sourceControllerId - controller of the target event source
* @param game
* @return - true if enough valid {@link mage.game.permanent.Permanent} or {@link mage.players.Player} exist
* @return - true if enough valid {@link mage.game.permanent.Permanent} or
* {@link mage.players.Player} exist
*/
@Override
public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) {
int count = 0;
MageObject targetSource = game.getObject(sourceId);
for (UUID playerId: game.getState().getPlayersInRange(sourceControllerId, game)) {
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) {
count++;
@ -159,7 +159,7 @@ public class TargetPermanentOrPlayer extends TargetImpl {
}
}
}
for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) {
count++;
if (count >= this.minNumberOfTargets) {
@ -171,17 +171,19 @@ public class TargetPermanentOrPlayer extends TargetImpl {
}
/**
* Checks if there are enough {@link mage.game.permanent.Permanent} or {@link mage.players.Player} that can be selected. Should not be used
* for Ability targets since this does not check for protection, shroud etc.
* Checks if there are enough {@link mage.game.permanent.Permanent} or
* {@link mage.players.Player} that can be selected. Should not be used for
* Ability targets since this does not check for protection, shroud etc.
*
* @param sourceControllerId - controller of the select event
* @param game
* @return - true if enough valid {@link mage.game.permanent.Permanent} or {@link mage.players.Player} exist
* @return - true if enough valid {@link mage.game.permanent.Permanent} or
* {@link mage.players.Player} exist
*/
@Override
public boolean canChoose(UUID sourceControllerId, Game game) {
int count = 0;
for (UUID playerId: game.getState().getPlayersInRange(sourceControllerId, game)) {
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && filter.match(player, game)) {
count++;
@ -190,7 +192,7 @@ public class TargetPermanentOrPlayer extends TargetImpl {
}
}
}
for (Permanent permanent: game.getBattlefield().getActivePermanents(filterPermanent, sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, sourceControllerId, game)) {
if (filter.match(permanent, null, sourceControllerId, game) && filter.match(permanent, game)) {
count++;
if (count >= this.minNumberOfTargets) {
@ -205,13 +207,13 @@ public class TargetPermanentOrPlayer extends TargetImpl {
public Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
MageObject targetSource = game.getObject(sourceId);
for (UUID playerId: game.getState().getPlayersInRange(sourceControllerId, game)) {
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(player, game)) {
possibleTargets.add(playerId);
}
}
for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterPermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterPermanent(), sourceControllerId, game)) {
if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(permanent, sourceId, sourceControllerId, game)) {
possibleTargets.add(permanent.getId());
}
@ -222,13 +224,13 @@ public class TargetPermanentOrPlayer extends TargetImpl {
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
for (UUID playerId: game.getState().getPlayersInRange(sourceControllerId, game)) {
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && filter.match(player, game)) {
possibleTargets.add(playerId);
}
}
for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) {
if (filter.match(permanent, null, sourceControllerId, game)) {
possibleTargets.add(permanent.getId());
}
@ -239,12 +241,11 @@ public class TargetPermanentOrPlayer extends TargetImpl {
@Override
public String getTargetedName(Game game) {
StringBuilder sb = new StringBuilder();
for (UUID targetId: getTargets()) {
for (UUID targetId : getTargets()) {
Permanent permanent = game.getPermanent(targetId);
if (permanent != null) {
sb.append(permanent.getLogName()).append(' ');
}
else {
} else {
Player player = game.getPlayer(targetId);
sb.append(player.getLogName()).append(' ');
}

View file

@ -4,7 +4,6 @@ import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.game.Game;
@ -43,7 +42,9 @@ public class CastFromHandWatcher extends Watcher {
step = game.getTurn().getStep();
}
Spell spell = (Spell) game.getObject(event.getTargetId());
spellsCastFromHand.add(spell.getSourceId());
if (spell != null) {
spellsCastFromHand.add(spell.getSourceId());
}
}
}