Merge pull request #4940 from magefree/master

merge
This commit is contained in:
theelk801 2018-05-14 14:08:30 -04:00 committed by GitHub
commit fbde510bac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
935 changed files with 13628 additions and 12155 deletions

View file

@ -1083,7 +1083,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
&& this.red >= mana.red
&& this.colorless >= mana.colorless
&& (this.generic >= mana.generic
|| this.countColored() >= mana.countColored() + mana.generic);
|| this.countColored() + this.colorless >= mana.count());
}

View file

@ -126,6 +126,8 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
newColor.black = black && other.black;
newColor.red = red && other.red;
newColor.green = green && other.green;
newColor.gold = gold && other.gold;
return newColor;
}
@ -157,6 +159,7 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
List<ObjectColor> colors = new ArrayList<>();
int firstColor = 5000;
int secondColor = -1;
if (this.isWhite()) {
firstColor = 1;
secondColor = 1;
@ -177,6 +180,7 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
firstColor = Math.min(firstColor, 5);
secondColor = Math.max(secondColor, 5);
}
if (this.isWhite()) {
colors.add(ObjectColor.WHITE);
}
@ -192,6 +196,7 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
if (this.isGreen()) {
colors.add(ObjectColor.GREEN);
}
if (colors.size() >= 2 && secondColor - firstColor >= 3) {
Collections.swap(colors, 0, 1);
}
@ -391,7 +396,11 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
if (test.green != this.green) {
return false;
}
return test.gold == this.gold;
if (test.gold != this.gold) {
return false;
}
return true;
}
@Override
@ -465,10 +474,10 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
o1 = 4;
} else if (this.isWhite()) {
o1 = 5;
} else if (this.isGold()) {
o1 = 6;
}
if (o.isMulticolored()) {
o2 = 7;
} else if (o.isColorless()) {
@ -483,10 +492,10 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
o2 = 4;
} else if (o.isWhite()) {
o2 = 5;
} else if (o.isGold()) {
o2 = 6;
}
return o1 - o2;
}
@ -496,7 +505,12 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
*
* @return null or
*/
public ColoredManaSymbol getColoredManaSymbol() {
public ColoredManaSymbol getOneColoredManaSymbol() {
if (isMulticolored()) {
throw new IllegalStateException("Founded multicolored object, but it's must call with single mana color.");
}
if (isBlack()) {
return ColoredManaSymbol.B;
}

View file

@ -42,7 +42,7 @@ import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DynamicManaEffect;
import mage.abilities.effects.mana.DynamicManaEffect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.cards.Card;
@ -157,6 +157,8 @@ public abstract class AbilityImpl implements Ability {
public void newId() {
if (!(this instanceof MageSingleton)) {
this.id = UUID.randomUUID();
// this.sourceObject = null;
// this.sourceObjectZoneChangeCounter = -1;
}
getEffects().newId();
}
@ -1211,7 +1213,7 @@ public abstract class AbilityImpl implements Ability {
@Override
public Permanent getSourcePermanentIfItStillExists(Game game) {
if (sourceObject == null) {
if (sourceObject == null || !sourceObject.getId().equals(getSourceId())) {
setSourceObject(game.getObject(getSourceId()), game);
}
if (sourceObject instanceof Permanent) {

View file

@ -250,6 +250,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
return false;
}
@Override
public void setMayActivate(TargetController mayActivate) {
this.mayActivate = mayActivate;
}

View file

@ -79,6 +79,6 @@ public class ConstellationAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return new StringBuilder("<i>Constellation</i> - Whenever {this} or another enchantment enters the battlefield under your control, ").append(super.getRule()).toString();
return new StringBuilder("<i>Constellation</i> &mdash; Whenever {this} or another enchantment enters the battlefield under your control, ").append(super.getRule()).toString();
}
}

View file

@ -86,7 +86,7 @@ public class KinshipAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return new StringBuilder("<i>Kinship</i> - At the beginning of your upkeep, ").append(super.getRule()).toString();
return new StringBuilder("<i>Kinship</i> &mdash; At the beginning of your upkeep, ").append(super.getRule()).toString();
}
}

View file

@ -46,12 +46,12 @@ import mage.constants.Zone;
public class LieutenantAbility extends SimpleStaticAbility {
public LieutenantAbility(ContinuousEffect effect) {
super(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), CommanderInPlayCondition.instance, "<i>Lieutenant</i> - As long as you control your commander, {this} gets +2/+2"));
super(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), CommanderInPlayCondition.instance, "<i>Lieutenant</i> &mdash; As long as you control your commander, {this} gets +2/+2"));
this.addEffect(new ConditionalContinuousEffect(effect, CommanderInPlayCondition.instance, effect.getText(null)));
}
public LieutenantAbility(Effects effects) {
super(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), CommanderInPlayCondition.instance, "<i>Lieutenant</i> - As long as you control your commander, {this} gets +2/+2"));
super(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), CommanderInPlayCondition.instance, "<i>Lieutenant</i> &mdash; As long as you control your commander, {this} gets +2/+2"));
for (Effect effect : effects) {
this.addEffect(new ConditionalContinuousEffect((ContinuousEffect) effect, CommanderInPlayCondition.instance, effect.getText(null)));
}

View file

@ -68,7 +68,7 @@ public class StriveAbility extends SimpleStaticAbility {
@Override
public String getRule() {
return new StringBuilder("<i>Strive</i> - {this} costs ").append(striveCost).append(" more to cast for each target beyond the first.").toString();
return new StringBuilder("<i>Strive</i> &mdash; {this} costs ").append(striveCost).append(" more to cast for each target beyond the first.").toString();
}
}

View file

@ -1,18 +1,27 @@
package mage.abilities.common;
import mage.abilities.condition.common.LegendaryCondition;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.SupertypePredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
/**
* @author JRHerlehy
* Created on 4/8/18.
* @author JRHerlehy Created on 4/8/18.
*/
public class LegendarySpellAbility extends SimpleStaticAbility {
public LegendarySpellAbility() {
super(Zone.ALL, new CastOnlyIfConditionIsTrueEffect(LegendaryCondition.instance));
super(Zone.ALL, new LegendarySpellAbilityCheckEffect());
this.setRuleAtTheTop(true);
this.getEffects().get(0).setText("<i>(You may cast a legendary sorcery only if you control a legendary creature or planeswalker.)</i>");
}
private LegendarySpellAbility(final LegendarySpellAbility ability) {
@ -24,3 +33,46 @@ public class LegendarySpellAbility extends SimpleStaticAbility {
return new LegendarySpellAbility(this);
}
}
class LegendarySpellAbilityCheckEffect extends ContinuousRuleModifyingEffectImpl {
private static final FilterPermanent filter = new FilterPermanent("legendary creature or planeswalker");
static {
filter.add(
Predicates.and(
new SupertypePredicate(SuperType.LEGENDARY),
Predicates.or(
new CardTypePredicate(CardType.CREATURE),
new CardTypePredicate(CardType.PLANESWALKER)
)
)
);
}
public LegendarySpellAbilityCheckEffect() {
super(Duration.EndOfGame, Outcome.Detriment);
staticText = "<i>(You may cast a legendary sorcery only if you control a legendary creature or planeswalker.)</i>";
}
private LegendarySpellAbilityCheckEffect(final LegendarySpellAbilityCheckEffect effect) {
super(effect);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return event.getSourceId().equals(source.getSourceId())
&& !game.getBattlefield().contains(filter, event.getPlayerId(), 1, game);
}
@Override
public LegendarySpellAbilityCheckEffect copy() {
return new LegendarySpellAbilityCheckEffect(this);
}
}

View file

@ -1,46 +0,0 @@
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.constants.CardType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.SupertypePredicate;
import mage.game.Game;
/**
* @author JRHerlehy
* Created on 4/7/18.
*/
public enum LegendaryCondition implements Condition {
instance;
private static final FilterPermanent filter = new FilterPermanent("legendary creature or planeswalker");
static {
filter.add(
Predicates.and(
new SupertypePredicate(SuperType.LEGENDARY),
Predicates.or(
new CardTypePredicate(CardType.CREATURE),
new CardTypePredicate(CardType.PLANESWALKER)
)
)
);
}
@Override
public boolean apply(Game game, Ability source) {
return game.getBattlefield().contains(filter, source.getControllerId(), 1, game);
}
@Override
public String toString() {
return super.toString();
}
}

View file

@ -63,7 +63,7 @@ public class ExileFromStackCost extends CostImpl {
}
String spellName = spellToExile.getName();
if (spellToExile.isCopy()) {
game.getStack().remove(spellToExile);
game.getStack().remove(spellToExile, game);
} else {
spellToExile.moveToExile(null, "", ability.getSourceId(), game);
}

View file

@ -30,8 +30,8 @@ package mage.abilities.decorator;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.choices.ChoiceColor;
import mage.game.Game;
import mage.players.Player;
@ -73,31 +73,7 @@ public class ConditionalManaEffect extends ManaEffect {
if (controller == null) {
return false;
}
if (condition.apply(game, source)) {
effect.setTargetPointer(this.targetPointer);
} else if (otherwiseEffect != null) {
otherwiseEffect.setTargetPointer(this.targetPointer);
}
Mana mana = getMana(game, source);
if (mana == null) {
return false;
}
if (mana.getAny() > 0) {
int amount = mana.getAny();
ChoiceColor choice = new ChoiceColor(true);
Mana createdMana = null;
if (controller.choose(outcome, choice, game)) {
createdMana = choice.getMana(amount);
}
if (createdMana == null) {
return false;
}
mana = createdMana;
// because the mana type is now choosen, fire the event with the mana information
checkToFirePossibleEvents(mana, game, source);
}
controller.getManaPool().addMana(mana, game, source);
controller.getManaPool().addMana(getMana(game, source), game, source);
return true;
}
@ -107,12 +83,25 @@ public class ConditionalManaEffect extends ManaEffect {
}
@Override
public Mana getMana(Game game, Ability source) {
Mana mana = null;
public Mana produceMana(boolean netMana, Game game, Ability source) {
Mana mana = new Mana();
if (condition.apply(game, source)) {
mana = effect.getMana();
mana = effect.getManaTemplate().copy();
} else if (otherwiseEffect != null) {
mana = otherwiseEffect.getMana();
mana = otherwiseEffect.getManaTemplate().copy();
}
if (mana.getAny() > 0) {
int amount = mana.getAny();
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return mana;
}
ChoiceColor choice = new ChoiceColor(true);
if (controller.choose(outcome, choice, game)) {
mana.setAny(0);
mana.add(choice.getMana(amount));
}
checkToFirePossibleEvents(mana, game, source);
}
return mana;
}

View file

@ -48,7 +48,7 @@ public class OpponentsLostLifeCount implements DynamicValue {
public int calculate(Game game, UUID controllerId) {
PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName());
if (watcher != null) {
return watcher.getAllOppLifeLost(controllerId);
return watcher.getAllOppLifeLost(controllerId, game);
}
return 0;
}

View file

@ -8,18 +8,30 @@ import mage.game.Game;
public class SignInversionDynamicValue implements DynamicValue {
private final DynamicValue value;
private final boolean canBePositive;
public SignInversionDynamicValue(DynamicValue value) {
this(value, true);
}
public SignInversionDynamicValue(DynamicValue value, boolean canBePositive) {
this.value = value.copy();
this.canBePositive = canBePositive;
}
SignInversionDynamicValue(final SignInversionDynamicValue dynamicValue) {
this.value = dynamicValue.value.copy();
this.canBePositive = dynamicValue.canBePositive;
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return -1 * value.calculate(game, sourceAbility, effect);
int amount = value.calculate(game, sourceAbility, effect);
if (amount >= 0 || canBePositive) {
return -1 * amount;
} else {
return 0;
}
}
@Override

View file

@ -926,6 +926,14 @@ public class ContinuousEffects implements Serializable {
while (!done) { // loop needed if a added effect adds again an effect (e.g. Level 5- of Joraga Treespeaker)
done = true;
layer = filterLayeredEffects(activeLayerEffects, Layer.AbilityAddingRemovingEffects_6);
// debug
/*
System.out.println(game.getTurn() + ", " + game.getPhase() + ": " + "need apply " + layer.stream()
.map((eff) -> {return eff.getClass().getName().replaceAll(".+\\.(.+)", "$1");})
.collect(Collectors.joining(", ")));
*/
for (ContinuousEffect effect : layer) {
if (activeLayerEffects.contains(effect) && !appliedEffects.contains(effect.getId())) { // Effect does still exist and was not applied yet
Set<UUID> dependentTo = effect.isDependentTo(layer);

View file

@ -27,6 +27,7 @@
*/
package mage.abilities.effects;
import mage.MageObject;
import mage.abilities.Ability;
import mage.constants.Duration;
import mage.constants.EffectType;
@ -44,26 +45,34 @@ import mage.target.Target;
*/
public abstract class RedirectionEffect extends ReplacementEffectImpl {
protected Target redirectTarget;
protected int amountToRedirect;
protected boolean oneUsage;
public RedirectionEffect(Duration duration) {
this(duration, Integer.MAX_VALUE, false);
public enum UsageType {
ACCORDING_DURATION,
ONE_USAGE_ABSOLUTE,
ONE_USAGE_AT_THE_SAME_TIME; // all damage dealt at the same time
}
public RedirectionEffect(Duration duration, int amountToRedirect, boolean oneUsage) {
protected Target redirectTarget;
protected int amountToRedirect;
protected UsageType usageType;
protected int applyEffectsCounter;
public RedirectionEffect(Duration duration) {
this(duration, Integer.MAX_VALUE, UsageType.ACCORDING_DURATION);
applyEffectsCounter = -1;
}
public RedirectionEffect(Duration duration, int amountToRedirect, UsageType usageType) {
super(duration, Outcome.RedirectDamage);
this.effectType = EffectType.REDIRECTION;
this.amountToRedirect = amountToRedirect;
this.oneUsage = oneUsage;
this.usageType = usageType;
}
public RedirectionEffect(final RedirectionEffect effect) {
super(effect);
this.redirectTarget = effect.redirectTarget;
this.amountToRedirect = effect.amountToRedirect;
this.oneUsage = effect.oneUsage;
this.usageType = effect.usageType;
}
@Override
@ -79,26 +88,38 @@ public abstract class RedirectionEffect extends ReplacementEffectImpl {
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
int damageToRedirect = event.getAmount();
if (damageToRedirect < 1) { // if multiple replacement effect apply, the rest damage can be 0, so the effect is not applied/replaced
return false;
}
String sourceLogName = source != null ? game.getObject(source.getSourceId()).getLogName() + ": " : "";
DamageEvent damageEvent = (DamageEvent) event;
int restDamage = 0;
int damageToRedirect = event.getAmount();
if (damageEvent.getAmount() > amountToRedirect) {
restDamage = damageEvent.getAmount() - amountToRedirect;
damageToRedirect = amountToRedirect;
}
if (damageToRedirect > 0 && oneUsage) {
this.discard();
if (damageToRedirect > 0 && usageType != UsageType.ACCORDING_DURATION) {
if (UsageType.ONE_USAGE_ABSOLUTE == usageType) {
this.discard();
}
if (applyEffectsCounter > 0) {
if (applyEffectsCounter < game.getState().getApplyEffectsCounter()) {
this.discard();
}
} else {
applyEffectsCounter = game.getState().getApplyEffectsCounter();
}
}
Permanent permanent = game.getPermanent(redirectTarget.getFirstTarget());
if (permanent != null) {
permanent.damage(damageToRedirect, event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects());
game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage to " + permanent.getLogName());
game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage" + getRedirectedFromText(event, game) + " to " + permanent.getLogName());
} else {
Player player = game.getPlayer(redirectTarget.getFirstTarget());
if (player != null) {
player.damage(damageToRedirect, event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects());
game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage to " + player.getLogName());
game.informPlayers(sourceLogName + "Redirected " + damageToRedirect + " damage" + getRedirectedFromText(event, game) + " to " + player.getLogName());
}
}
if (restDamage > 0) {
@ -108,4 +129,16 @@ public abstract class RedirectionEffect extends ReplacementEffectImpl {
return true;
}
private String getRedirectedFromText(GameEvent event, Game game) {
Player player = game.getPlayer(event.getTargetId());
if (player != null) {
return " from " + player.getLogName();
}
MageObject mageObject = game.getObject(event.getTargetId());
if (mageObject != null) {
return " from " + mageObject.getLogName();
}
return "";
}
}

View file

@ -1,61 +0,0 @@
/*
* 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 mage.abilities.effects.common;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author LevelX2
*/
public class AddConditionalColorlessManaEffect extends ManaEffect {
private final int amount;
private final ConditionalManaBuilder manaBuilder;
public AddConditionalColorlessManaEffect(int amount, ConditionalManaBuilder manaBuilder) {
super();
this.amount = amount;
this.manaBuilder = manaBuilder;
staticText = "Add " + String.format(String.format("%%%ds", amount), " ").replace(" ", "{C}")
+ ". " + manaBuilder.getRule();
}
public AddConditionalColorlessManaEffect(final AddConditionalColorlessManaEffect effect) {
super(effect);
this.amount = effect.amount;
this.manaBuilder = effect.manaBuilder;
}
@Override
public AddConditionalColorlessManaEffect copy() {
return new AddConditionalColorlessManaEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
player.getManaPool().addMana(getMana(game, source), game, source);
return true;
}
return false;
}
@Override
public Mana getMana(Game game, Ability source) {
return manaBuilder.setMana(Mana.ColorlessMana(amount), source, game).build();
}
public Mana getMana() {
return Mana.ColorlessMana(amount);
}
}

View file

@ -1,49 +0,0 @@
package mage.abilities.effects.common;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.choices.ChoiceColor;
import mage.game.Game;
import mage.players.Player;
/**
*
* Created by Galatolol
*/
public class AddManaOfAnyColorToManaPoolTargetPlayerEffect extends ManaEffect {
public AddManaOfAnyColorToManaPoolTargetPlayerEffect(String textManaPoolOwner) {
super();
this.staticText = (textManaPoolOwner.equals("their") ? "that player adds " : "add ") + "one mana of any color" + " to " + textManaPoolOwner + " mana pool";
}
public AddManaOfAnyColorToManaPoolTargetPlayerEffect(final AddManaOfAnyColorToManaPoolTargetPlayerEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
UUID playerId = (UUID) game.getState().getValue(source.getSourceId() + "_player");
Player player = game.getPlayer(playerId);
ChoiceColor choice = new ChoiceColor();
if (player != null && player.choose(outcome, choice, game)) {
Mana mana = choice.getMana(1);
checkToFirePossibleEvents(mana, game, source);
player.getManaPool().addMana(mana, game, source);
return true;
}
return false;
}
@Override
public AddManaOfAnyColorToManaPoolTargetPlayerEffect copy() {
return new AddManaOfAnyColorToManaPoolTargetPlayerEffect(this);
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
}
}

View file

@ -27,6 +27,7 @@
*/
package mage.abilities.effects.common;
import java.util.Objects;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
@ -36,8 +37,6 @@ import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import java.util.Objects;
/**
*
* @author jeffwadsworth
@ -67,6 +66,17 @@ public class CantBeRegeneratedSourceEffect extends ContinuousRuleModifyingEffect
return event.getType() == EventType.REGENERATE;
}
@Override
public void init(Ability source, Game game) {
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
if (duration.isOnlyValidIfNoZoneChange()) {
// If source permanent is no longer onto battlefield discard the effect
if (source.getSourcePermanentIfItStillExists(game) == null) {
discard();
}
}
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return Objects.equals(source.getSourceId(), event.getTargetId());

View file

@ -63,7 +63,7 @@ public class DestroySourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent != null) {
permanent.destroy(source.getSourceId(), game, noRegen);
return true;

View file

@ -71,6 +71,7 @@ public class DoIfCostPaid extends OneShotEffect {
}
message = getCostText() + " and " + effectText + '?';
message = Character.toUpperCase(message.charAt(0)) + message.substring(1);
CardUtil.replaceSourceName(message, mageObject.getName());
} else {
message = chooseUseText;
}
@ -79,6 +80,7 @@ public class DoIfCostPaid extends OneShotEffect {
if (cost.canPay(source, source.getSourceId(), player.getId(), game)
&& executingEffects.size() > 0 && (!optional || player.chooseUse(executingEffects.get(0).getOutcome(), message, source, game))) {
cost.clearPaid();
int bookmark = game.bookmarkState();
if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) {
for (Effect effect : executingEffects) {
effect.setTargetPointer(this.targetPointer);
@ -89,13 +91,17 @@ public class DoIfCostPaid extends OneShotEffect {
}
}
player.resetStoredBookmark(game); // otherwise you can e.g. undo card drawn with Mentor of the Meek
} else if (!otherwiseEffects.isEmpty()) {
for (Effect effect : otherwiseEffects) {
effect.setTargetPointer(this.targetPointer);
if (effect instanceof OneShotEffect) {
result &= effect.apply(game, source);
} else {
game.addEffect((ContinuousEffect) effect, source);
} else {
// Paying cost was cancels so try to undo payment so far
game.restoreState(bookmark, DoIfCostPaid.class.getName());
if (!otherwiseEffects.isEmpty()) {
for (Effect effect : otherwiseEffects) {
effect.setTargetPointer(this.targetPointer);
if (effect instanceof OneShotEffect) {
result &= effect.apply(game, source);
} else {
game.addEffect((ContinuousEffect) effect, source);
}
}
}
}

View file

@ -27,6 +27,7 @@
*/
package mage.abilities.effects.common;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
@ -50,21 +51,19 @@ public class FightTargetSourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent originalPermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (originalPermanent != null) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
// only if target is legal the effect will be applied
if (source.getTargets().get(0).isLegal(source, game)) {
Permanent creature1 = game.getPermanent(source.getTargets().get(0).getFirstTarget());
// 20110930 - 701.10
if (creature1 != null && sourcePermanent != null) {
if (creature1.isCreature() && sourcePermanent.isCreature()) {
return sourcePermanent.fight(creature1, source, game);
}
MageObject sourceObject = source.getSourceObject(game);
if (sourceObject != null) {
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
Permanent creature1 = game.getPermanent(getTargetPointer().getFirst(game, source));
// 20110930 - 701.10
if (creature1 != null && sourcePermanent != null) {
if (creature1.isCreature() && sourcePermanent.isCreature()) {
return sourcePermanent.fight(creature1, source, game);
}
}
if (!game.isSimulation())
game.informPlayers(originalPermanent.getLogName() + ": Fighting effect has been fizzled.");
if (!game.isSimulation()) {
game.informPlayers(sourceObject.getLogName() + ": Fighting effect has been fizzled.");
}
}
return false;
}
@ -83,4 +82,3 @@ public class FightTargetSourceEffect extends OneShotEffect {
}
}

View file

@ -8,11 +8,9 @@ import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
import mage.players.Player;
/**
* @author Loki
*/
@ -33,14 +31,15 @@ public class FlipSourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
Player controller = game.getPlayer(source.getControllerId());
if (permanent != null && controller != null) {
if (permanent.flip(game)) {
ContinuousEffect effect = new ConditionalContinuousEffect(new CopyTokenEffect(flipToken), FlippedCondition.instance, "");
game.addEffect(effect, source);
if (!game.isSimulation())
if (!game.isSimulation()) {
game.informPlayers(new StringBuilder(controller.getLogName()).append(" flips ").append(permanent.getName()).toString());
}
return true;
}
}

View file

@ -35,7 +35,6 @@ import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.Outcome;
@ -150,6 +149,7 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff
FilterCard pickFilter, Zone targetZoneLookedCards, boolean putOnTop,
boolean reveal, boolean upTo, Zone targetZonePickedCards,
boolean optional) {
this(numberOfCards, mayShuffleAfter, numberToPick, pickFilter,
targetZoneLookedCards, putOnTop, reveal, upTo,
targetZonePickedCards, optional, true, true);
@ -207,16 +207,10 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff
}
@Override
protected void cardLooked(Card card, Game game, Ability source) {
if (numberToPick.calculate(game, source, this) > 0 && filter.match(card, game)) {
++foundCardsToPick;
}
}
@Override
protected void actionWithSelectedCards(Cards cards, Game game, Ability source, String windowName) {
protected void actionWithSelectedCards(Cards cards, Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null && foundCardsToPick > 0) {
if (player != null && numberToPick.calculate(game, source, this) > 0
&& cards.count(filter, source.getSourceId(), source.getControllerId(), game) > 0) {
if (!optional || player.chooseUse(Outcome.DrawCard, getMayText(), source, game)) {
FilterCard pickFilter = filter.copy();
pickFilter.setMessage(getPickText());
@ -231,7 +225,7 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff
player.moveCards(pickedCards.getCards(game), targetPickedCards, source, game);
}
if (revealPickedCards) {
player.revealCards(windowName, pickedCards, game);
player.revealCards(source, pickedCards, game);
}
}
@ -346,7 +340,14 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff
}
sb.append(" order");
} else if (targetZoneLookedCards == Zone.GRAVEYARD) {
sb.append(" and the other into your graveyard");
sb.append(" and the");
if (numberOfCards instanceof StaticValue && numberToPick instanceof StaticValue
&& ((StaticValue) numberToPick).getValue() + 1 == ((StaticValue) numberOfCards).getValue()) {
sb.append(" other");
} else {
sb.append(" rest");
}
sb.append(" into your graveyard");
}
}
// get text frame from super class and inject action text

View file

@ -29,18 +29,15 @@ package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.SpellAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.util.CardUtil;
@ -105,46 +102,25 @@ public class LookLibraryControllerEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
String windowName = "Reveal";
if (source instanceof SpellAbility) {
Card sourceCard = game.getCard(source.getSourceId());
if (sourceCard != null) {
windowName = sourceCard.getIdName();
}
} else {
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent != null) {
windowName = sourcePermanent.getIdName();
}
}
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
// take cards from library and look at them
boolean topCardRevealed = player.isTopCardRevealed();
player.setTopCardRevealed(false);
Cards cards = new CardsImpl();
int count = Math.min(player.getLibrary().size(), this.numberOfCards.calculate(game, source, this));
for (int i = 0; i < count; i++) {
Card card = player.getLibrary().removeFromTop(game);
if (card != null) {
cards.add(card);
this.cardLooked(card, game, source);
}
}
player.lookAtCards(windowName, cards, game);
boolean topCardRevealed = controller.isTopCardRevealed();
controller.setTopCardRevealed(false);
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, this.numberOfCards.calculate(game, source, this)));
this.actionWithSelectedCards(cards, game, source, windowName);
controller.lookAtCards(source, null, cards, game);
this.putCardsBack(source, player, cards, game);
this.actionWithSelectedCards(cards, game, source);
player.setTopCardRevealed(topCardRevealed);
this.putCardsBack(source, controller, cards, game);
this.mayShuffle(player, source, game);
controller.setTopCardRevealed(topCardRevealed);
this.mayShuffle(controller, source, game);
return true;
}
@ -158,10 +134,7 @@ public class LookLibraryControllerEffect extends OneShotEffect {
return this;
}
protected void cardLooked(Card card, Game game, Ability source) {
}
protected void actionWithSelectedCards(Cards cards, Game game, Ability source, String windowName) {
protected void actionWithSelectedCards(Cards cards, Game game, Ability source) {
}
/**

View file

@ -47,11 +47,13 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect {
protected int amount;
protected boolean putToGraveyard;
protected boolean mayShuffleAfter; // for Visions
public LookLibraryTopCardTargetPlayerEffect(int amount) {
super(Outcome.Benefit);
this.amount = amount;
this.putToGraveyard = false;
this.mayShuffleAfter = false;
setText();
}
@ -59,6 +61,15 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect {
super(Outcome.Benefit);
this.amount = amount;
this.putToGraveyard = putToGraveyard;
this.mayShuffleAfter = false;
setText();
}
public LookLibraryTopCardTargetPlayerEffect(int amount, boolean putToGraveyard, boolean mayShuffleAfter) {
super(Outcome.Benefit);
this.amount = amount;
this.putToGraveyard = putToGraveyard;
this.mayShuffleAfter = mayShuffleAfter;
setText();
}
@ -70,6 +81,7 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect {
super(effect);
amount = effect.amount;
putToGraveyard = effect.putToGraveyard;
mayShuffleAfter = effect.mayShuffleAfter;
}
@Override
@ -95,6 +107,11 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect {
}
}
}
if (mayShuffleAfter) {
if (player.chooseUse(Outcome.Benefit, (player == targetPlayer ? "Shuffle your library?" : "Do you want the chosen player to shuffle his or her library?"), source, game)) {
targetPlayer.shuffleLibrary(source, game);
}
}
return true;
}
return false;
@ -118,6 +135,9 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect {
}
sb.append(" into that player's graveyard");
}
if (mayShuffleAfter) {
sb.append(". You may then have that player shuffle that library");
}
this.staticText = sb.toString();
}
}

View file

@ -24,10 +24,11 @@
* 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 java.util.ArrayList;
import java.util.List;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
@ -45,26 +46,72 @@ import mage.game.events.ManaEvent;
*/
public abstract class ManaEffect extends OneShotEffect {
protected Mana createdMana;
public ManaEffect() {
super(Outcome.PutManaInPool);
createdMana = null;
}
public ManaEffect(final ManaEffect effect) {
super(effect);
this.createdMana = effect.createdMana == null ? null : effect.createdMana.copy();
}
public abstract Mana getMana(Game game, Ability source);
/**
* Creates the mana the effect can produce or if that already has happened
* returns the mana the effect has created during its process of resolving
*
* @param game
* @param source
* @return
*/
public Mana getMana(Game game, Ability source) {
if (createdMana == null) {
return createdMana = produceMana(false, game, source);
}
return createdMana;
}
/**
* Only used for mana effects that decide which kind of mana is produced during resolution of the effect.
*
* Returns the currently available max mana variations the effect can
* produce
*
* @param game
* @param source
* @return
*/
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netMana = new ArrayList<>();
Mana mana = produceMana(true, game, source);
if (mana != null) {
netMana.add(mana);
}
return netMana;
}
/**
* Produced the mana the effect can produce
*
* @param netMana true - produce the hypotetical possible mana for check of
* possible castable spells
* @param game
* @param source
* @return
*/
public abstract Mana produceMana(boolean netMana, Game game, Ability source);
/**
* Only used for mana effects that decide which kind of mana is produced
* during resolution of the effect.
*
* @param mana
* @param game
* @param source
*/
public void checkToFirePossibleEvents(Mana mana, Game game, Ability source) {
if (source.getAbilityType()==AbilityType.MANA) {
for (Cost cost: source.getCosts()) {
if (source.getAbilityType() == AbilityType.MANA) {
for (Cost cost : source.getCosts()) {
if (cost instanceof TapSourceCost) {
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, source.getSourceId(), source.getSourceId(), source.getControllerId(), mana);
if (!game.replaceEvent(event)) {

View file

@ -5,7 +5,6 @@
*/
package mage.abilities.effects.common;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
@ -34,9 +33,8 @@ public class PhaseOutSourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
if (sourceObject instanceof Permanent) {
Permanent permanent = (Permanent) sourceObject;
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent != null) {
return permanent.phaseOut(game);
}
return false;

View file

@ -54,6 +54,17 @@ public class PreventDamageToSourceEffect extends PreventionEffectImpl {
return new PreventDamageToSourceEffect(this);
}
@Override
public void init(Ability source, Game game) {
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
if (duration.isOnlyValidIfNoZoneChange()) {
// If source permanent is no longer onto battlefield discard the effect
if (source.getSourcePermanentIfItStillExists(game) == null) {
discard();
}
}
}
@Override
public boolean apply(Game game, Ability source) {
return true;

View file

@ -18,8 +18,8 @@ import mage.game.permanent.Permanent;
*/
public class RedirectDamageFromSourceToTargetEffect extends RedirectionEffect {
public RedirectDamageFromSourceToTargetEffect(Duration duration, int amountToRedirect, boolean oneUsage) {
super(duration, amountToRedirect, oneUsage);
public RedirectDamageFromSourceToTargetEffect(Duration duration, int amountToRedirect, UsageType usageType) {
super(duration, amountToRedirect, usageType);
staticText = "The next " + amountToRedirect + " damage that would be dealt to {this} this turn is dealt to target creature you control instead.";
}

View file

@ -28,12 +28,18 @@
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.Card;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
/**
*
@ -43,21 +49,25 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
private boolean tapped;
private boolean ownerControl;
private boolean haste;
public ReturnSourceFromGraveyardToBattlefieldEffect() {
this(false);
}
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped) {
super(Outcome.PutCreatureInPlay);
this.tapped = tapped;
setText();
this(tapped, true);
}
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped, boolean ownerControl) {
this(tapped, ownerControl, false);
}
public ReturnSourceFromGraveyardToBattlefieldEffect(boolean tapped, boolean ownerControl, boolean haste) {
super(Outcome.PutCreatureInPlay);
this.tapped = tapped;
this.ownerControl = ownerControl;
this.haste = haste;
setText();
}
@ -65,6 +75,7 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
super(effect);
this.tapped = effect.tapped;
this.ownerControl = effect.ownerControl;
this.haste = effect.haste;
}
@Override
@ -89,6 +100,14 @@ public class ReturnSourceFromGraveyardToBattlefieldEffect extends OneShotEffect
}
if (game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) {
player.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, true, null);
if (haste) {
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom);
effect.setTargetPointer(new FixedTarget(permanent, game));
game.addEffect(effect, source);
}
}
}
return true;
}

View file

@ -33,6 +33,7 @@ import mage.cards.Card;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
/**
*
@ -81,16 +82,17 @@ public class ReturnToBattlefieldUnderOwnerControlSourceEffect extends OneShotEff
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Card card = game.getCard(source.getSourceId());
if (card != null) {
if (controller != null && card != null) {
// return only from public zones
switch (game.getState().getZone(card.getId())) {
case EXILED:
case COMMAND:
case GRAVEYARD:
if (zoneChangeCounter < 0 || game.getState().getZoneChangeCounter(card.getId()) == zoneChangeCounter) {
Zone currentZone = game.getState().getZone(card.getId());
if (card.putOntoBattlefield(game, currentZone, source.getSourceId(), card.getOwnerId(), tapped)) {
if (controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, true, null)) {
if (attacking) {
game.getCombat().addAttackingCreature(card.getId(), game);
}

View file

@ -103,7 +103,7 @@ public class ReturnToHandTargetEffect extends OneShotEffect {
}
}
for (UUID copyId : copyIds) {
game.getStack().remove(game.getSpell(copyId));
game.getStack().remove(game.getSpell(copyId), game);
}
return controller.moveCards(cards, Zone.HAND, source, game);
}

View file

@ -63,10 +63,7 @@ public class TapSourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent == null) {
permanent = game.getPermanentEntering(source.getSourceId());
}
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent != null) {
if (withoutTrigger) {
permanent.setTapped(true);

View file

@ -31,8 +31,6 @@ import java.util.UUID;
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.FilterLandPermanent;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game;
@ -46,6 +44,11 @@ import mage.util.CardUtil;
*/
public class UntapLandsEffect extends OneShotEffect {
private static final FilterLandPermanent filter = new FilterLandPermanent("untapped lands");
static {
filter.add(new TappedPredicate());
}
private final int amount;
private final boolean upTo;
@ -70,15 +73,12 @@ public class UntapLandsEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
TargetLandPermanent target = new TargetLandPermanent(upTo ? 0 : amount, amount, StaticFilters.FILTER_LAND, true);
int tappedLands = game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game).size();
TargetLandPermanent target = new TargetLandPermanent(upTo ? 0 : Math.min(tappedLands, amount), amount, filter, true);
if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) {
// UI Shortcut: Check if any lands are already tapped. If there are equal/fewer than amount, give the option to add those in to be untapped now.
FilterPermanent filter = new FilterLandPermanent();
filter.add(new TappedPredicate());
int tappedLands = game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game).size();
if (tappedLands <= amount) {
if (tappedLands <= amount && upTo) {
if (controller.chooseUse(outcome, "Include your tapped lands to untap?", source, game)) {
for (Permanent land : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) {
target.addTarget(land.getId(), source, game);

View file

@ -58,7 +58,7 @@ public class CantBeBlockedByAllSourceEffect extends RestrictionEffect {
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return source.getSourceId().equals(permanent.getId());
return permanent.equals(source.getSourcePermanentIfItStillExists(game));
}
@Override

View file

@ -38,13 +38,33 @@ import mage.game.permanent.Permanent;
*/
public class BecomesBlackZombieAdditionEffect extends ContinuousEffectImpl {
private boolean giveBlackColor = true;
public BecomesBlackZombieAdditionEffect() {
super(Duration.Custom, Outcome.Neutral);
staticText = "That creature is a black Zombie in addition to its other colors and types";
this.giveBlackColor = true;
updateText();
}
public BecomesBlackZombieAdditionEffect(boolean giveBlackColor) {
this();
this.giveBlackColor = giveBlackColor;
updateText();
}
public BecomesBlackZombieAdditionEffect(final BecomesBlackZombieAdditionEffect effect) {
super(effect);
this.giveBlackColor = effect.giveBlackColor;
updateText();
}
private void updateText() {
if (this.giveBlackColor) {
this.staticText = "That creature is a black Zombie in addition to its other colors and types";
} else {
this.staticText = "That creature is a Zombie in addition to its other types";
}
}
@Override
@ -73,7 +93,7 @@ public class BecomesBlackZombieAdditionEffect extends ContinuousEffectImpl {
}
break;
case ColorChangingEffects_5:
if (sublayer == SubLayer.NA) {
if (sublayer == SubLayer.NA && this.giveBlackColor) {
creature.getColor(game).setBlack(true);
}
break;

View file

@ -52,21 +52,24 @@ import java.util.Set;
public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
protected Token token;
protected String type;
protected String theyAreStillType;
private final FilterPermanent filter;
private boolean loseColor = true;
public BecomesCreatureAllEffect(Token token, String type, FilterPermanent filter, Duration duration) {
public BecomesCreatureAllEffect(Token token, String theyAreStillType, FilterPermanent filter, Duration duration, boolean loseColor) {
super(duration, Outcome.BecomeCreature);
this.token = token;
this.type = type;
this.theyAreStillType = theyAreStillType;
this.filter = filter;
this.loseColor = loseColor;
}
public BecomesCreatureAllEffect(final BecomesCreatureAllEffect effect) {
super(effect);
token = effect.token.copy();
type = effect.type;
this.token = effect.token.copy();
this.theyAreStillType = effect.theyAreStillType;
this.filter = effect.filter.copy();
this.loseColor = effect.loseColor;
}
@Override
@ -94,6 +97,7 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
} else {
affectedPermanents = new HashSet<>(game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game));
}
for(Permanent permanent : affectedPermanents) {
if (permanent != null) {
switch (layer) {
@ -106,7 +110,7 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
}
}
}
if (type == null) {
if (theyAreStillType == null) {
permanent.getSubtype(game).clear();
}
if (!token.getSubtype(game).isEmpty()) {
@ -114,13 +118,22 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
}
}
break;
case ColorChangingEffects_5:
if (sublayer == SubLayer.NA) {
if (this.loseColor) {
permanent.getColor(game).setBlack(false);
permanent.getColor(game).setGreen(false);
permanent.getColor(game).setBlue(false);
permanent.getColor(game).setWhite(false);
permanent.getColor(game).setRed(false);
}
if (token.getColor(game).hasColor()) {
permanent.getColor(game).setColor(token.getColor(game));
permanent.getColor(game).addColor(token.getColor(game));
}
}
break;
case AbilityAddingRemovingEffects_6:
if (sublayer == SubLayer.NA) {
if (!token.getAbilities().isEmpty()) {
@ -130,6 +143,7 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
}
}
break;
case PTChangingEffects_7:
if (sublayer == SubLayer.SetPT_7b) {
int power = token.getPower().getValue();
@ -139,6 +153,7 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
permanent.getToughness().setValue(toughness);
}
}
break;
}
}
}
@ -168,8 +183,8 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
sb.append(" become ");
}
sb.append(token.getDescription());
if (type != null && !type.isEmpty()) {
sb.append(". They're still ").append(type);
if (theyAreStillType != null && !theyAreStillType.isEmpty()) {
sb.append(". They're still ").append(theyAreStillType);
}
return sb.toString();
}

View file

@ -40,7 +40,7 @@ import mage.game.permanent.token.Token;
public class BecomesCreatureAttachedEffect extends ContinuousEffectImpl {
public enum LoseType {
NONE, ALL, ALL_BUT_COLOR, ABILITIES, ABILITIES_SUBTYPE_AND_PT, ABILITIES_AND_PT
NONE, ALL, ALL_BUT_COLOR, ABILITIES, ABILITIES_SUBTYPE, COLOR
}
protected Token token;
@ -98,7 +98,7 @@ public class BecomesCreatureAttachedEffect extends ContinuousEffectImpl {
switch (loseType) {
case ALL:
case ALL_BUT_COLOR:
case ABILITIES_SUBTYPE_AND_PT:
case ABILITIES_SUBTYPE:
permanent.getSubtype(game).retainAll(SubType.getLandTypes(false));
break;
}
@ -107,12 +107,12 @@ public class BecomesCreatureAttachedEffect extends ContinuousEffectImpl {
permanent.getSubtype(game).add(t);
}
}
}
break;
case ColorChangingEffects_5:
if (sublayer == SubLayer.NA) {
if (loseType == LoseType.ALL) {
if (loseType == LoseType.ALL || loseType == LoseType.COLOR) {
permanent.getColor(game).setBlack(false);
permanent.getColor(game).setGreen(false);
permanent.getColor(game).setBlue(false);
@ -124,29 +124,29 @@ public class BecomesCreatureAttachedEffect extends ContinuousEffectImpl {
}
}
break;
case AbilityAddingRemovingEffects_6:
if (sublayer == SubLayer.NA) {
switch (loseType) {
case ALL:
case ALL_BUT_COLOR:
case ABILITIES:
case ABILITIES_AND_PT:
case ABILITIES_SUBTYPE_AND_PT:
case ABILITIES_SUBTYPE:
permanent.removeAllAbilities(source.getSourceId(), game);
break;
}
for (Ability ability : token.getAbilities()) {
permanent.addAbility(ability, source.getSourceId(), game);
}
}
break;
case PTChangingEffects_7:
if (sublayer == SubLayer.SetPT_7b) {
permanent.getPower().setValue(token.getPower().getValue());
permanent.getToughness().setValue(token.getToughness().getValue());
break;
}
break;
}
}
return true;

View file

@ -31,10 +31,10 @@ import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.keyword.FlyingAbility;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
/**
@ -43,34 +43,36 @@ import mage.game.permanent.token.Token;
public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements SourceEffect {
protected Token token;
protected String type;
protected String theyAreStillType;
protected boolean losePreviousTypes;
protected DynamicValue power = null;
protected DynamicValue toughness = null;
public BecomesCreatureSourceEffect(Token token, String type, Duration duration) {
this(token, type, duration, false, false);
public BecomesCreatureSourceEffect(Token token, String theyAreStillType, Duration duration) {
this(token, theyAreStillType, duration, false, false);
}
public BecomesCreatureSourceEffect(Token token, String type, Duration duration, boolean losePreviousTypes, boolean characterDefining) {
this(token, type, duration, losePreviousTypes, characterDefining, null, null);
public BecomesCreatureSourceEffect(Token token, String theyAreStillType, Duration duration, boolean losePreviousTypes, boolean characterDefining) {
this(token, theyAreStillType, duration, losePreviousTypes, characterDefining, null, null);
}
public BecomesCreatureSourceEffect(Token token, String type, Duration duration, boolean losePreviousTypes, boolean characterDefining, DynamicValue power, DynamicValue toughness) {
public BecomesCreatureSourceEffect(Token token, String theyAreStillType, Duration duration, boolean losePreviousTypes, boolean characterDefining, DynamicValue power, DynamicValue toughness) {
super(duration, Outcome.BecomeCreature);
this.characterDefining = characterDefining;
this.token = token;
this.type = type;
this.theyAreStillType = theyAreStillType;
this.losePreviousTypes = losePreviousTypes;
this.power = power;
this.toughness = toughness;
setText();
this.addDependencyType(DependencyType.BecomeCreature);
}
public BecomesCreatureSourceEffect(final BecomesCreatureSourceEffect effect) {
super(effect);
this.token = effect.token.copy();
this.type = effect.type;
this.theyAreStillType = effect.theyAreStillType;
this.losePreviousTypes = effect.losePreviousTypes;
if (effect.power != null) {
this.power = effect.power.copy();
@ -108,10 +110,11 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
if (losePreviousTypes) {
permanent.getCardType().clear();
}
for (CardType t : token.getCardType()) {
permanent.addCardType(t);
for (CardType cardType : token.getCardType()) {
permanent.addCardType(cardType);
}
if (type != null && type.isEmpty() || type == null && permanent.isLand()) {
if (theyAreStillType != null && theyAreStillType.isEmpty() || theyAreStillType == null && permanent.isLand()) {
permanent.getSubtype(game).retainAll(SubType.getLandTypes(false));
}
if (!token.getSubtype(game).isEmpty()) {
@ -120,6 +123,7 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
permanent.setIsAllCreatureTypes(token.isAllCreatureTypes());
}
break;
case ColorChangingEffects_5:
if (sublayer == SubLayer.NA) {
if (token.getColor(game).hasColor()) {
@ -127,19 +131,20 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
}
}
break;
case AbilityAddingRemovingEffects_6:
if (sublayer == SubLayer.NA) {
for (Ability ability : token.getAbilities()) {
permanent.addAbility(ability, source.getSourceId(), game);
}
}
break;
case PTChangingEffects_7:
if ((sublayer == SubLayer.CharacteristicDefining_7a && isCharacterDefining())
|| (sublayer == SubLayer.SetPT_7b && !isCharacterDefining())) {
if (power != null) {
permanent.getPower().setValue(power.calculate(game, source, this));
permanent.getPower().setValue(power.calculate(game, source, this)); // check all other becomes to use calculate?
} else if (token.getPower() != null) {
permanent.getPower().setValue(token.getPower().getValue());
}
@ -149,11 +154,15 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
permanent.getToughness().setValue(token.getToughness().getValue());
}
}
break;
}
return true;
} else if (duration == Duration.Custom) {
this.discard();
}
return false;
}
@ -163,8 +172,8 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
}
private void setText() {
if (type != null && !type.isEmpty()) {
staticText = duration.toString() + " {this} becomes a " + token.getDescription() + " that's still a " + this.type;
if (theyAreStillType != null && !theyAreStillType.isEmpty()) {
staticText = duration.toString() + " {this} becomes a " + token.getDescription() + " that's still a " + this.theyAreStillType;
} else {
staticText = duration.toString() + " {this} becomes a " + token.getDescription();
}

View file

@ -39,6 +39,9 @@ import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -50,6 +53,7 @@ public class ExchangeControlTargetEffect extends ContinuousEffectImpl {
private String rule;
private boolean withSource;
private boolean withSecondTarget;
private boolean destroyAttachedAuras;
private Map<UUID, Integer> zoneChangeCounter = new HashMap<>();
private Map<UUID, UUID> lockedControllers = new HashMap<>();
@ -62,9 +66,14 @@ public class ExchangeControlTargetEffect extends ContinuousEffectImpl {
}
public ExchangeControlTargetEffect(Duration duration, String rule, boolean withSource, boolean withSecondTarget) {
this(duration, rule, withSource, withSecondTarget, false);
}
public ExchangeControlTargetEffect(Duration duration, String rule, boolean withSource, boolean withSecondTarget, boolean destroyAttachedAuras) {
super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);
this.withSource = withSource;
this.withSecondTarget = withSecondTarget;
this.destroyAttachedAuras = destroyAttachedAuras;
this.rule = rule;
}
@ -73,6 +82,7 @@ public class ExchangeControlTargetEffect extends ContinuousEffectImpl {
this.rule = effect.rule;
this.withSource = effect.withSource;
this.withSecondTarget = effect.withSecondTarget;
this.destroyAttachedAuras = effect.destroyAttachedAuras;
this.lockedControllers = new HashMap<>(effect.lockedControllers);
this.zoneChangeCounter = new HashMap<>(effect.zoneChangeCounter);
}
@ -141,6 +151,16 @@ public class ExchangeControlTargetEffect extends ContinuousEffectImpl {
}
permanent.changeControllerId(lockedControllers.get(permanent.getId()), game);
permanent.getAbilities().setControllerId(lockedControllers.get(permanent.getId()));
if (destroyAttachedAuras) {
FilterPermanent filter = new FilterPermanent();
filter.add(new SubtypePredicate(SubType.AURA));
for (UUID attachmentId : new HashSet<>(permanent.getAttachments())) {
Permanent attachment = game.getPermanent(attachmentId);
if (attachment != null && filter.match(attachment, game)) {
attachment.destroy(source.getSourceId(), game, false);
}
}
}
}
if (!toDelete.isEmpty()) {
for (UUID uuid : toDelete) {

View file

@ -92,6 +92,13 @@ public class GainAbilitySourceEffect extends ContinuousEffectImpl implements Sou
@Override
public void init(Ability source, Game game) {
super.init(source, game);
if (!onCard && Duration.WhileOnBattlefield != duration) {
// If source permanent is no longer onto battlefield discard the effect
if (source.getSourcePermanentIfItStillExists(game) == null) {
discard();
return;
}
}
if (affectedObjectsSet) {
Permanent permanent = game.getPermanentEntering(source.getSourceId());
if (permanent != null) {

View file

@ -12,38 +12,50 @@ import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author Noahsark
*/
public class LoseAbilitySourceEffect extends ContinuousEffectImpl{
public class LoseAbilitySourceEffect extends ContinuousEffectImpl {
protected Ability ability;
public LoseAbilitySourceEffect(Ability ability){
public LoseAbilitySourceEffect(Ability ability) {
this(ability, Duration.WhileOnBattlefield);
}
public LoseAbilitySourceEffect(Ability ability, Duration duration){
public LoseAbilitySourceEffect(Ability ability, Duration duration) {
super(duration, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.LoseAbility);
this.ability = ability;
staticText = "{this} loses " + ability.getRule() + ' ' + duration.toString();
}
public LoseAbilitySourceEffect(final LoseAbilitySourceEffect effect){
public LoseAbilitySourceEffect(final LoseAbilitySourceEffect effect) {
super(effect);
this.ability = effect.ability.copy();
}
@Override
public LoseAbilitySourceEffect copy(){
public LoseAbilitySourceEffect copy() {
return new LoseAbilitySourceEffect(this);
}
@Override
public boolean apply(Game game, Ability source){
public void init(Ability source, Game game) {
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
if (duration.isOnlyValidIfNoZoneChange()) {
// If source permanent is no longer onto battlefield discard the effect
if (source.getSourcePermanentIfItStillExists(game) == null) {
discard();
}
}
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null){
if (permanent != null) {
// 112.10
while (permanent.getAbilities().remove(ability)) {

View file

@ -69,6 +69,17 @@ public class LoseCreatureTypeSourceEffect extends ContinuousEffectImpl implement
return new LoseCreatureTypeSourceEffect(this);
}
@Override
public void init(Ability source, Game game) {
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
if (duration.isOnlyValidIfNoZoneChange()) {
// If source permanent is no longer onto battlefield discard the effect
if (source.getSourcePermanentIfItStillExists(game) == null) {
discard();
}
}
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
if (dynamicValue.calculate(game, source, this) >= lessThan) {

View file

@ -1,16 +1,16 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@ -20,19 +20,19 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common.continuous;
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.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -55,14 +55,29 @@ public class SwitchPowerToughnessSourceEffect extends ContinuousEffectImpl {
return new SwitchPowerToughnessSourceEffect(this);
}
@Override
public void init(Ability source, Game game) {
super.init(source, game); //To change body of generated methods, choose Tools | Templates.
if (duration.isOnlyValidIfNoZoneChange()) {
// If source permanent is no longer onto battlefield discard the effect
if (source.getSourcePermanentIfItStillExists(game) == null) {
discard();
}
}
}
@Override
public boolean apply(Game game, Ability source) {
Permanent target = game.getPermanent(source.getSourceId());
if (target != null) {
int power = target.getPower().getValue();
target.getPower().setValue(target.getToughness().getValue());
target.getToughness().setValue(power);
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
if (sourcePermanent != null) {
int power = sourcePermanent.getPower().getValue();
sourcePermanent.getPower().setValue(sourcePermanent.getToughness().getValue());
sourcePermanent.getToughness().setValue(power);
return true;
} else {
if (duration.isOnlyValidIfNoZoneChange()) {
discard();
}
}
return false;
}

View file

@ -53,6 +53,7 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
private FilterCard filter;
private int amount;
private final boolean upTo;
private boolean onlyControlled;
public SpellsCostReductionAllEffect(int amount) {
this(new FilterCard("Spells"), amount);
@ -63,19 +64,24 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
}
public SpellsCostReductionAllEffect(FilterCard filter, int amount, boolean upTo) {
this(filter, amount, upTo, false);
}
public SpellsCostReductionAllEffect(FilterCard filter, int amount, boolean upTo, boolean onlyControlled) {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
this.filter = filter;
this.amount = amount;
this.upTo = upTo;
this.onlyControlled = onlyControlled;
this.staticText = filter.getMessage() + " cost " + (upTo ? "up to " : "") + '{' + amount + "} less to cast";
}
protected SpellsCostReductionAllEffect(SpellsCostReductionAllEffect effect) {
protected SpellsCostReductionAllEffect(final SpellsCostReductionAllEffect effect) {
super(effect);
this.filter = effect.filter;
this.amount = effect.amount;
this.upTo = effect.upTo;
this.onlyControlled = effect.onlyControlled;
}
@Override
@ -136,6 +142,9 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (onlyControlled && abilityToModify.getControllerId().equals(source.getControllerId())) {
return false;
}
if (abilityToModify instanceof SpellAbility) {
Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId());
if (spell != null) {

View file

@ -19,7 +19,11 @@ import mage.game.Game;
public class SpellsCostReductionAllOfChosenSubtypeEffect extends SpellsCostReductionAllEffect {
public SpellsCostReductionAllOfChosenSubtypeEffect(FilterCard filter, int amount) {
super(filter, amount);
this(filter, amount, false);
}
public SpellsCostReductionAllOfChosenSubtypeEffect(FilterCard filter, int amount, boolean onlyControlled) {
super(filter, amount, false, onlyControlled);
}
public SpellsCostReductionAllOfChosenSubtypeEffect(final SpellsCostReductionAllOfChosenSubtypeEffect effect) {

View file

@ -39,7 +39,7 @@ import mage.game.permanent.Permanent;
* @author TheElk801
*/
public class RemoveAllCountersSourceEffect extends OneShotEffect {
private final CounterType counterType;
public RemoveAllCountersSourceEffect(CounterType counterType) {
@ -55,13 +55,13 @@ public class RemoveAllCountersSourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if(permanent != null) {
int count = permanent.getCounters(game).getCount(counterType);
permanent.removeCounters(counterType.getName(), count, game);
return true;
}
return false;
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent != null) {
int count = permanent.getCounters(game).getCount(counterType);
permanent.removeCounters(counterType.getName(), count, game);
return true;
}
return false;
}
@Override

View file

@ -56,7 +56,7 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent != null) {
int toRemove = Math.min(counter.getCount(), permanent.getCounters(game).getCount(counter.getName()));
if (toRemove > 0) {
@ -67,18 +67,20 @@ public class RemoveCounterSourceEffect extends OneShotEffect {
}
return true;
}
Card card = game.getCard(source.getSourceId());
if (card != null) {
int toRemove = Math.min(counter.getCount(), card.getCounters(game).getCount(counter.getName()));
if (toRemove > 0) {
card.removeCounters(counter.getName(), toRemove, game);
if (!game.isSimulation()) {
game.informPlayers("Removed " + toRemove + ' ' + counter.getName()
+ " counter from " + card.getLogName()
+ " (" + card.getCounters(game).getCount(counter.getName()) + " left)");
if (!(source.getSourceObject(game) instanceof Permanent)) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
int toRemove = Math.min(counter.getCount(), card.getCounters(game).getCount(counter.getName()));
if (toRemove > 0) {
card.removeCounters(counter.getName(), toRemove, game);
if (!game.isSimulation()) {
game.informPlayers("Removed " + toRemove + ' ' + counter.getName()
+ " counter from " + card.getLogName()
+ " (" + card.getCounters(game).getCount(counter.getName()) + " left)");
}
}
return true;
}
return true;
}
return false;
}

View file

@ -53,7 +53,7 @@ public class SweepEffect extends OneShotEffect {
public SweepEffect(SubType sweepSubtype) {
super(Outcome.Benefit);
this.sweepSubtype = sweepSubtype;
this.staticText = "<i>Sweep</i> - Return any number of " + sweepSubtype + (sweepSubtype.getDescription().endsWith("s") ? "" : "s") + " you control to their owner's hand";
this.staticText = "<i>Sweep</i> &mdash; Return any number of " + sweepSubtype + (sweepSubtype.getDescription().endsWith("s") ? "" : "s") + " you control to their owner's hand";
}
public SweepEffect(final SweepEffect effect) {

View file

@ -0,0 +1,29 @@
/*
* 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 mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.mana.builder.ConditionalManaBuilder;
/**
*
* @author LevelX2
*/
public class AddConditionalColorlessManaEffect extends AddConditionalManaEffect {
public AddConditionalColorlessManaEffect(int amount, ConditionalManaBuilder manaBuilder) {
super(Mana.ColorlessMana(amount), manaBuilder);
}
public AddConditionalColorlessManaEffect(final AddConditionalColorlessManaEffect effect) {
super(effect);
}
@Override
public AddConditionalColorlessManaEffect copy() {
return new AddConditionalColorlessManaEffect(this);
}
}

View file

@ -3,10 +3,11 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.game.Game;
import mage.players.Player;
@ -49,7 +50,11 @@ public class AddConditionalManaEffect extends ManaEffect {
}
@Override
public Mana getMana(Game game, Ability source) {
public Mana produceMana(boolean netMana, Game game, Ability source) {
return manaBuilder.setMana(mana, source, game).build();
}
public Mana getMana() {
return mana;
}
}

View file

@ -25,12 +25,14 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import mage.ConditionalMana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.choices.ChoiceColor;
import mage.game.Game;
@ -63,9 +65,9 @@ public class AddConditionalManaOfAnyColorEffect extends ManaEffect {
staticText = "Add "
+ (amount instanceof StaticValue ? (CardUtil.numberToText(((StaticValue) amount).toString())) : "")
+ " mana "
+ (oneChoice ? "of any"
+ (amount instanceof StaticValue && (((StaticValue) amount).toString()).equals("1") ? "" : " one")
+ " color" : "in any combination of colors")
+ (oneChoice || (amount instanceof StaticValue && (((StaticValue) amount).toString()).equals("1"))
? "of any" + (amount instanceof StaticValue && (((StaticValue) amount).toString()).equals("1") ? "" : " one") + " color"
: "in any combination of colors")
+ ". " + manaBuilder.getRule();
}
@ -84,39 +86,44 @@ public class AddConditionalManaOfAnyColorEffect extends ManaEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
if (controller != null) {
checkToFirePossibleEvents(getMana(game, source), game, source);
controller.getManaPool().addMana(getMana(game, source), game, source);
return true;
}
return false;
}
@Override
public Mana produceMana(boolean netMana, Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return null;
}
ConditionalMana mana = null;
int value = amount.calculate(game, source, this);
boolean result = false;
ChoiceColor choice = new ChoiceColor(true);
for (int i = 0; i < value; i++) {
controller.choose(outcome, choice, game);
if (choice.getChoice() == null) {
return false;
controller.choose(outcome, choice, game);
}
Mana mana = choice.getMana(1);
if (mana != null) {
mana = manaBuilder.setMana(mana, source, game).build();
if (choice.getChoice() == null) {
return null;
}
if (mana != null) {
checkToFirePossibleEvents(mana, game, source);
controller.getManaPool().addMana(mana, game, source);
result = true;
}
if (!oneChoice) {
if (oneChoice) {
mana = new ConditionalMana(manaBuilder.setMana(choice.getMana(value), source, game).build());
break;
} else {
if (mana == null) {
mana = new ConditionalMana(manaBuilder.setMana(choice.getMana(1), source, game).build());
} else {
mana.add(choice.getMana(1));
}
choice.clearChoice();
}
}
return result;
}
return mana;
@Override
public Mana getMana(Game game, Ability source) {
//TODO: TAP_FOR_MANA Event does not support currently to get an amount > 1 of conditional mana
return null;
}
}

View file

@ -25,10 +25,13 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import java.util.ArrayList;
import java.util.List;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.choices.ChoiceColor;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -53,14 +56,12 @@ public class AddManaAnyColorAttachedControllerEffect extends ManaEffect {
public boolean apply(Game game, Ability source) {
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment != null) {
Permanent land = game.getPermanent(enchantment.getAttachedTo());
if (land != null) {
Player player = game.getPlayer(land.getControllerId());
ChoiceColor choice = new ChoiceColor();
if (player != null && player.choose(outcome, choice, game)) {
Mana mana = choice.getMana(1);
checkToFirePossibleEvents(mana, game, source);
player.getManaPool().addMana(mana, game, source);
Permanent permanentattachedTo = game.getPermanent(enchantment.getAttachedTo());
if (permanentattachedTo != null) {
Player player = game.getPlayer(permanentattachedTo.getControllerId());
if (player != null) {
checkToFirePossibleEvents(getMana(game, source), game, source);
player.getManaPool().addMana(getMana(game, source), game, source);
return true;
}
}
@ -74,8 +75,30 @@ public class AddManaAnyColorAttachedControllerEffect extends ManaEffect {
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
public Mana produceMana(boolean netMana, Game game, Ability source) {
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment != null) {
Permanent land = game.getPermanent(enchantment.getAttachedTo());
if (land != null) {
Player player = game.getPlayer(land.getControllerId());
ChoiceColor choice = new ChoiceColor();
if (player != null && player.choose(outcome, choice, game)) {
return choice.getMana(1);
}
}
}
return new Mana();
}
@Override
public List<Mana> getNetMana(Game game, Ability source) {
ArrayList<Mana> netMana = new ArrayList<>();
netMana.add(Mana.GreenMana(1));
netMana.add(Mana.WhiteMana(1));
netMana.add(Mana.BlueMana(1));
netMana.add(Mana.RedMana(1));
netMana.add(Mana.BlackMana(1));
return netMana;
}
}

View file

@ -0,0 +1,54 @@
/*
* 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 mage.abilities.effects.mana;
import mage.Mana;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.constants.ColoredManaSymbol;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author LevelX2
*/
public class AddManaChosenColorEffect extends ManaEffect {
public AddManaChosenColorEffect() {
super();
staticText = "Add one mana of the chosen color";
}
public AddManaChosenColorEffect(final AddManaChosenColorEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
player.getManaPool().addMana(getMana(game, source), game, source);
}
return true;
}
@Override
public Mana produceMana(boolean netMana, Game game, Ability source) {
ObjectColor color = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color");
if (color != null) {
return new Mana(ColoredManaSymbol.lookup(color.toString().charAt(0)));
} else {
return null;
}
}
@Override
public AddManaChosenColorEffect copy() {
return new AddManaChosenColorEffect(this);
}
}

View file

@ -25,14 +25,16 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.ManaEffect;
import mage.constants.ColoredManaSymbol;
import mage.game.Game;
import mage.players.Player;
@ -90,6 +92,17 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
checkToFirePossibleEvents(getMana(game, source), game, source);
player.getManaPool().addMana(getMana(game, source), game, source);
return true;
}
return false;
}
@Override
public Mana produceMana(boolean netMana, Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
Mana mana = new Mana();
@ -111,16 +124,17 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
}
}
}
checkToFirePossibleEvents(mana, game, source);
player.getManaPool().addMana(mana, game, source);
return true;
return mana;
}
return false;
return null;
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
public List<Mana> getNetMana(Game game, Ability source) {
ArrayList<Mana> netMana = new ArrayList<>();
netMana.add(new Mana(0, 0, 0, 0, 0, 0, amount.calculate(game, source, this), 0));
return netMana;
}
private String setText() {

View file

@ -25,7 +25,7 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;
@ -91,7 +91,7 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect {
}
@Override
public Mana getMana() {
public Mana getManaTemplate() {
return new Mana(0, 0, 0, 0, 0, 0, amount, 0);
}

View file

@ -25,10 +25,11 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.choices.Choice;
import mage.choices.ChoiceColor;
import mage.game.Game;
@ -58,6 +59,24 @@ public class AddManaOfAnyTypeProducedEffect extends ManaEffect {
if (targetController == null) {
return false;
}
checkToFirePossibleEvents(getMana(game, source), game, source);
targetController.getManaPool().addMana(getMana(game, source), game, source);
return true;
}
return false;
}
@Override
public Mana produceMana(boolean netMana, Game game, Ability source) {
if (netMana) {
return null;
}
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
Player targetController = game.getPlayer(permanent.getControllerId());
if (targetController == null) {
return null;
}
Mana types = (Mana) this.getValue("mana");
Choice choice = new ChoiceColor(true);
choice.getChoices().clear();
@ -80,15 +99,16 @@ public class AddManaOfAnyTypeProducedEffect extends ManaEffect {
if (types.getColorless() > 0) {
choice.getChoices().add("Colorless");
}
Mana newMana = new Mana();
if (!choice.getChoices().isEmpty()) {
if (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next());
} else {
if (!targetController.choose(outcome, choice, game)) {
return false;
return null;
}
}
Mana newMana = new Mana();
switch (choice.getChoice()) {
case "Black":
newMana.setBlack(1);
@ -109,13 +129,10 @@ public class AddManaOfAnyTypeProducedEffect extends ManaEffect {
newMana.setColorless(1);
break;
}
checkToFirePossibleEvents(newMana, game, source);
targetController.getManaPool().addMana(newMana, game, source);
}
return true;
return newMana;
}
return false;
return null;
}
@Override
@ -123,8 +140,4 @@ public class AddManaOfAnyTypeProducedEffect extends ManaEffect {
return new AddManaOfAnyTypeProducedEffect(this);
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
}
}

View file

@ -4,7 +4,7 @@
* and open the template in the editor.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;

View file

@ -3,11 +3,11 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.game.Game;
import mage.players.Player;
@ -15,28 +15,30 @@ import mage.players.Player;
*
* @author LevelX2
*/
public class AddManaToManaPoolTargetControllerEffect extends ManaEffect {
protected Mana mana;
protected boolean emptyOnlyOnTurnsEnd;
public AddManaToManaPoolTargetControllerEffect(Mana mana, String textManaPoolOwner) {
this(mana, textManaPoolOwner, false);
}
/**
* Adds mana to the mana pool of target pointer player
*
*
* @param mana mana that will be added to the pool
* @param textManaPoolOwner text that references to the mana pool owner (e.g. "damaged player's")
* @param emptyOnTurnsEnd if set, the mana will empty only on end of turnstep
*
*/
* @param textManaPoolOwner text that references to the mana pool owner
* (e.g. "damaged player's")
* @param emptyOnTurnsEnd if set, the mana will empty only on end of
* turnstep
*
*/
public AddManaToManaPoolTargetControllerEffect(Mana mana, String textManaPoolOwner, boolean emptyOnTurnsEnd) {
super();
this.mana = mana;
this.emptyOnlyOnTurnsEnd = emptyOnTurnsEnd;
this.staticText = (textManaPoolOwner.equals("their")?"that player adds ":"add ") + mana.toString() + " to " + textManaPoolOwner + " mana pool";
this.staticText = (textManaPoolOwner.equals("their") ? "that player adds " : "add ") + mana.toString() + " to " + textManaPoolOwner + " mana pool";
}
public AddManaToManaPoolTargetControllerEffect(final AddManaToManaPoolTargetControllerEffect effect) {
@ -54,15 +56,17 @@ public class AddManaToManaPoolTargetControllerEffect extends ManaEffect {
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null) {
player.getManaPool().addMana(mana, game, source, emptyOnlyOnTurnsEnd);
player.getManaPool().addMana(getMana(game, source), game, source, emptyOnlyOnTurnsEnd);
return true;
}
return false;
}
@Override
public Mana getMana(Game game, Ability source) {
return mana;
public Mana produceMana(boolean netMana, Game game, Ability source) {
if (netMana) {
return null;
}
return mana.copy();
}
}

View file

@ -1,29 +1,31 @@
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import mage.ConditionalMana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.game.Game;
public class BasicManaEffect extends ManaEffect {
protected Mana mana;
protected Mana manaTemplate;
public BasicManaEffect(Mana mana) {
super();
this.mana = mana;
this.manaTemplate = mana;
staticText = "add " + mana.toString();
}
public BasicManaEffect(ConditionalMana conditionalMana) {
super();
this.mana = conditionalMana;
staticText = "add " + mana.toString() + " " + conditionalMana.getDescription();
this.manaTemplate = conditionalMana;
staticText = "add " + manaTemplate.toString() + " " + conditionalMana.getDescription();
}
public BasicManaEffect(final BasicManaEffect effect) {
super(effect);
this.mana = effect.mana.copy();
this.manaTemplate = effect.manaTemplate.copy();
}
@Override
@ -33,16 +35,17 @@ public class BasicManaEffect extends ManaEffect {
@Override
public boolean apply(Game game, Ability source) {
game.getPlayer(source.getControllerId()).getManaPool().addMana(mana, game, source);
game.getPlayer(source.getControllerId()).getManaPool().addMana(getMana(game, source), game, source);
return true;
}
public Mana getMana() {
return mana;
public Mana getManaTemplate() {
return manaTemplate;
}
@Override
public Mana getMana(Game game, Ability source) {
return mana;
public Mana produceMana(boolean netMana, Game game, Ability source) {
return manaTemplate.copy();
}
}

View file

@ -3,14 +3,17 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.costs.Cost;
import mage.abilities.effects.common.ManaEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
@ -69,6 +72,24 @@ public class DoUnlessAnyPlayerPaysManaEffect extends ManaEffect {
return false;
}
@Override
public List<Mana> getNetMana(Game game, Ability source) {
if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game)) {
return manaEffect.getNetMana(game, source);
}
return new ArrayList<>();
}
@Override
public Mana getMana(Game game, Ability source) {
return manaEffect.getMana(game, source);
}
@Override
public Mana produceMana(boolean netMana, Game game, Ability source) {
return manaEffect.produceMana(netMana, game, source);
}
protected Player getPayingPlayer(Game game, Ability source) {
return game.getPlayer(source.getControllerId());
}
@ -81,11 +102,6 @@ public class DoUnlessAnyPlayerPaysManaEffect extends ManaEffect {
return manaEffect.getText(mode) + " unless any player pays " + cost.getText();
}
@Override
public Mana getMana(Game game, Ability source) {
return manaEffect.getMana(game, source);
}
@Override
public ManaEffect copy() {
return new DoUnlessAnyPlayerPaysManaEffect(this);

View file

@ -25,7 +25,7 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;
@ -64,10 +64,10 @@ public class DynamicManaEffect extends BasicManaEffect {
* @param mana
* @param amount
* @param text
* @param oneChoice is all mana from the same colour or if false the player
* can choose different colours
* @param oneChoice is all manaTemplate from the same colour or if false the
* player can choose different colours
* @param netAmount a dynamic value that calculates the possible available
* mana (e.g. if you have to pay by removing counters from source)
* manaTemplate (e.g. if you have to pay by removing counters from source)
*/
public DynamicManaEffect(Mana mana, DynamicValue amount, String text, boolean oneChoice, DynamicValue netAmount) {
super(mana);
@ -96,9 +96,8 @@ public class DynamicManaEffect extends BasicManaEffect {
@Override
public boolean apply(Game game, Ability source) {
Mana computedMana = computeMana(false, game, source);
checkToFirePossibleEvents(computedMana, game, source);
game.getPlayer(source.getControllerId()).getManaPool().addMana(computedMana, game, source);
checkToFirePossibleEvents(getMana(game, source), game, source);
game.getPlayer(source.getControllerId()).getManaPool().addMana(getMana(game, source), game, source);
return true;
}
@ -111,33 +110,29 @@ public class DynamicManaEffect extends BasicManaEffect {
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
}
public Mana computeMana(boolean netMana, Game game, Ability source) {
public Mana produceMana(boolean netMana, Game game, Ability source) {
Mana computedMana = new Mana();
int count;
if (netMana && netAmount != null) {
// calculate the maximum available mana
// calculate the maximum available manaTemplate
count = netAmount.calculate(game, source, this);
} else {
count = amount.calculate(game, source, this);
}
if (mana.getBlack() > 0) {
if (manaTemplate.getBlack() > 0) {
computedMana.setBlack(count);
} else if (mana.getBlue() > 0) {
} else if (manaTemplate.getBlue() > 0) {
computedMana.setBlue(count);
} else if (mana.getGreen() > 0) {
} else if (manaTemplate.getGreen() > 0) {
computedMana.setGreen(count);
} else if (mana.getRed() > 0) {
} else if (manaTemplate.getRed() > 0) {
computedMana.setRed(count);
} else if (mana.getWhite() > 0) {
} else if (manaTemplate.getWhite() > 0) {
computedMana.setWhite(count);
} else if (mana.getColorless() > 0) {
} else if (manaTemplate.getColorless() > 0) {
computedMana.setColorless(count);
} else if (mana.getAny() > 0) {
} else if (manaTemplate.getAny() > 0) {
if (netMana) {
computedMana.setAny(count);
} else {

View file

@ -72,7 +72,7 @@ public class BattalionAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return new StringBuilder("<i>Battalion</i> - Whenever {this} and at least two other creatures attack, ").append(super.getRule()).toString() ;
return new StringBuilder("<i>Battalion</i> &mdash; Whenever {this} and at least two other creatures attack, ").append(super.getRule()).toString() ;
}
}

View file

@ -65,7 +65,7 @@ public class BloodrushAbility extends ActivatedAbilityImpl {
@Override
public String getRule() {
StringBuilder sb = new StringBuilder("<i>Bloodrush</i> - ");
StringBuilder sb = new StringBuilder("<i>Bloodrush</i> &mdash; ");
sb.append(super.getRule());
return sb.toString();
}

View file

@ -60,7 +60,7 @@ public class ChannelAbility extends ActivatedAbilityImpl {
@Override
public String getRule() {
StringBuilder sb = new StringBuilder("<i>Channel</i> - ");
StringBuilder sb = new StringBuilder("<i>Channel</i> &mdash; ");
sb.append(super.getRule());
if(this.timing == TimingRule.SORCERY) {
sb.append(" Activate this ability only any time you could cast a sorcery.");

View file

@ -103,6 +103,6 @@ public class HeroicAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return new StringBuilder("<i>Heroic</i> - Whenever you cast a spell that targets {this}, ").append(super.getRule()).toString();
return new StringBuilder("<i>Heroic</i> &mdash; Whenever you cast a spell that targets {this}, ").append(super.getRule()).toString();
}
}

View file

@ -71,6 +71,6 @@ public class InspiredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "<i>Inspired</i> - Whenever {this} becomes untapped, " + super.getRule();
return "<i>Inspired</i> &mdash; Whenever {this} becomes untapped, " + super.getRule();
}
}

View file

@ -27,6 +27,8 @@
*/
package mage.abilities.keyword;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.ObjectColor;
@ -53,6 +55,7 @@ public class ProtectionAbility extends StaticAbility {
protected Filter filter;
protected boolean removeAuras;
protected static List<ObjectColor> colors = new ArrayList<>();
protected UUID auraIdNotToBeRemoved; // defines an Aura objectId that will not be removed from this protection ability
public ProtectionAbility(Filter filter) {
@ -72,12 +75,15 @@ public class ProtectionAbility extends StaticAbility {
public static ProtectionAbility from(ObjectColor color) {
FilterObject filter = new FilterObject(color.getDescription());
filter.add(new ColorPredicate(color));
colors.add(color);
return new ProtectionAbility(filter);
}
public static ProtectionAbility from(ObjectColor color1, ObjectColor color2) {
FilterObject filter = new FilterObject(color1.getDescription() + " and from " + color2.getDescription());
filter.add(Predicates.or(new ColorPredicate(color1), new ColorPredicate(color2)));
colors.add(color1);
colors.add(color2);
return new ProtectionAbility(filter);
}
@ -140,6 +146,8 @@ public class ProtectionAbility extends StaticAbility {
return removeAuras;
}
public List<ObjectColor> getColors() { return colors; }
public UUID getAuraIdNotToBeRemoved() {
return auraIdNotToBeRemoved;
}

View file

@ -35,7 +35,6 @@ import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.ExileSourceEffect;
import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TimingRule;
@ -63,9 +62,8 @@ import mage.game.events.ZoneChangeEvent;
public class UnearthAbility extends ActivatedAbilityImpl {
public UnearthAbility(ManaCosts costs) {
super(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), costs);
super(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, true, true), costs);
this.timing = TimingRule.SORCERY;
this.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom));
this.addEffect(new CreateDelayedTriggeredAbilityEffect(new UnearthDelayedTriggeredAbility()));
this.addEffect(new UnearthLeavesBattlefieldEffect());
}

View file

@ -29,8 +29,8 @@ package mage.abilities.mana;
import mage.abilities.condition.Condition;
import mage.abilities.costs.Cost;
import mage.abilities.effects.common.AddConditionalColorlessManaEffect;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.mana.AddConditionalColorlessManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.constants.Zone;
import mage.game.Game;
@ -38,7 +38,7 @@ public class ActivateIfConditionManaAbility extends ActivatedManaAbilityImpl {
public ActivateIfConditionManaAbility(Zone zone, BasicManaEffect effect, Cost cost, Condition condition) {
super(zone, effect, cost);
this.netMana.add(effect.getMana());
this.netMana.add(effect.getManaTemplate());
this.condition = condition;
}

View file

@ -29,8 +29,8 @@ package mage.abilities.mana;
import mage.Mana;
import mage.abilities.costs.Cost;
import mage.abilities.effects.common.AddManaOfAnyColorEffect;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.constants.Zone;
import mage.game.Game;
@ -42,7 +42,7 @@ public class ActivateOncePerTurnManaAbility extends ActivatedManaAbilityImpl {
public ActivateOncePerTurnManaAbility(Zone zone, BasicManaEffect effect, Cost cost) {
super(zone, effect, cost);
this.netMana.add(effect.getMana());
this.netMana.add(effect.getManaTemplate());
this.maxActivationsPerTurn = 1;
}

View file

@ -33,6 +33,7 @@ import java.util.UUID;
import mage.Mana;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.Cost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ManaEffect;
import mage.constants.AbilityType;
import mage.constants.AsThoughEffectType;
@ -95,6 +96,13 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
*/
@Override
public List<Mana> getNetMana(Game game) {
if (netMana.isEmpty()) {
for (Effect effect : getEffects()) {
if (effect instanceof ManaEffect) {
netMana.addAll(((ManaEffect) effect).getNetMana(game, this));
}
}
}
return netMana;
}

View file

@ -105,6 +105,18 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
checkToFirePossibleEvents(getMana(game, source), game, source);
controller.getManaPool().addMana(getMana(game, source), game, source);
return true;
}
return false;
}
@Override
public Mana produceMana(boolean netMana, Game game, Ability source) {
Mana mana = new Mana();
Mana types = getManaTypes(game, source);
Choice choice = new ChoiceColor(true);
choice.getChoices().clear();
@ -143,12 +155,11 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
if (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next());
} else {
if (!player.choose(outcome, choice, game)) {
return false;
if (player == null || !player.choose(outcome, choice, game)) {
return null;
}
}
if (choice.getChoice() != null) {
Mana mana = new Mana();
switch (choice.getChoice()) {
case "Black":
mana.setBlack(1);
@ -169,16 +180,9 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
mana.setColorless(1);
break;
}
checkToFirePossibleEvents(mana, game, source);
player.getManaPool().addMana(mana, game, source);
}
}
return true;
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
return mana;
}
private Mana getManaTypes(Game game, Ability source) {
@ -205,6 +209,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
return types;
}
@Override
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netManas = new ArrayList<>();
Mana types = getManaTypes(game, source);

View file

@ -30,7 +30,7 @@ package mage.abilities.mana;
import mage.Mana;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.AddManaOfAnyColorEffect;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.constants.Zone;
public class AnyColorManaAbility extends ActivatedManaAbilityImpl {

View file

@ -82,6 +82,18 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
checkToFirePossibleEvents(getMana(game, source), game, source);
controller.getManaPool().addMana(getMana(game, source), game, source);
return true;
}
return false;
}
@Override
public Mana produceMana(boolean netMana, Game game, Ability source) {
Mana mana = new Mana();
Mana types = getManaTypes(game, source);
Choice choice = new ChoiceColor(true);
choice.getChoices().clear();
@ -121,11 +133,11 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
choice.setChoice(choice.getChoices().iterator().next());
} else {
if (!player.choose(outcome, choice, game)) {
return false;
return mana;
}
}
if (choice.getChoice() != null) {
Mana mana = new Mana();
switch (choice.getChoice()) {
case "Black":
mana.setBlack(1);
@ -146,16 +158,9 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
mana.setColorless(1);
break;
}
checkToFirePossibleEvents(mana, game, source);
player.getManaPool().addMana(mana, game, source);
}
}
return true;
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
return mana;
}
private Mana getManaTypes(Game game, Ability source) {
@ -167,19 +172,19 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
return types;
}
inManaTypeCalculation = true;
ObjectColor permanentColor;
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
for (Permanent permanent : permanents) {
permanentColor = permanent.getColor(game);
if(permanentColor.isColorless())
if (permanentColor.isColorless()) {
types.add(Mana.ColorlessMana(1));
else{
} else {
List<ObjectColor> permanentColors = permanent.getColor(game).getColors();
for (ObjectColor color : permanentColors){
types.add(new Mana(color.getColoredManaSymbol()));
for (ObjectColor color : permanentColors) {
types.add(new Mana(color.getOneColoredManaSymbol()));
}
}
}
@ -187,6 +192,7 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
return types;
}
@Override
public List<Mana> getNetMana(Game game, Ability source) {
List<Mana> netManas = new ArrayList<>();
Mana types = getManaTypes(game, source);

View file

@ -29,7 +29,7 @@
package mage.abilities.mana;
import mage.Mana;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.constants.ColoredManaSymbol;
/**

View file

@ -29,7 +29,7 @@
package mage.abilities.mana;
import mage.Mana;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.constants.ColoredManaSymbol;
/**

View file

@ -28,7 +28,7 @@
package mage.abilities.mana;
import mage.Mana;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
/**
*

View file

@ -122,6 +122,18 @@ class CommanderIdentityManaEffect extends ManaEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
checkToFirePossibleEvents(getMana(game, source), game, source);
controller.getManaPool().addMana(getMana(game, source), game, source);
return true;
}
return false;
}
@Override
public Mana produceMana(boolean netMana, Game game, Ability source) {
Mana mana = new Mana();
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Choice choice = new ChoiceImpl();
@ -152,10 +164,10 @@ class CommanderIdentityManaEffect extends ManaEffect {
choice.setChoice(choice.getChoices().iterator().next());
} else {
if (!controller.choose(outcome, choice, game)) {
return false;
return mana;
}
}
Mana mana = new Mana();
switch (choice.getChoice()) {
case "Black":
mana.setBlack(1);
@ -173,16 +185,10 @@ class CommanderIdentityManaEffect extends ManaEffect {
mana.setWhite(1);
break;
}
checkToFirePossibleEvents(mana, game, source);
controller.getManaPool().addMana(mana, game, source);
return true;
}
}
return false;
return mana;
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
}
}

View file

@ -33,7 +33,7 @@ import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.AddConditionalManaOfAnyColorEffect;
import mage.abilities.effects.mana.AddConditionalManaOfAnyColorEffect;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.constants.Zone;
import mage.game.Game;

View file

@ -8,7 +8,7 @@ package mage.abilities.mana;
import mage.Mana;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.AddConditionalManaEffect;
import mage.abilities.effects.mana.AddConditionalManaEffect;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.constants.Zone;

View file

@ -8,7 +8,7 @@ package mage.abilities.mana;
import mage.Mana;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.AddConditionalColorlessManaEffect;
import mage.abilities.effects.mana.AddConditionalColorlessManaEffect;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.constants.Zone;

View file

@ -33,7 +33,7 @@ import mage.Mana;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.common.DynamicManaEffect;
import mage.abilities.effects.mana.DynamicManaEffect;
import mage.constants.Zone;
import mage.game.Game;
@ -111,7 +111,7 @@ public class DynamicManaAbility extends ActivatedManaAbilityImpl {
if (game != null) {
// TODO: effects from replacement effects like Mana Reflection are not considered yet
// TODO: effects that need a X payment (e.g. Mage-Ring Network) return always 0
newNetMana.add(manaEffect.computeMana(true, game, this));
newNetMana.addAll(manaEffect.getNetMana(game, this));
}
return newNetMana;
}

View file

@ -29,7 +29,7 @@
package mage.abilities.mana;
import mage.Mana;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.constants.ColoredManaSymbol;
/**

View file

@ -29,7 +29,7 @@
package mage.abilities.mana;
import mage.Mana;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.constants.ColoredManaSymbol;
/**

View file

@ -30,9 +30,8 @@ package mage.abilities.mana;
import java.util.List;
import mage.Mana;
import mage.abilities.costs.Cost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.constants.Zone;
import mage.game.Game;
@ -79,15 +78,8 @@ public class SimpleManaAbility extends ActivatedManaAbilityImpl {
@Override
public List<Mana> getNetMana(Game game) {
if (netMana.isEmpty() && predictable) {
for (Effect effect : getEffects()) {
if (effect instanceof ManaEffect) {
Mana effectMana = ((ManaEffect) effect).getMana(game, this);
if (effectMana != null) {
netMana.add(effectMana);
}
}
}
if (predictable) {
return super.getNetMana(game);
}
return netMana;
}

View file

@ -32,7 +32,6 @@ import java.util.List;
import mage.Mana;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DynamicManaEffect;
import mage.abilities.effects.common.ManaEffect;
import mage.constants.AbilityType;
import mage.constants.Zone;
@ -72,20 +71,14 @@ public abstract class TriggeredManaAbility extends TriggeredAbilityImpl implemen
*/
@Override
public List<Mana> getNetMana(Game game) {
if (!getEffects().isEmpty()) {
Effect effect = getEffects().get(0);
if (effect != null && game != null) {
ArrayList<Mana> newNetMana = new ArrayList<>();
if (effect instanceof DynamicManaEffect) {
// TODO: effects from replacement effects like Mana Reflection are not considered yet
// TODO: effects that need a X payment (e.g. Mage-Ring Network) return always 0
newNetMana.add(((DynamicManaEffect) effect).computeMana(true, game, this));
} else if (effect instanceof Effect) {
newNetMana.add(((ManaEffect) effect).getMana(game, this));
if (game != null) {
ArrayList<Mana> newNetMana = new ArrayList<>();
for (Effect effect : getEffects()) {
if (effect instanceof ManaEffect) {
newNetMana.addAll(((ManaEffect) effect).getNetMana(game, this));
}
return newNetMana;
}
return newNetMana;
}
return netMana;
}

View file

@ -29,7 +29,7 @@
package mage.abilities.mana;
import mage.Mana;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.constants.ColoredManaSymbol;
/**

View file

@ -55,6 +55,7 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.mageobject.PowerPredicate;
import mage.game.*;
import mage.game.command.CommandObject;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
@ -618,14 +619,18 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
stackObject = game.getStack().getSpell(getId());
}
if (stackObject != null) {
removed = game.getStack().remove(stackObject);
removed = game.getStack().remove(stackObject, game);
lkiObject = stackObject;
}
break;
case COMMAND:
lkiObject = game.getObject(objectId);
for (CommandObject commandObject : game.getState().getCommand()) {
if (commandObject.getId().equals(objectId)) {
lkiObject = commandObject;
}
}
if (lkiObject != null) {
removed = game.getState().getCommand().remove(game.getObject(objectId));
removed = game.getState().getCommand().remove((CommandObject) lkiObject);
}
break;
case OUTSIDE:

View file

@ -54,6 +54,12 @@ public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializabl
}
}
public CardsImpl(Set<Card> cards) {
for (Card card : cards) {
this.add(card.getId());
}
}
public CardsImpl(Collection<UUID> cardIds) {
if (cardIds != null) {
this.addAll(cardIds);

View file

@ -110,7 +110,15 @@ public class TxtDeckImporter extends DeckImporter {
}
String lineNum = line.substring(0, delim).trim();
String lineName = line.substring(delim).replace("", "\'").trim();
lineName = lineName.replace("&amp;", "//").replace("Æ", "Ae").replace("ö", "ö").replace("û", "u").replace("\"", "'");
lineName = lineName
.replace("&amp;", "//")
.replace("Æ", "Ae")
.replace("ö", "o")
.replace("û", "u")
.replace("í", "i")
.replace("â", "a")
.replace("á", "a")
.replace("\"", "'");
if (lineName.contains("//") && !lineName.contains(" // ")) {
lineName = lineName.replace("//", " // ");
}

View file

@ -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 = 108;
private static final long CARD_CONTENT_VERSION = 109;
private Dao<CardInfo, Object> cardDao;
private Set<String> classNames;

View file

@ -39,7 +39,6 @@ package mage.constants;
* @author LevelX2
*/
public enum DependencyType {
AuraAddingRemoving,
ArtifactAddingRemoving,
AddingAbility,
@ -48,6 +47,7 @@ public enum DependencyType {
BecomeMountain,
BecomePlains,
BecomeSwamp,
BecomeCreature,
EnchantmentAddingRemoving,
LooseDefenderEffect
}
}

View file

@ -5,21 +5,23 @@ package mage.constants;
* @author North
*/
public enum Duration {
OneUse(""),
EndOfGame("for the rest of the game"),
WhileOnBattlefield(""),
WhileOnStack(""),
WhileInGraveyard(""),
EndOfTurn("until end of turn"),
UntilYourNextTurn("until your next turn"),
EndOfCombat("until end of combat"),
EndOfStep("until end of phase step"),
Custom("");
OneUse("", true),
EndOfGame("for the rest of the game", false),
WhileOnBattlefield("", false),
WhileOnStack("", false),
WhileInGraveyard("", false),
EndOfTurn("until end of turn", true),
UntilYourNextTurn("until your next turn", true),
EndOfCombat("until end of combat", true),
EndOfStep("until end of phase step", true),
Custom("", true);
private final String text;
private final boolean onlyValidIfNoZoneChange; // defines if an effect lasts only if the source has not chnaged zone since init of the effect
Duration(String text) {
Duration(String text, boolean onlyValidIfNoZoneChange) {
this.text = text;
this.onlyValidIfNoZoneChange = onlyValidIfNoZoneChange;
}
@Override
@ -27,4 +29,8 @@ public enum Duration {
return text;
}
public boolean isOnlyValidIfNoZoneChange() {
return onlyValidIfNoZoneChange;
}
}

View file

@ -4,6 +4,7 @@ import java.util.Arrays;
import java.util.EnumSet;
import java.util.Set;
import java.util.stream.Collectors;
import mage.util.SubTypeList;
public enum SubType {
@ -328,17 +329,16 @@ public enum SubType {
TROOPER("Trooper", SubTypeSet.CreatureType, true), // Star Wars
TRILOBITE("Trilobite", SubTypeSet.CreatureType),
TWILEK("Twi'lek", SubTypeSet.CreatureType, true), // Star Wars
// U
UGNAUGHT("Ugnaught", SubTypeSet.CreatureType, true),
UNICORN("Unicorn", SubTypeSet.CreatureType),
//V
// V
VAMPIRE("Vampire", SubTypeSet.CreatureType),
VEDALKEN("Vedalken", SubTypeSet.CreatureType),
VIASHINO("Viashino", SubTypeSet.CreatureType),
VILLAIN("Villain", SubTypeSet.CreatureType, true), // Unstable
VOLVER("Volver", SubTypeSet.CreatureType),
//W
// W
WALL("Wall", SubTypeSet.CreatureType),
WARRIOR("Warrior", SubTypeSet.CreatureType),
WEEQUAY("Weequay", SubTypeSet.CreatureType, true),
@ -429,6 +429,16 @@ public enum SubType {
return description;
}
public static SubType fromString(String value) {
for (SubType st : SubType.values()) {
if (st.toString().equals(value)) {
return st;
}
}
throw new IllegalArgumentException("Can''t find subtype enum value: " + value);
}
public static SubType byDescription(String subType) {
for (SubType s : values()) {
if (s.getDescription().equals(subType)) {

View file

@ -39,6 +39,7 @@ public enum CounterType {
ARROWHEAD("arrowhead"),
AWAKENING("awakening"),
BLAZE("blaze"),
BLOOD("blood"),
BOUNTY("bounty"),
BRIBERY("bribery"),
BRICK("brick"),
@ -67,10 +68,12 @@ public enum CounterType {
FADE("fade"),
FATE("fate"),
FEATHER("feather"),
FILIBUSTER("filibuster"),
FLOOD("flood"),
FURY("fury"),
FUNGUS("fungus"),
FUSE("fuse"),
GEM("gem"),
GLOBE("globe"),
GOLD("gold"),
GROWTH("growth"),
@ -83,6 +86,7 @@ public enum CounterType {
ICE("ice"),
INFECTION("infection"),
INTERVENTION("intervention"),
ISOLATION("isolation"),
JAVELIN("javelin"),
KI("ki"),
LANDMARK("landmark"),
@ -90,6 +94,7 @@ public enum CounterType {
LORE("lore"),
LUCK("luck"),
LOYALTY("loyalty"),
MANIFESTATION("manifestation"),
MANNEQUIN("mannequin"),
M1M1(new BoostCounter(-1, -1).name),
M2M1(new BoostCounter(-2, -1).name),
@ -99,6 +104,7 @@ public enum CounterType {
MIRE("mire"),
MUSTER("muster"),
NET("net"),
OMEN("omen"),
P0P1(new BoostCounter(0, 1).name),
P1P0(new BoostCounter(1, 0).name),
P1P1(new BoostCounter(1, 1).name),
@ -108,6 +114,7 @@ public enum CounterType {
PAIN("pain"),
PETAL("petal"),
PETRIFICATION("petrification"),
PHYLACTERY("phylactery"),
PLAGUE("plague"),
PLOT("plot"),
POLYP("polyp"),
@ -123,6 +130,7 @@ public enum CounterType {
SHIELD("shield"),
SHRED("shred"),
SLIME("slime"),
SOOT("soot"),
SPITE("spite"),
SPORE("spore"),
STORAGE("storage"),
@ -132,6 +140,7 @@ public enum CounterType {
TIDE("tide"),
TIME("time"),
TOWER("tower"),
TRAINING("training"),
TRAP("trap"),
TREASURE("treasure"),
UNITY("unity"),

View file

@ -12,6 +12,7 @@ import mage.constants.TargetController;
import mage.filter.common.*;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.MulticoloredPredicate;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.filter.predicate.mageobject.SupertypePredicate;
import mage.filter.predicate.permanent.AnotherPredicate;
@ -75,6 +76,13 @@ public final class StaticFilters {
static {
FILTER_CARD_CREATURE_YOUR_GRAVEYARD.setLockedFilter(true);
}
public static final FilterCard FILTER_CARD_FROM_YOUR_GRAVEYARD = new FilterCard("card from your graveyard");
static {
FILTER_CARD_FROM_YOUR_GRAVEYARD.setLockedFilter(true);
}
public static final FilterLandCard FILTER_CARD_LAND = new FilterLandCard();
static {
@ -102,6 +110,13 @@ public final class StaticFilters {
static {
FILTER_PERMANENT.setLockedFilter(true);
}
public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_AN = new FilterArtifactPermanent("an artifact");
static {
FILTER_PERMANENT_ARTIFACT_AN.setLockedFilter(true);
}
public static final FilterArtifactOrEnchantmentPermanent FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT = new FilterArtifactOrEnchantmentPermanent();
static {
@ -363,10 +378,18 @@ public final class StaticFilters {
static {
FILTER_SPELL.setLockedFilter(true);
}
public static final FilterSpell FILTER_A_SPELL = new FilterSpell("a spell");
public static final FilterSpell FILTER_SPELL_A = new FilterSpell("a spell");
static {
FILTER_A_SPELL.setLockedFilter(true);
FILTER_SPELL_A.setLockedFilter(true);
}
public static final FilterSpell FILTER_SPELL_A_MULTICOLORED = new FilterSpell("a multicolored spell");
static {
FILTER_SPELL_A_MULTICOLORED.add(new MulticoloredPredicate());
FILTER_SPELL_A_MULTICOLORED.setLockedFilter(true);
}
public static final FilterSpell FILTER_INSTANT_OR_SORCERY_SPELL = new FilterSpell("instant or sorcery spell");

View file

@ -328,12 +328,15 @@ public abstract class GameImpl implements Game, Serializable {
MageObject object;
if (state.getBattlefield().containsPermanent(objectId)) {
object = state.getBattlefield().getPermanent(objectId);
state.setZone(objectId, Zone.BATTLEFIELD); // why is this neccessary?
// state.setZone(objectId, Zone.BATTLEFIELD); // why is this neccessary?
return object;
}
if (getPermanentsEntering().containsKey(objectId)) {
return getPermanentEntering(objectId);
}
for (StackObject item : state.getStack()) {
if (item.getId().equals(objectId)) {
state.setZone(objectId, Zone.STACK); // why is this neccessary?
// state.setZone(objectId, Zone.STACK); // why is this neccessary?
return item;
}
if (item.getSourceId().equals(objectId) && item instanceof Spell) {
@ -1383,7 +1386,7 @@ public abstract class GameImpl implements Game, Serializable {
} catch (Exception ex) {
logger.fatal("Game exception gameId: " + getId(), ex);
if ((ex instanceof NullPointerException)
&& errorContinueCounter == 1 && ex.getStackTrace() != null) {
&& errorContinueCounter == 0 && ex.getStackTrace() != null) {
logger.fatal(ex.getStackTrace());
}
this.fireErrorEvent("Game exception occurred: ", ex);
@ -1421,7 +1424,7 @@ public abstract class GameImpl implements Game, Serializable {
top.resolve(this);
} finally {
if (top != null) {
state.getStack().remove(top); // seems partly redundant because move card from stack to grave is already done and the stack removed
state.getStack().remove(top, this); // seems partly redundant because move card from stack to grave is already done and the stack removed
rememberLKI(top.getSourceId(), Zone.STACK, top);
checkInfiniteLoop(top.getSourceId());
if (!getTurn().isEndTurnRequested()) {
@ -2581,10 +2584,10 @@ public abstract class GameImpl implements Game, Serializable {
it.remove();
}
}
if (addPlaneAgain) {
boolean addedAgain = false;
for (Player aplayer : state.getPlayers().values()) {
for (Player aplayer : state.getPlayers().values()) {
if (!aplayer.hasLeft() && !addedAgain) {
addedAgain = true;
Plane plane = Plane.getRandomPlane();

View file

@ -30,7 +30,6 @@ package mage.game;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import mage.MageObject;
import mage.abilities.*;
import mage.abilities.effects.ContinuousEffect;
@ -121,6 +120,8 @@ public class GameState implements Serializable, Copyable<GameState> {
private Map<UUID, Card> copiedCards = new HashMap<>();
private int permanentOrderNumber;
private int applyEffectsCounter; // Upcounting number of each applyEffects execution
public GameState() {
players = new Players();
playerList = new PlayerList();
@ -137,6 +138,7 @@ public class GameState implements Serializable, Copyable<GameState> {
combat = new Combat();
turnMods = new TurnMods();
watchers = new Watchers();
applyEffectsCounter = 0;
}
public GameState(final GameState state) {
@ -193,6 +195,7 @@ public class GameState implements Serializable, Copyable<GameState> {
this.zoneChangeCounter.putAll(state.zoneChangeCounter);
this.copiedCards.putAll(state.copiedCards);
this.permanentOrderNumber = state.permanentOrderNumber;
this.applyEffectsCounter = state.applyEffectsCounter;
}
public void restoreForRollBack(GameState state) {
@ -210,7 +213,7 @@ public class GameState implements Serializable, Copyable<GameState> {
this.command = state.command;
this.isPlaneChase = state.isPlaneChase;
this.seenPlanes = state.seenPlanes;
this.designations = state.designations;
this.designations = state.designations;
this.exile = state.exile;
this.battlefield = state.battlefield;
this.turnNum = state.turnNum;
@ -237,6 +240,7 @@ public class GameState implements Serializable, Copyable<GameState> {
this.zoneChangeCounter = state.zoneChangeCounter;
this.copiedCards = state.copiedCards;
this.permanentOrderNumber = state.permanentOrderNumber;
this.applyEffectsCounter = state.applyEffectsCounter;
}
@Override
@ -466,12 +470,12 @@ public class GameState implements Serializable, Copyable<GameState> {
}
}
return null;
}
}
public List<String> getSeenPlanes() {
return seenPlanes;
}
public boolean isPlaneChase() {
return isPlaneChase;
}
@ -574,6 +578,7 @@ public class GameState implements Serializable, Copyable<GameState> {
}
public void applyEffects(Game game) {
applyEffectsCounter++;
for (Player player : players.values()) {
player.reset();
}
@ -680,7 +685,11 @@ public class GameState implements Serializable, Copyable<GameState> {
}
public void setZone(UUID id, Zone zone) {
zones.put(id, zone);
if (zone == null) {
zones.remove(id);
} else {
zones.put(id, zone);
}
}
public void addSimultaneousEvent(GameEvent event, Game game) {
@ -752,8 +761,8 @@ public class GameState implements Serializable, Copyable<GameState> {
ZoneChangeData data = (ZoneChangeData) obj;
return this.fromZone == data.fromZone
&& this.toZone == data.toZone
&& this.sourceId == data.sourceId
&& this.playerId == data.playerId;
&& Objects.equals(this.sourceId, data.sourceId)
&& Objects.equals(this.playerId, data.playerId);
}
return false;
}
@ -881,13 +890,13 @@ public class GameState implements Serializable, Copyable<GameState> {
addAbility(ability, designation.getId(), null);
}
}
public void addSeenPlane(Plane plane, Game game, UUID controllerId) {
if (plane != null) {
getSeenPlanes().add(plane.getName());
}
}
public void resetSeenPlanes() {
getSeenPlanes().clear();
}
@ -1169,4 +1178,9 @@ public class GameState implements Serializable, Copyable<GameState> {
public int getNextPermanentOrderNumber() {
return permanentOrderNumber++;
}
public int getApplyEffectsCounter() {
return applyEffectsCounter;
}
}

Some files were not shown because too many files have changed in this diff Show more