mirror of
https://github.com/magefree/mage.git
synced 2025-12-26 13:32:06 -08:00
Merge branch 'master' into copy_constructor_watchers
This commit is contained in:
commit
85c6528d2d
724 changed files with 23423 additions and 5250 deletions
|
|
@ -53,6 +53,10 @@ public class MageObjectReference implements Comparable<MageObjectReference>, Ser
|
|||
|
||||
public MageObjectReference(UUID sourceId, Game game) {
|
||||
this.sourceId = sourceId;
|
||||
if (sourceId == null) {
|
||||
throw new IllegalArgumentException("MageObjectReference contains nullable sourceId");
|
||||
}
|
||||
|
||||
MageObject mageObject = game.getObject(sourceId);
|
||||
if (mageObject != null) {
|
||||
this.zoneChangeCounter = mageObject.getZoneChangeCounter(game);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.abilities;
|
||||
|
||||
import mage.constants.Duration;
|
||||
|
|
@ -48,8 +46,8 @@ public class DelayedTriggeredAbilities extends AbilitiesImpl<DelayedTriggeredAbi
|
|||
}
|
||||
}
|
||||
|
||||
public void removeEndOfTurnAbilities() {
|
||||
this.removeIf(ability -> ability.getDuration() == Duration.EndOfTurn);
|
||||
public void removeEndOfTurnAbilities(Game game) {
|
||||
this.removeIf(ability -> ability.getDuration() == Duration.EndOfTurn); // TODO: add Duration.EndOfYourTurn like effects
|
||||
}
|
||||
|
||||
public void removeEndOfCombatAbilities() {
|
||||
|
|
|
|||
|
|
@ -335,26 +335,31 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
if (this.getMaxModesFilter() != null) {
|
||||
sb.append("choose one or more. Each mode must target ").append(getMaxModesFilter().getMessage());
|
||||
} else if (this.getMinModes() == 0 && this.getMaxModes() == 1) {
|
||||
sb.append("choose up to one ");
|
||||
sb.append("choose up to one");
|
||||
} else if (this.getMinModes() == 1 && this.getMaxModes() > 2) {
|
||||
sb.append("choose one or more ");
|
||||
sb.append("choose one or more");
|
||||
} else if (this.getMinModes() == 1 && this.getMaxModes() == 2) {
|
||||
sb.append("choose one or both ");
|
||||
sb.append("choose one or both");
|
||||
} else if (this.getMinModes() == 2 && this.getMaxModes() == 2) {
|
||||
sb.append("choose two ");
|
||||
sb.append("choose two");
|
||||
} else if (this.getMinModes() == 3 && this.getMaxModes() == 3) {
|
||||
sb.append("choose three ");
|
||||
sb.append("choose three");
|
||||
} else if (this.getMinModes() == 4 && this.getMaxModes() == 4) {
|
||||
sb.append("choose four");
|
||||
} else {
|
||||
sb.append("choose one ");
|
||||
sb.append("choose one");
|
||||
}
|
||||
|
||||
if (isEachModeOnlyOnce()) {
|
||||
sb.append("that hasn't been chosen ");
|
||||
sb.append(" that hasn't been chosen");
|
||||
}
|
||||
|
||||
if (isEachModeMoreThanOnce()) {
|
||||
sb.append(". You may choose the same mode more than once.<br>");
|
||||
} else {
|
||||
sb.append("—<br>");
|
||||
sb.append(" —<br>");
|
||||
}
|
||||
|
||||
for (Mode mode : this.values()) {
|
||||
sb.append("&bull ");
|
||||
sb.append(mode.getEffects().getTextStartingUpperCase(mode));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.abilities.abilityword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -21,28 +19,27 @@ import mage.players.Player;
|
|||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class KinshipAbility extends TriggeredAbilityImpl {
|
||||
|
||||
|
||||
public KinshipAbility(Effect kinshipEffect) {
|
||||
super(Zone.BATTLEFIELD, new KinshipBaseEffect(kinshipEffect), true);
|
||||
super(Zone.BATTLEFIELD, new KinshipBaseEffect(kinshipEffect), true);
|
||||
}
|
||||
|
||||
|
||||
public KinshipAbility(final KinshipAbility ability) {
|
||||
super(ability);
|
||||
super(ability);
|
||||
}
|
||||
|
||||
public void addKinshipEffect(Effect kinshipEffect) {
|
||||
for (Effect effect: this.getEffects()) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
if (effect instanceof KinshipBaseEffect) {
|
||||
((KinshipBaseEffect) effect).addEffect(kinshipEffect);
|
||||
break;
|
||||
((KinshipBaseEffect) effect).addEffect(kinshipEffect);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public KinshipAbility copy() {
|
||||
return new KinshipAbility(this);
|
||||
|
|
@ -62,33 +59,33 @@ public class KinshipAbility extends TriggeredAbilityImpl {
|
|||
public String getRule() {
|
||||
return new StringBuilder("<i>Kinship</i> — At the beginning of your upkeep, ").append(super.getRule()).toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class KinshipBaseEffect extends OneShotEffect {
|
||||
|
||||
|
||||
private final Effects kinshipEffects = new Effects();
|
||||
|
||||
|
||||
public KinshipBaseEffect(Effect kinshipEffect) {
|
||||
super(kinshipEffect.getOutcome());
|
||||
this.kinshipEffects.add(kinshipEffect);
|
||||
this.staticText = "you may look at the top card of your library. If it shares a creature type with {this}, you may reveal it. If you do, ";
|
||||
}
|
||||
|
||||
|
||||
public KinshipBaseEffect(final KinshipBaseEffect effect) {
|
||||
super(effect);
|
||||
this.kinshipEffects.addAll(effect.kinshipEffects);
|
||||
this.kinshipEffects.addAll(effect.kinshipEffects.copy());
|
||||
}
|
||||
|
||||
|
||||
public void addEffect(Effect kinshipEffect) {
|
||||
this.kinshipEffects.add(kinshipEffect);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public KinshipBaseEffect copy() {
|
||||
return new KinshipBaseEffect(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
|
|
@ -100,22 +97,22 @@ class KinshipBaseEffect extends OneShotEffect {
|
|||
Cards cards = new CardsImpl(card);
|
||||
controller.lookAtCards(sourcePermanent.getName(), cards, game);
|
||||
if (sourcePermanent.shareSubtypes(card, game)) {
|
||||
if (controller.chooseUse(outcome,new StringBuilder("Kinship - Reveal ").append(card.getLogName()).append('?').toString(), source, game)) {
|
||||
if (controller.chooseUse(outcome, new StringBuilder("Kinship - Reveal ").append(card.getLogName()).append('?').toString(), source, game)) {
|
||||
controller.revealCards(sourcePermanent.getName(), cards, game);
|
||||
for (Effect effect: kinshipEffects) {
|
||||
for (Effect effect : kinshipEffects) {
|
||||
effect.setTargetPointer(new FixedTarget(card.getId()));
|
||||
if (effect.getEffectType() == EffectType.ONESHOT) {
|
||||
effect.apply(game, source);
|
||||
} else {
|
||||
if (effect instanceof ContinuousEffect) {
|
||||
game.addEffect((ContinuousEffect)effect, source);
|
||||
game.addEffect((ContinuousEffect) effect, source);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("This kind of effect is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -125,7 +122,7 @@ class KinshipBaseEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
return new StringBuilder(super.getText(mode)).append(kinshipEffects.getText(mode)).toString();
|
||||
return new StringBuilder(super.getText(mode)).append(kinshipEffects.getText(mode)).toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,16 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
}
|
||||
return yours;
|
||||
case NOT_YOU:
|
||||
boolean notYours = !event.getPlayerId().equals(this.controllerId);
|
||||
if (notYours && setTargetPointer) {
|
||||
if (getTargets().isEmpty()) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return notYours;
|
||||
case OPPONENT:
|
||||
if (game.getPlayer(this.controllerId).hasOpponent(event.getPlayerId(), game)) {
|
||||
if (setTargetPointer && getTargets().isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.CostsImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.constants.TimingRule;
|
||||
|
|
@ -9,15 +9,21 @@ import mage.constants.Zone;
|
|||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Plopman
|
||||
*/
|
||||
public class CastCommanderAbility extends SpellAbility {
|
||||
|
||||
public CastCommanderAbility(Card card) {
|
||||
super(card.getManaCost(), card.getName(), Zone.COMMAND, SpellAbilityType.BASE);
|
||||
this.costs = card.getSpellAbility().getCosts().copy();
|
||||
this.timing = TimingRule.SORCERY;
|
||||
if (card.getSpellAbility() != null) {
|
||||
this.getCosts().addAll(card.getSpellAbility().getCosts().copy());
|
||||
this.getEffects().addAll(card.getSpellAbility().getEffects().copy());
|
||||
this.getTargets().addAll(card.getSpellAbility().getTargets().copy());
|
||||
this.timing = card.getSpellAbility().getTiming();
|
||||
} else {
|
||||
this.costs = new CostsImpl<>();
|
||||
this.timing = TimingRule.SORCERY;
|
||||
}
|
||||
this.usesStack = true;
|
||||
this.controllerId = card.getOwnerId();
|
||||
this.sourceId = card.getId();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
|
|
@ -45,6 +44,7 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility
|
|||
this.text = ability.text;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
this.onlyOpponents = ability.onlyOpponents;
|
||||
this.orPlaneswalker = ability.orPlaneswalker;
|
||||
}
|
||||
|
||||
public DealsCombatDamageToAPlayerTriggeredAbility setOrPlaneswalker(boolean orPlaneswalker) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class GodEternalDiesTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public GodEternalDiesTriggeredAbility() {
|
||||
super(Zone.ALL, null, true);
|
||||
}
|
||||
|
||||
private GodEternalDiesTriggeredAbility(GodEternalDiesTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.ZONE_CHANGE) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getFromZone() == Zone.BATTLEFIELD
|
||||
&& (zEvent.getToZone() == Zone.GRAVEYARD || zEvent.getToZone() == Zone.EXILED);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (zEvent.getTargetId().equals(this.getSourceId())) {
|
||||
this.getEffects().clear();
|
||||
this.addEffect(new GodEternalEffect(new MageObjectReference(zEvent.getTarget(), game)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GodEternalDiesTriggeredAbility copy() {
|
||||
return new GodEternalDiesTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "When {this} dies or is put into exile from the battlefield, " +
|
||||
"you may put it into its owner's library third from the top.";
|
||||
}
|
||||
}
|
||||
|
||||
class GodEternalEffect extends OneShotEffect {
|
||||
|
||||
private final MageObjectReference mor;
|
||||
|
||||
GodEternalEffect(MageObjectReference mor) {
|
||||
super(Outcome.Benefit);
|
||||
this.mor = mor;
|
||||
}
|
||||
|
||||
private GodEternalEffect(final GodEternalEffect effect) {
|
||||
super(effect);
|
||||
this.mor = effect.mor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GodEternalEffect copy() {
|
||||
return new GodEternalEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(mor.getSourceId());
|
||||
if (card.getZoneChangeCounter(game) - 1 != mor.getZoneChangeCounter()) {
|
||||
return false;
|
||||
}
|
||||
return player.putCardOnTopXOfLibrary(card, game, source, 3);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,3 @@
|
|||
/*
|
||||
* 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.condition.common;
|
||||
|
||||
import mage.MageObject;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
|
|
@ -18,8 +14,11 @@ import mage.players.Player;
|
|||
import mage.target.TargetPermanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX
|
||||
*/
|
||||
public class RemoveCounterCost extends CostImpl {
|
||||
|
|
@ -102,10 +101,6 @@ public class RemoveCounterCost extends CostImpl {
|
|||
new StringBuilder("Remove how many counters from ").append(permanent.getIdName()).toString(), game);
|
||||
}
|
||||
permanent.removeCounters(counterName, numberOfCountersSelected, game);
|
||||
if (permanent.getCounters(game).getCount(counterName) == 0) {
|
||||
// this removes only the item with number = 0 from the collection
|
||||
permanent.getCounters(game).removeCounter(counterName);
|
||||
}
|
||||
countersRemoved += numberOfCountersSelected;
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(new StringBuilder(controller.getLogName())
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
package mage.abilities.decorator;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.condition.Condition;
|
||||
|
|
@ -11,11 +7,14 @@ import mage.abilities.condition.FixedCondition;
|
|||
import mage.abilities.condition.LockedInCondition;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.constants.DependencyType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Adds condition to {@link ContinuousEffect}. Acts as decorator.
|
||||
|
|
@ -48,6 +47,18 @@ public class ConditionalContinuousEffect extends ContinuousEffectImpl {
|
|||
this.otherwiseEffect = otherwiseEffect;
|
||||
this.baseCondition = condition;
|
||||
this.staticText = text;
|
||||
|
||||
// checks for compatibility
|
||||
EffectType needType = EffectType.CONTINUOUS;
|
||||
if (effect != null && !effect.getEffectType().equals(needType)) {
|
||||
Assert.fail("ConditionalContinuousEffect supports only " + needType.toString() + " but found " + effect.getEffectType().toString());
|
||||
}
|
||||
if (otherwiseEffect != null && !otherwiseEffect.getEffectType().equals(needType)) {
|
||||
Assert.fail("ConditionalContinuousEffect supports only " + needType.toString() + " but found " + effect.getEffectType().toString());
|
||||
}
|
||||
if (effect != null && otherwiseEffect != null && !effect.getEffectType().equals(otherwiseEffect.getEffectType())) {
|
||||
Assert.fail("ConditionalContinuousEffect must be same but found " + effect.getEffectType().toString() + " and " + otherwiseEffect.getEffectType().toString());
|
||||
}
|
||||
}
|
||||
|
||||
public ConditionalContinuousEffect(final ConditionalContinuousEffect effect) {
|
||||
|
|
@ -68,6 +79,7 @@ public class ConditionalContinuousEffect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
if (baseCondition instanceof LockedInCondition) {
|
||||
condition = new FixedCondition(((LockedInCondition) baseCondition).getBaseCondition().apply(game, source));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
package mage.abilities.decorator;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.effects.CostModificationEffect;
|
||||
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class ConditionalCostModificationEffect extends CostModificationEffectImpl {
|
||||
|
||||
protected CostModificationEffect effect;
|
||||
protected CostModificationEffect otherwiseEffect;
|
||||
protected Condition condition;
|
||||
protected boolean conditionState;
|
||||
|
||||
public ConditionalCostModificationEffect(CostModificationEffect effect, Condition condition, String text) {
|
||||
this(effect, condition, null, text);
|
||||
}
|
||||
|
||||
public ConditionalCostModificationEffect(CostModificationEffect effect, Condition condition, CostModificationEffect otherwiseEffect,
|
||||
String text) {
|
||||
super(effect.getDuration(), effect.getOutcome(), effect.getModificationType());
|
||||
this.effect = effect;
|
||||
this.condition = condition;
|
||||
this.otherwiseEffect = otherwiseEffect;
|
||||
if (text != null) {
|
||||
this.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
public ConditionalCostModificationEffect(final ConditionalCostModificationEffect effect) {
|
||||
super(effect);
|
||||
this.effect = (CostModificationEffect) effect.effect.copy();
|
||||
if (effect.otherwiseEffect != null) {
|
||||
this.otherwiseEffect = (CostModificationEffect) effect.otherwiseEffect.copy();
|
||||
}
|
||||
this.condition = effect.condition;
|
||||
this.conditionState = effect.conditionState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDiscarded() {
|
||||
return effect.isDiscarded() || (otherwiseEffect != null && otherwiseEffect.isDiscarded());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source, Ability abilityToModify) {
|
||||
conditionState = condition.apply(game, source);
|
||||
if (conditionState) {
|
||||
effect.setTargetPointer(this.targetPointer);
|
||||
return effect.apply(game, source, abilityToModify);
|
||||
} else if (otherwiseEffect != null) {
|
||||
otherwiseEffect.setTargetPointer(this.targetPointer);
|
||||
return otherwiseEffect.apply(game, source, abilityToModify);
|
||||
}
|
||||
if (!conditionState && effect.getDuration() == Duration.OneUse) {
|
||||
used = true;
|
||||
}
|
||||
if (!conditionState && effect.getDuration() == Duration.Custom) {
|
||||
this.discard();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
conditionState = condition.apply(game, source);
|
||||
if (conditionState) {
|
||||
effect.setTargetPointer(this.targetPointer);
|
||||
return effect.applies(abilityToModify, source, game);
|
||||
} else if (otherwiseEffect != null) {
|
||||
otherwiseEffect.setTargetPointer(this.targetPointer);
|
||||
return otherwiseEffect.applies(abilityToModify, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionalCostModificationEffect copy() {
|
||||
return new ConditionalCostModificationEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
package mage.abilities.decorator;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.condition.FixedCondition;
|
||||
import mage.abilities.condition.LockedInCondition;
|
||||
import mage.abilities.effects.PreventionEffect;
|
||||
import mage.abilities.effects.PreventionEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class ConditionalPreventionEffect extends PreventionEffectImpl {
|
||||
|
||||
protected PreventionEffect effect;
|
||||
protected PreventionEffect otherwiseEffect;
|
||||
protected Condition baseCondition;
|
||||
protected Condition condition;
|
||||
protected boolean conditionState;
|
||||
protected boolean initDone = false;
|
||||
|
||||
public ConditionalPreventionEffect(PreventionEffect effect, Condition condition, String text) {
|
||||
this(effect, null, condition, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only use this if both effects have the same layers
|
||||
*
|
||||
* @param effect
|
||||
* @param otherwiseEffect
|
||||
* @param condition
|
||||
* @param text
|
||||
*/
|
||||
public ConditionalPreventionEffect(PreventionEffect effect, PreventionEffect otherwiseEffect, Condition condition, String text) {
|
||||
super(effect.getDuration());
|
||||
this.effect = effect;
|
||||
this.otherwiseEffect = otherwiseEffect;
|
||||
this.baseCondition = condition;
|
||||
this.staticText = text;
|
||||
}
|
||||
|
||||
public ConditionalPreventionEffect(final ConditionalPreventionEffect effect) {
|
||||
super(effect);
|
||||
this.effect = (PreventionEffect) effect.effect.copy();
|
||||
if (effect.otherwiseEffect != null) {
|
||||
this.otherwiseEffect = (PreventionEffect) effect.otherwiseEffect.copy();
|
||||
}
|
||||
this.condition = effect.condition; // TODO: checks conditional copy -- it's can be usefull for memory leaks fix?
|
||||
this.conditionState = effect.conditionState;
|
||||
this.baseCondition = effect.baseCondition;
|
||||
this.initDone = effect.initDone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDiscarded() {
|
||||
return this.discarded || effect.isDiscarded() || (otherwiseEffect != null && otherwiseEffect.isDiscarded());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
if (baseCondition instanceof LockedInCondition) {
|
||||
condition = new FixedCondition(((LockedInCondition) baseCondition).getBaseCondition().apply(game, source));
|
||||
} else {
|
||||
condition = baseCondition;
|
||||
}
|
||||
effect.setTargetPointer(this.targetPointer);
|
||||
effect.init(source, game);
|
||||
if (otherwiseEffect != null) {
|
||||
otherwiseEffect.setTargetPointer(this.targetPointer);
|
||||
otherwiseEffect.init(source, game);
|
||||
}
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
if (conditionState) {
|
||||
effect.setTargetPointer(this.targetPointer);
|
||||
return effect.replaceEvent(event, source, game);
|
||||
} else if (otherwiseEffect != null) {
|
||||
otherwiseEffect.setTargetPointer(this.targetPointer);
|
||||
return otherwiseEffect.replaceEvent(event, source, game);
|
||||
}
|
||||
|
||||
if (!conditionState && effect.getDuration() == Duration.OneUse) {
|
||||
used = true;
|
||||
}
|
||||
if (!conditionState && effect.getDuration() == Duration.Custom) {
|
||||
this.discard();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return effect.checksEventType(event, game)
|
||||
|| (otherwiseEffect != null && otherwiseEffect.checksEventType(event, game));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (!initDone) { // if simpleStaticAbility, init won't be called
|
||||
init(source, game);
|
||||
}
|
||||
conditionState = condition.apply(game, source);
|
||||
if (conditionState) {
|
||||
effect.setTargetPointer(this.targetPointer);
|
||||
return effect.applies(event, source, game);
|
||||
} else if (otherwiseEffect != null) {
|
||||
otherwiseEffect.setTargetPointer(this.targetPointer);
|
||||
return otherwiseEffect.applies(event, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
if ((staticText == null || staticText.isEmpty()) && this.effect != null) { // usefull for conditional night/day card abilities
|
||||
return effect.getText(mode);
|
||||
}
|
||||
return staticText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionalPreventionEffect copy() {
|
||||
return new ConditionalPreventionEffect(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.abilities.decorator;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.condition.FixedCondition;
|
||||
|
|
@ -12,12 +10,13 @@ import mage.constants.EffectType;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class ConditionalRequirementEffect extends RequirementEffect {
|
||||
public class ConditionalRequirementEffect extends RequirementEffect {
|
||||
|
||||
protected RequirementEffect effect;
|
||||
protected RequirementEffect otherwiseEffect;
|
||||
|
|
@ -27,7 +26,14 @@ public class ConditionalRequirementEffect extends RequirementEffect {
|
|||
protected boolean initDone = false;
|
||||
|
||||
public ConditionalRequirementEffect(RequirementEffect effect, Condition condition) {
|
||||
this(Duration.WhileOnBattlefield, effect, condition, null, false);
|
||||
this(effect, condition, null);
|
||||
}
|
||||
|
||||
public ConditionalRequirementEffect(RequirementEffect effect, Condition condition, String text) {
|
||||
this(effect.getDuration(), effect, condition, null, false);
|
||||
if (text != null) {
|
||||
setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
public ConditionalRequirementEffect(Duration duration, RequirementEffect effect, Condition condition, RequirementEffect otherwiseEffect, boolean lockedInCondition) {
|
||||
|
|
@ -75,7 +81,7 @@ public class ConditionalRequirementEffect extends RequirementEffect {
|
|||
conditionState = condition.apply(game, source);
|
||||
if (conditionState) {
|
||||
effect.setTargetPointer(this.targetPointer);
|
||||
return effect.applies(permanent, source,game);
|
||||
return effect.applies(permanent, source, game);
|
||||
} else if (otherwiseEffect != null) {
|
||||
otherwiseEffect.setTargetPointer(this.targetPointer);
|
||||
return otherwiseEffect.applies(permanent, source, game);
|
||||
|
|
@ -138,7 +144,7 @@ public class ConditionalRequirementEffect extends RequirementEffect {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ConditionalRequirementEffect copy() {
|
||||
return new ConditionalRequirementEffect(this);
|
||||
|
|
|
|||
|
|
@ -22,14 +22,25 @@ public class ConditionalRestrictionEffect extends RestrictionEffect {
|
|||
protected boolean initDone = false;
|
||||
|
||||
public ConditionalRestrictionEffect(RestrictionEffect effect, Condition condition) {
|
||||
this(Duration.WhileOnBattlefield, effect, condition, null);
|
||||
this(effect, condition, null);
|
||||
}
|
||||
|
||||
public ConditionalRestrictionEffect(RestrictionEffect effect, Condition condition, String text) {
|
||||
this(effect.getDuration(), effect, condition, null, text);
|
||||
}
|
||||
|
||||
public ConditionalRestrictionEffect(Duration duration, RestrictionEffect effect, Condition condition, RestrictionEffect otherwiseEffect) {
|
||||
this(duration, effect, condition, otherwiseEffect, null);
|
||||
}
|
||||
|
||||
public ConditionalRestrictionEffect(Duration duration, RestrictionEffect effect, Condition condition, RestrictionEffect otherwiseEffect, String text) {
|
||||
super(duration);
|
||||
this.effect = effect;
|
||||
this.baseCondition = condition;
|
||||
this.otherwiseEffect = otherwiseEffect;
|
||||
if (text != null) {
|
||||
this.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
public ConditionalRestrictionEffect(final ConditionalRestrictionEffect effect) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package mage.abilities.dynamicvalue.common;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
|
@ -17,17 +17,13 @@ public enum GreatestPowerAmongControlledCreaturesValue implements DynamicValue {
|
|||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
Player player = game.getPlayer(sourceAbility.getControllerId());
|
||||
if (player != null) {
|
||||
int amount = 0;
|
||||
for (Permanent p : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), sourceAbility.getControllerId(), game)) {
|
||||
if (p.getPower().getValue() > amount) {
|
||||
amount = p.getPower().getValue();
|
||||
}
|
||||
}
|
||||
return amount;
|
||||
int amount = 0;
|
||||
for (Permanent p : game.getBattlefield().getActivePermanents(
|
||||
StaticFilters.FILTER_CONTROLLED_CREATURE, sourceAbility.getControllerId(), game
|
||||
)) {
|
||||
amount = Math.max(p.getPower().getValue(), amount);
|
||||
}
|
||||
return 0;
|
||||
return amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum GreatestToughnessAmongControlledCreaturesValue implements DynamicValue {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
int amount = 0;
|
||||
for (Permanent p : game.getBattlefield().getActivePermanents(
|
||||
StaticFilters.FILTER_CONTROLLED_CREATURE, sourceAbility.getControllerId(), game
|
||||
)) {
|
||||
amount = Math.max(p.getToughness().getValue(), amount);
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GreatestToughnessAmongControlledCreaturesValue copy() {
|
||||
return GreatestToughnessAmongControlledCreaturesValue.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "the greatest toughness among creatures you control";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum PermanentsYouControlCount implements DynamicValue {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
return game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermanentsYouControlCount copy() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "permanents you control";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,5 @@
|
|||
|
||||
package mage.abilities.effects;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.DependencyType;
|
||||
|
|
@ -13,8 +8,12 @@ import mage.constants.Layer;
|
|||
import mage.constants.SubLayer;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public interface ContinuousEffect extends Effect {
|
||||
|
|
@ -41,6 +40,8 @@ public interface ContinuousEffect extends Effect {
|
|||
|
||||
void init(Ability source, Game game);
|
||||
|
||||
void init(Ability source, Game game, UUID activePlayerId);
|
||||
|
||||
Layer getLayer();
|
||||
|
||||
SubLayer getSublayer();
|
||||
|
|
@ -59,6 +60,14 @@ public interface ContinuousEffect extends Effect {
|
|||
|
||||
void addDependedToType(DependencyType dependencyType);
|
||||
|
||||
void setStartingControllerAndTurnNum(Game game, UUID startingController, UUID activePlayerId);
|
||||
|
||||
UUID getStartingController();
|
||||
|
||||
void incYourTurnNumPlayed();
|
||||
|
||||
boolean isYourNextTurn(Game game);
|
||||
|
||||
@Override
|
||||
void newId();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
|
||||
package mage.abilities.effects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.MageSingleton;
|
||||
|
|
@ -14,18 +7,14 @@ import mage.abilities.dynamicvalue.DynamicValue;
|
|||
import mage.abilities.dynamicvalue.common.DomainValue;
|
||||
import mage.abilities.dynamicvalue.common.SignInversionDynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.DependencyType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.EffectType;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||
*/
|
||||
public abstract class ContinuousEffectImpl extends EffectImpl implements ContinuousEffect {
|
||||
|
||||
|
|
@ -49,9 +38,10 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
*/
|
||||
protected boolean characterDefining = false;
|
||||
|
||||
// until your next turn
|
||||
protected int startingTurn;
|
||||
protected UUID startingControllerId;
|
||||
// until your next turn or until end of your next turn
|
||||
private UUID startingControllerId; // player to checkss turns (can't different with real controller ability)
|
||||
private boolean startingTurnWasActive;
|
||||
private int yourTurnNumPlayed = 0; // turnes played after effect was created
|
||||
|
||||
public ContinuousEffectImpl(Duration duration, Outcome outcome) {
|
||||
super(outcome);
|
||||
|
|
@ -79,8 +69,9 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
this.affectedObjectsSet = effect.affectedObjectsSet;
|
||||
this.affectedObjectList.addAll(effect.affectedObjectList);
|
||||
this.temporary = effect.temporary;
|
||||
this.startingTurn = effect.startingTurn;
|
||||
this.startingControllerId = effect.startingControllerId;
|
||||
this.startingTurnWasActive = effect.startingTurnWasActive;
|
||||
this.yourTurnNumPlayed = effect.yourTurnNumPlayed;
|
||||
this.dependencyTypes = effect.dependencyTypes;
|
||||
this.dependendToTypes = effect.dependendToTypes;
|
||||
this.characterDefining = effect.characterDefining;
|
||||
|
|
@ -148,6 +139,11 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
init(source, game, game.getActivePlayerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game, UUID activePlayerId) {
|
||||
targetPointer.init(game, source);
|
||||
//20100716 - 611.2c
|
||||
if (AbilityType.ACTIVATED == source.getAbilityType()
|
||||
|
|
@ -170,23 +166,75 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
this.affectedObjectsSet = true;
|
||||
}
|
||||
}
|
||||
startingTurn = game.getTurnNum();
|
||||
startingControllerId = source.getControllerId();
|
||||
setStartingControllerAndTurnNum(game, source.getControllerId(), activePlayerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getStartingController() {
|
||||
return startingControllerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartingControllerAndTurnNum(Game game, UUID startingController, UUID activePlayerId) {
|
||||
this.startingControllerId = startingController;
|
||||
this.startingTurnWasActive = activePlayerId != null && activePlayerId.equals(startingController); // you can't use "game" for active player cause it's called from tests/cheat too
|
||||
this.yourTurnNumPlayed = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incYourTurnNumPlayed() {
|
||||
yourTurnNumPlayed++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isYourNextTurn(Game game) {
|
||||
if (this.startingTurnWasActive) {
|
||||
return yourTurnNumPlayed == 1 && game.isActivePlayer(startingControllerId);
|
||||
} else {
|
||||
return yourTurnNumPlayed == 0 && game.isActivePlayer(startingControllerId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInactive(Ability source, Game game) {
|
||||
if (duration == Duration.UntilYourNextTurn) {
|
||||
Player player = game.getPlayer(startingControllerId);
|
||||
if (player != null) {
|
||||
if (player.isInGame()) {
|
||||
return game.isActivePlayer(startingControllerId) && game.getTurnNum() != startingTurn;
|
||||
}
|
||||
return player.hasReachedNextTurnAfterLeaving();
|
||||
}
|
||||
return true;
|
||||
// YOUR turn checks
|
||||
// until end of turn - must be checked on cleanup step, see rules 514.2
|
||||
// other must checked here (active and leave players), see rules 800.4
|
||||
switch (duration) {
|
||||
case UntilYourNextTurn:
|
||||
case UntilEndOfYourNextTurn:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
// cheat engine put cards without play and calls direct applyEffects with clean -- need to ignore it
|
||||
if (game.getActivePlayerId() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean canDelete = false;
|
||||
Player player = game.getPlayer(startingControllerId);
|
||||
|
||||
// discard on start of turn for leave player
|
||||
// 800.4i When a player leaves the game, any continuous effects with durations that last until that player's next turn
|
||||
// or until a specific point in that turn will last until that turn would have begun.
|
||||
// They neither expire immediately nor last indefinitely.
|
||||
switch (duration) {
|
||||
case UntilYourNextTurn:
|
||||
case UntilEndOfYourNextTurn:
|
||||
canDelete = player == null || (!player.isInGame() && player.hasReachedNextTurnAfterLeaving());
|
||||
}
|
||||
|
||||
// discard on another conditions (start of your turn)
|
||||
switch (duration) {
|
||||
case UntilYourNextTurn:
|
||||
if (player != null && player.isInGame()) {
|
||||
canDelete = canDelete || this.isYourNextTurn(game);
|
||||
}
|
||||
}
|
||||
|
||||
return canDelete;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -263,14 +311,6 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
}
|
||||
}
|
||||
return dependentToEffects;
|
||||
/*
|
||||
return allEffectsInLayer.stream()
|
||||
.filter(effect -> effect.getDependencyTypes().contains(dependendToTypes))
|
||||
.map(Effect::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
}
|
||||
return new HashSet<>();*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
package mage.abilities.effects;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.*;
|
||||
|
|
@ -31,6 +27,11 @@ import mage.players.Player;
|
|||
import mage.target.common.TargetCardInHand;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -54,7 +55,7 @@ public class ContinuousEffects implements Serializable {
|
|||
private final Map<AsThoughEffectType, ContinuousEffectsList<AsThoughEffect>> asThoughEffectsMap = new EnumMap<>(AsThoughEffectType.class);
|
||||
public final List<ContinuousEffectsList<?>> allEffectsLists = new ArrayList<>();
|
||||
private final ApplyCountersEffect applyCounters;
|
||||
// private final PlaneswalkerRedirectionEffect planeswalkerRedirectionEffect;
|
||||
// private final PlaneswalkerRedirectionEffect planeswalkerRedirectionEffect;
|
||||
private final AuraReplacementEffect auraReplacementEffect;
|
||||
|
||||
private final List<ContinuousEffect> previous = new ArrayList<>();
|
||||
|
|
@ -134,18 +135,18 @@ public class ContinuousEffects implements Serializable {
|
|||
spliceCardEffects.removeEndOfCombatEffects();
|
||||
}
|
||||
|
||||
public synchronized void removeEndOfTurnEffects() {
|
||||
layeredEffects.removeEndOfTurnEffects();
|
||||
continuousRuleModifyingEffects.removeEndOfTurnEffects();
|
||||
replacementEffects.removeEndOfTurnEffects();
|
||||
preventionEffects.removeEndOfTurnEffects();
|
||||
requirementEffects.removeEndOfTurnEffects();
|
||||
restrictionEffects.removeEndOfTurnEffects();
|
||||
public synchronized void removeEndOfTurnEffects(Game game) {
|
||||
layeredEffects.removeEndOfTurnEffects(game);
|
||||
continuousRuleModifyingEffects.removeEndOfTurnEffects(game);
|
||||
replacementEffects.removeEndOfTurnEffects(game);
|
||||
preventionEffects.removeEndOfTurnEffects(game);
|
||||
requirementEffects.removeEndOfTurnEffects(game);
|
||||
restrictionEffects.removeEndOfTurnEffects(game);
|
||||
for (ContinuousEffectsList asThoughtlist : asThoughEffectsMap.values()) {
|
||||
asThoughtlist.removeEndOfTurnEffects();
|
||||
asThoughtlist.removeEndOfTurnEffects(game);
|
||||
}
|
||||
costModificationEffects.removeEndOfTurnEffects();
|
||||
spliceCardEffects.removeEndOfTurnEffects();
|
||||
costModificationEffects.removeEndOfTurnEffects(game);
|
||||
spliceCardEffects.removeEndOfTurnEffects(game);
|
||||
}
|
||||
|
||||
public synchronized void removeInactiveEffects(Game game) {
|
||||
|
|
@ -163,6 +164,20 @@ public class ContinuousEffects implements Serializable {
|
|||
spliceCardEffects.removeInactiveEffects(game);
|
||||
}
|
||||
|
||||
public synchronized void incYourTurnNumPlayed(Game game) {
|
||||
layeredEffects.incYourTurnNumPlayed(game);
|
||||
continuousRuleModifyingEffects.incYourTurnNumPlayed(game);
|
||||
replacementEffects.incYourTurnNumPlayed(game);
|
||||
preventionEffects.incYourTurnNumPlayed(game);
|
||||
requirementEffects.incYourTurnNumPlayed(game);
|
||||
restrictionEffects.incYourTurnNumPlayed(game);
|
||||
for (ContinuousEffectsList asThoughtlist : asThoughEffectsMap.values()) {
|
||||
asThoughtlist.incYourTurnNumPlayed(game);
|
||||
}
|
||||
costModificationEffects.incYourTurnNumPlayed(game);
|
||||
spliceCardEffects.incYourTurnNumPlayed(game);
|
||||
}
|
||||
|
||||
public synchronized List<ContinuousEffect> getLayeredEffects(Game game) {
|
||||
List<ContinuousEffect> layerEffects = new ArrayList<>();
|
||||
for (ContinuousEffect effect : layeredEffects) {
|
||||
|
|
@ -322,7 +337,7 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
// boolean checkLKI = event.getType().equals(EventType.ZONE_CHANGE) || event.getType().equals(EventType.DESTROYED_PERMANENT);
|
||||
//get all applicable transient Replacement effects
|
||||
for (Iterator<ReplacementEffect> iterator = replacementEffects.iterator(); iterator.hasNext();) {
|
||||
for (Iterator<ReplacementEffect> iterator = replacementEffects.iterator(); iterator.hasNext(); ) {
|
||||
ReplacementEffect effect = iterator.next();
|
||||
if (!effect.checksEventType(event, game)) {
|
||||
continue;
|
||||
|
|
@ -354,7 +369,8 @@ public class ContinuousEffects implements Serializable {
|
|||
replaceEffects.put(effect, applicableAbilities);
|
||||
}
|
||||
}
|
||||
for (Iterator<PreventionEffect> iterator = preventionEffects.iterator(); iterator.hasNext();) {
|
||||
|
||||
for (Iterator<PreventionEffect> iterator = preventionEffects.iterator(); iterator.hasNext(); ) {
|
||||
PreventionEffect effect = iterator.next();
|
||||
if (!effect.checksEventType(event, game)) {
|
||||
continue;
|
||||
|
|
@ -376,9 +392,10 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
}
|
||||
if (!applicableAbilities.isEmpty()) {
|
||||
replaceEffects.put((ReplacementEffect) effect, applicableAbilities);
|
||||
replaceEffects.put(effect, applicableAbilities);
|
||||
}
|
||||
}
|
||||
|
||||
return replaceEffects;
|
||||
}
|
||||
|
||||
|
|
@ -478,7 +495,6 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param objectId
|
||||
* @param type
|
||||
* @param affectedAbility
|
||||
|
|
@ -697,10 +713,10 @@ public class ContinuousEffects implements Serializable {
|
|||
* Checks if an event won't happen because of an rule modifying effect
|
||||
*
|
||||
* @param event
|
||||
* @param targetAbility ability the event is attached to. can be null.
|
||||
* @param targetAbility ability the event is attached to. can be null.
|
||||
* @param game
|
||||
* @param checkPlayableMode true if the event does not really happen but
|
||||
* it's checked if the event would be replaced
|
||||
* it's checked if the event would be replaced
|
||||
* @return
|
||||
*/
|
||||
public boolean preventedByRuleModification(GameEvent event, Ability targetAbility, Game game, boolean checkPlayableMode) {
|
||||
|
|
@ -747,7 +763,7 @@ public class ContinuousEffects implements Serializable {
|
|||
do {
|
||||
Map<ReplacementEffect, Set<Ability>> rEffects = getApplicableReplacementEffects(event, game);
|
||||
// Remove all consumed effects (ability dependant)
|
||||
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext();) {
|
||||
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext(); ) {
|
||||
ReplacementEffect entry = it1.next();
|
||||
if (consumed.containsKey(entry.getId()) /*&& !(entry instanceof CommanderReplacementEffect) */) { // 903.9.
|
||||
Set<UUID> consumedAbilitiesIds = consumed.get(entry.getId());
|
||||
|
|
@ -938,7 +954,7 @@ public class ContinuousEffects implements Serializable {
|
|||
|
||||
if (!waitingEffects.isEmpty()) {
|
||||
// check if waiting effects can be applied now
|
||||
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext();) {
|
||||
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext(); ) {
|
||||
Map.Entry<ContinuousEffect, Set<UUID>> entry = iterator.next();
|
||||
if (appliedEffects.containsAll(entry.getValue())) { // all dependent to effects are applied now so apply the effect itself
|
||||
appliedAbilities = appliedEffectAbilities.get(entry.getKey());
|
||||
|
|
@ -1059,9 +1075,7 @@ public class ContinuousEffects implements Serializable {
|
|||
final Card card = game.getPermanentOrLKIBattlefield(ability.getSourceId());
|
||||
if (!(effect instanceof BecomesFaceDownCreatureEffect)) {
|
||||
if (card != null) {
|
||||
if (!card.getAbilities(game).contains(ability)) {
|
||||
return false;
|
||||
}
|
||||
return card.getAbilities(game).contains(ability);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
package mage.abilities.effects;
|
||||
|
||||
import java.util.*;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
|
@ -40,10 +44,21 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
return new ContinuousEffectsList<>(this);
|
||||
}
|
||||
|
||||
public void removeEndOfTurnEffects() {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext();) {
|
||||
public void removeEndOfTurnEffects(Game game) {
|
||||
// calls every turn on cleanup step (only end of turn duration)
|
||||
// rules 514.2
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
||||
T entry = i.next();
|
||||
if (entry.getDuration() == Duration.EndOfTurn) {
|
||||
boolean canRemove = false;
|
||||
switch (entry.getDuration()) {
|
||||
case EndOfTurn:
|
||||
canRemove = true;
|
||||
break;
|
||||
case UntilEndOfYourNextTurn:
|
||||
canRemove = entry.isYourNextTurn(game);
|
||||
break;
|
||||
}
|
||||
if (canRemove) {
|
||||
i.remove();
|
||||
effectAbilityMap.remove(entry.getId());
|
||||
}
|
||||
|
|
@ -52,7 +67,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
|
||||
public void removeEndOfCombatEffects() {
|
||||
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext();) {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
||||
T entry = i.next();
|
||||
if (entry.getDuration() == Duration.EndOfCombat) {
|
||||
i.remove();
|
||||
|
|
@ -62,7 +77,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
}
|
||||
|
||||
public void removeInactiveEffects(Game game) {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext();) {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
||||
T entry = i.next();
|
||||
if (isInactive(entry, game)) {
|
||||
i.remove();
|
||||
|
|
@ -71,7 +86,32 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
}
|
||||
}
|
||||
|
||||
public void incYourTurnNumPlayed(Game game) {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
||||
T entry = i.next();
|
||||
if (game.isActivePlayer(entry.getStartingController())) {
|
||||
entry.incYourTurnNumPlayed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInactive(T effect, Game game) {
|
||||
// ends all inactive effects -- calls on player leave or apply new effect
|
||||
if (game.getState().isGameOver()) {
|
||||
// no need to remove effects after end -- users and tests must see last game state
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
800.4a When a player leaves the game, all objects (see rule 109) owned by that player leave the game and any effects
|
||||
which give that player control of any objects or players end. Then, if that player controlled any objects on the stack
|
||||
not represented by cards, those objects cease to exist. Then, if there are any objects still controlled by that player,
|
||||
those objects are exiled. This is not a state-based action. It happens as soon as the player leaves the game.
|
||||
If the player who left the game had priority at the time he or she left, priority passes to the next player in turn
|
||||
order who’s still in the game.
|
||||
*/
|
||||
// objects removes doing in player.leave() call... effects removes is here
|
||||
|
||||
Set<Ability> set = effectAbilityMap.get(effect.getId());
|
||||
if (set == null) {
|
||||
logger.debug("No abilities for effect found: " + effect.toString());
|
||||
|
|
@ -87,29 +127,62 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
} else if (effect.isDiscarded()) {
|
||||
it.remove();
|
||||
} else {
|
||||
// 800.4k When a player leaves the game, any continuous effects with durations that last until that
|
||||
// player’s next turn or until a specific point in that turn will last until that turn would have begun.
|
||||
// They neither expire immediately nor last indefinitely.
|
||||
MageObject object = game.getObject(ability.getSourceId());
|
||||
boolean isObjectInGame = ability.getSourceId() == null || object != null; // Commander effects have no sourceId
|
||||
boolean isOwnerLeaveGame = false;
|
||||
if (object instanceof Card) {
|
||||
Player owner = game.getPlayer(((Card) object).getOwnerId());
|
||||
isOwnerLeaveGame = !owner.isInGame();
|
||||
}
|
||||
|
||||
switch (effect.getDuration()) {
|
||||
//
|
||||
case WhileOnBattlefield:
|
||||
case WhileInGraveyard:
|
||||
case WhileOnStack:
|
||||
if (ability.getSourceId() != null && game.getObject(ability.getSourceId()) == null) { // Commander effects have no sourceId
|
||||
it.remove(); // if the related source object does no longer exist in game - the effect has to be removed
|
||||
case EndOfStep:
|
||||
case EndOfCombat:
|
||||
case EndOfGame:
|
||||
// if the related source object does no longer exist in game - the effect has to be removed
|
||||
if (isOwnerLeaveGame || !isObjectInGame) {
|
||||
it.remove();
|
||||
}
|
||||
break;
|
||||
case OneUse:
|
||||
if (effect.isUsed()) {
|
||||
if (isOwnerLeaveGame || effect.isUsed()) {
|
||||
it.remove();
|
||||
}
|
||||
break;
|
||||
case Custom:
|
||||
// custom effects must process it's own inactive method (override), but can'be missied by devs
|
||||
if (isOwnerLeaveGame || effect.isInactive(ability, game)) {
|
||||
it.remove();
|
||||
}
|
||||
break;
|
||||
case EndOfTurn:
|
||||
// end of turn discards on cleanup steps
|
||||
// 514.2
|
||||
break;
|
||||
case UntilYourNextTurn:
|
||||
case UntilEndOfYourNextTurn:
|
||||
// until your turn effects continue until real turn reached, their used it's own inactive method
|
||||
// 514.2 Second, the following actions happen simultaneously: all damage marked on permanents
|
||||
// (including phased-out permanents) is removed and all "until end of turn" and "this turn" effects end.
|
||||
// This turn-based action doesn’t use the stack.
|
||||
if (effect.isInactive(ability, game)) {
|
||||
it.remove();
|
||||
}
|
||||
break;
|
||||
case UntilSourceLeavesBattlefield:
|
||||
if (Zone.BATTLEFIELD != game.getState().getZone(ability.getSourceId())) {
|
||||
if (isOwnerLeaveGame || Zone.BATTLEFIELD != game.getState().getZone(ability.getSourceId())) {
|
||||
it.remove();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Effects gets unknown duration " + effect.getDuration() + ", effect: " + effect.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -151,7 +224,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
abilities.removeAll(abilitiesToRemove);
|
||||
}
|
||||
if (abilities == null || abilities.isEmpty()) {
|
||||
for (Iterator<T> iterator = this.iterator(); iterator.hasNext();) {
|
||||
for (Iterator<T> iterator = this.iterator(); iterator.hasNext(); ) {
|
||||
ContinuousEffect effect = iterator.next();
|
||||
if (effect.getId().equals(effectIdToRemove)) {
|
||||
iterator.remove();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.Duration;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author antoni-g
|
||||
*/
|
||||
public class PreventDamageAndRemoveCountersEffect extends PreventionEffectImpl {
|
||||
|
||||
public PreventDamageAndRemoveCountersEffect() {
|
||||
super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false, false);
|
||||
staticText = "If damage would be dealt to {this}, prevent that damage and remove that many +1/+1 counters from it";
|
||||
}
|
||||
|
||||
public PreventDamageAndRemoveCountersEffect(final PreventDamageAndRemoveCountersEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreventDamageAndRemoveCountersEffect copy() {
|
||||
return new PreventDamageAndRemoveCountersEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
int damage = event.getAmount();
|
||||
preventDamageAction(event, source, game);
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
permanent.removeCounters(CounterType.P1P1.createInstance(damage), game); //MTG ruling (this) loses counters even if the damage isn't prevented
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (super.applies(event, source, game)) {
|
||||
if (event.getTargetId().equals(source.getSourceId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,6 @@ import mage.players.Player;
|
|||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class ChooseACardNameEffect extends OneShotEffect {
|
||||
|
|
@ -92,11 +91,11 @@ public class ChooseACardNameEffect extends OneShotEffect {
|
|||
if (controller.choose(Outcome.Detriment, cardChoice, game)) {
|
||||
String cardName = cardChoice.getChoice();
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(sourceObject.getLogName() + ", named card: [" + cardName + ']');
|
||||
game.informPlayers(sourceObject.getLogName() + ", chosen name: [" + cardName + ']');
|
||||
}
|
||||
game.getState().setValue(source.getSourceId().toString() + INFO_KEY, cardName);
|
||||
if (sourceObject instanceof Permanent) {
|
||||
((Permanent) sourceObject).addInfo(INFO_KEY, CardUtil.addToolTipMarkTags("Named card: " + cardName), game);
|
||||
((Permanent) sourceObject).addInfo(INFO_KEY, CardUtil.addToolTipMarkTags("Chosen name: " + cardName), game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,8 +122,12 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
permanent.addAbility(ability, getSourceId(), game, false); // no new Id so consumed replacement effects are known while new continuousEffects.apply happen.
|
||||
}
|
||||
}
|
||||
permanent.getPower().setValue(copyFromObject.getPower().getValue());
|
||||
permanent.getToughness().setValue(copyFromObject.getToughness().getValue());
|
||||
|
||||
// Primal Clay example:
|
||||
// If a creature that’s already on the battlefield becomes a copy of this creature, it copies the power, toughness,
|
||||
// and abilities that were chosen for this creature as it entered the battlefield. (2018-03-16)
|
||||
permanent.getPower().setValue(copyFromObject.getPower().getBaseValueModified());
|
||||
permanent.getToughness().setValue(copyFromObject.getToughness().getBaseValueModified());
|
||||
if (copyFromObject instanceof Permanent) {
|
||||
Permanent targetPermanent = (Permanent) copyFromObject;
|
||||
permanent.setTransformed(targetPermanent.isTransformed());
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -70,8 +69,8 @@ public class PreventDamageToAttachedEffect extends PreventionEffectImpl {
|
|||
}
|
||||
sb.append("damage to ");
|
||||
sb.append(attachmentType.verb());
|
||||
sb.append("creature, prevent ").append(amountToPrevent);;
|
||||
sb.append("of that damage");
|
||||
sb.append(" creature, prevent ").append(amountToPrevent);;
|
||||
sb.append(" of that damage");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public class RecruiterEffect extends OneShotEffect {
|
|||
if (controller != null) {
|
||||
TargetCardInLibrary targetCards = new TargetCardInLibrary(0, Integer.MAX_VALUE, filter);
|
||||
Cards cards = new CardsImpl();
|
||||
if (controller.searchLibrary(targetCards, game)) {
|
||||
if (controller.searchLibrary(targetCards, source, game)) {
|
||||
cards.addAll(targetCards.getTargets());
|
||||
}
|
||||
controller.revealCards(staticText, cards, game);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public class ReplaceOpponentCardsInHandWithSelectedEffect extends OneShotEffect
|
|||
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(searchLibraryForNum, searchLibraryForNum, new FilterCard());
|
||||
|
||||
controller.searchLibrary(target, game, targetOpponent.getId());
|
||||
controller.searchLibrary(target, source, game, targetOpponent.getId());
|
||||
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
Card targetCard = game.getCard(cardId);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
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;
|
||||
|
|
@ -34,8 +35,15 @@ public class ReturnFromGraveyardToHandTargetEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
return controller.moveCards(new CardsImpl(getTargetPointer().getTargets(game, source)), Zone.HAND, source, game);
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Cards cardsInGraveyard = new CardsImpl(getTargetPointer().getTargets(game, source));
|
||||
for (Card card : cardsInGraveyard.getCards(game)) {
|
||||
if (card != null
|
||||
&& game.getState().getZone(card.getId()) == Zone.GRAVEYARD) {
|
||||
controller.moveCards(card, Zone.HAND, source, game); //verify the target card is still in the graveyard
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class CantAttackYouAllEffect extends RestrictionEffect {
|
|||
this.alsoPlaneswalker = alsoPlaneswalker;
|
||||
staticText = filterAttacker.getMessage() + " can't attack you"
|
||||
+ (alsoPlaneswalker ? " or a planeswalker you control" : "")
|
||||
+ (duration == Duration.UntilYourNextTurn ? " until your next turn" : "");
|
||||
+ (duration == Duration.UntilYourNextTurn || duration == Duration.UntilEndOfYourNextTurn ? " " + duration.toString() : "");
|
||||
}
|
||||
|
||||
CantAttackYouAllEffect(final CantAttackYouAllEffect effect) {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
|
||||
package mage.abilities.effects.common.continuous;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.TokenImpl;
|
||||
import mage.game.permanent.token.Token;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
|
@ -21,7 +15,6 @@ import java.util.Set;
|
|||
|
||||
/**
|
||||
* @author LevelX2
|
||||
*
|
||||
*/
|
||||
public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
|
||||
|
||||
|
|
@ -29,13 +22,19 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
|
|||
protected String theyAreStillType;
|
||||
private final FilterPermanent filter;
|
||||
private boolean loseColor = true;
|
||||
protected boolean loseName = false;
|
||||
|
||||
public BecomesCreatureAllEffect(Token token, String theyAreStillType, FilterPermanent filter, Duration duration, boolean loseColor) {
|
||||
this(token, theyAreStillType, filter, duration, loseColor, false);
|
||||
}
|
||||
|
||||
public BecomesCreatureAllEffect(Token token, String theyAreStillType, FilterPermanent filter, Duration duration, boolean loseColor, boolean loseName) {
|
||||
super(duration, Outcome.BecomeCreature);
|
||||
this.token = token;
|
||||
this.theyAreStillType = theyAreStillType;
|
||||
this.filter = filter;
|
||||
this.loseColor = loseColor;
|
||||
this.loseName = loseName;
|
||||
}
|
||||
|
||||
public BecomesCreatureAllEffect(final BecomesCreatureAllEffect effect) {
|
||||
|
|
@ -44,6 +43,7 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
|
|||
this.theyAreStillType = effect.theyAreStillType;
|
||||
this.filter = effect.filter.copy();
|
||||
this.loseColor = effect.loseColor;
|
||||
this.loseName = effect.loseName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -65,30 +65,47 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
|
|||
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
||||
Set<Permanent> affectedPermanents = new HashSet<>();
|
||||
if (this.affectedObjectsSet) {
|
||||
for(MageObjectReference ref : affectedObjectList) {
|
||||
for (MageObjectReference ref : affectedObjectList) {
|
||||
affectedPermanents.add(ref.getPermanent(game));
|
||||
}
|
||||
} else {
|
||||
affectedPermanents = new HashSet<>(game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game));
|
||||
}
|
||||
|
||||
for(Permanent permanent : affectedPermanents) {
|
||||
for (Permanent permanent : affectedPermanents) {
|
||||
if (permanent != null) {
|
||||
switch (layer) {
|
||||
case TextChangingEffects_3:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
if (loseName) {
|
||||
permanent.setName(token.getName());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TypeChangingEffects_4:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
if (!token.getCardType().isEmpty()) {
|
||||
for (CardType t : token.getCardType()) {
|
||||
if (!permanent.getCardType().contains(t)) {
|
||||
permanent.addCardType(t);
|
||||
if (theyAreStillType != null) {
|
||||
permanent.getSubtype(game).retainAll(SubType.getLandTypes());
|
||||
permanent.getSubtype(game).addAll(token.getSubtype(game));
|
||||
} else {
|
||||
for (SubType t : token.getSubtype(game)) {
|
||||
if (!permanent.hasSubtype(t, game)) {
|
||||
permanent.getSubtype(game).add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (theyAreStillType == null) {
|
||||
permanent.getSubtype(game).clear();
|
||||
|
||||
for (SuperType t : token.getSuperType()) {
|
||||
if (!permanent.getSuperType().contains(t)) {
|
||||
permanent.addSuperType(t);
|
||||
}
|
||||
}
|
||||
if (!token.getSubtype(game).isEmpty()) {
|
||||
permanent.getSubtype(game).addAll(token.getSubtype(game));
|
||||
|
||||
for (CardType t : token.getCardType()) {
|
||||
if (!permanent.getCardType().contains(t)) {
|
||||
permanent.addCardType(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -141,7 +158,11 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean hasLayer(Layer layer) {
|
||||
return layer == Layer.PTChangingEffects_7 || layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.ColorChangingEffects_5 || layer == Layer.TypeChangingEffects_4;
|
||||
return layer == Layer.PTChangingEffects_7
|
||||
|| layer == Layer.AbilityAddingRemovingEffects_6
|
||||
|| layer == Layer.ColorChangingEffects_5
|
||||
|| layer == Layer.TypeChangingEffects_4
|
||||
|| layer == Layer.TextChangingEffects_3;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -20,25 +20,34 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
|
|||
protected Token token;
|
||||
protected boolean loseAllAbilities;
|
||||
protected boolean addStillALandText;
|
||||
protected boolean loseName;
|
||||
|
||||
|
||||
public BecomesCreatureTargetEffect(Token token, boolean loseAllAbilities, boolean stillALand, Duration duration) {
|
||||
this(token, loseAllAbilities, stillALand, duration, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @param loseAllAbilities loses all subtypes and colors
|
||||
* @param stillALand add rule text, "it's still a land"
|
||||
* @param loseName permanent lose name and get's it from token
|
||||
* @param duration
|
||||
*/
|
||||
public BecomesCreatureTargetEffect(Token token, boolean loseAllAbilities, boolean stillALand, Duration duration) {
|
||||
public BecomesCreatureTargetEffect(Token token, boolean loseAllAbilities, boolean stillALand, Duration duration, boolean loseName) {
|
||||
super(duration, Outcome.BecomeCreature);
|
||||
this.token = token;
|
||||
this.loseAllAbilities = loseAllAbilities;
|
||||
this.addStillALandText = stillALand;
|
||||
this.loseName = loseName;
|
||||
}
|
||||
|
||||
public BecomesCreatureTargetEffect(final BecomesCreatureTargetEffect effect) {
|
||||
super(effect);
|
||||
token = effect.token.copy();
|
||||
this.token = effect.token.copy();
|
||||
this.loseAllAbilities = effect.loseAllAbilities;
|
||||
this.addStillALandText = effect.addStillALandText;
|
||||
this.loseName = effect.loseName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -53,30 +62,41 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
|
|||
Permanent permanent = game.getPermanent(permanentId);
|
||||
if (permanent != null) {
|
||||
switch (layer) {
|
||||
case TextChangingEffects_3:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
if (loseName) {
|
||||
permanent.setName(token.getName());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TypeChangingEffects_4:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
if (loseAllAbilities) {
|
||||
permanent.getSubtype(game).retainAll(SubType.getLandTypes());
|
||||
permanent.getSubtype(game).addAll(token.getSubtype(game));
|
||||
} else {
|
||||
if (!token.getSubtype(game).isEmpty()) {
|
||||
for (SubType subtype : token.getSubtype(game)) {
|
||||
if (!permanent.hasSubtype(subtype, game)) {
|
||||
permanent.getSubtype(game).add(subtype);
|
||||
}
|
||||
for (SubType t : token.getSubtype(game)) {
|
||||
if (!permanent.hasSubtype(t, game)) {
|
||||
permanent.getSubtype(game).add(t);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (!token.getCardType().isEmpty()) {
|
||||
for (CardType t : token.getCardType()) {
|
||||
if (!permanent.getCardType().contains(t)) {
|
||||
permanent.addCardType(t);
|
||||
}
|
||||
|
||||
for (SuperType t : token.getSuperType()) {
|
||||
if (!permanent.getSuperType().contains(t)) {
|
||||
permanent.addSuperType(t);
|
||||
}
|
||||
}
|
||||
|
||||
for (CardType t : token.getCardType()) {
|
||||
if (!permanent.getCardType().contains(t)) {
|
||||
permanent.addCardType(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ColorChangingEffects_5:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
if (loseAllAbilities) {
|
||||
|
|
@ -91,6 +111,7 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AbilityAddingRemovingEffects_6:
|
||||
if (loseAllAbilities) {
|
||||
permanent.removeAllAbilities(source.getSourceId(), game);
|
||||
|
|
@ -125,7 +146,11 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean hasLayer(Layer layer) {
|
||||
return layer == Layer.PTChangingEffects_7 || layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.ColorChangingEffects_5 || layer == Layer.TypeChangingEffects_4;
|
||||
return layer == Layer.PTChangingEffects_7
|
||||
|| layer == Layer.AbilityAddingRemovingEffects_6
|
||||
|| layer == Layer.ColorChangingEffects_5
|
||||
|| layer == Layer.TypeChangingEffects_4
|
||||
|| layer == Layer.TextChangingEffects_3;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
package mage.abilities.effects.common.continuous;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class LookAtTopCardOfLibraryAnyTimeEffect extends ContinuousEffectImpl {
|
||||
|
||||
public LookAtTopCardOfLibraryAnyTimeEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit);
|
||||
staticText = "You may look at the top card of your library any time.";
|
||||
}
|
||||
|
||||
private LookAtTopCardOfLibraryAnyTimeEffect(final LookAtTopCardOfLibraryAnyTimeEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return true;
|
||||
}
|
||||
Card topCard = controller.getLibrary().getFromTop(game);
|
||||
if (topCard == null) {
|
||||
return true;
|
||||
}
|
||||
MageObject obj = source.getSourceObject(game);
|
||||
if (obj == null) {
|
||||
return true;
|
||||
}
|
||||
controller.lookAtCards("Top card of " + obj.getIdName() + " controller's library", topCard, game);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LookAtTopCardOfLibraryAnyTimeEffect copy() {
|
||||
return new LookAtTopCardOfLibraryAnyTimeEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -33,13 +33,13 @@ public class UntapAllDuringEachOtherPlayersUntapStepEffect extends ContinuousEff
|
|||
|
||||
@Override
|
||||
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
||||
Boolean applied = (Boolean) game.getState().getValue(source.getSourceId() + "applied");
|
||||
if (applied == null) {
|
||||
applied = Boolean.FALSE;
|
||||
}
|
||||
if (!applied && layer == Layer.RulesEffects) {
|
||||
if (!source.isControlledBy(game.getActivePlayerId()) && game.getStep().getType() == PhaseStep.UNTAP) {
|
||||
game.getState().setValue(source.getSourceId() + "applied", true);
|
||||
if (layer == Layer.RulesEffects && game.getStep().getType() == PhaseStep.UNTAP && !source.isControlledBy(game.getActivePlayerId())) {
|
||||
Integer appliedTurn = (Integer) game.getState().getValue(source.getSourceId() + "appliedTurn");
|
||||
if (appliedTurn == null) {
|
||||
appliedTurn = 0;
|
||||
}
|
||||
if (appliedTurn < game.getTurnNum()) {
|
||||
game.getState().setValue(source.getSourceId() + "appliedTurn", game.getTurnNum());
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) {
|
||||
boolean untap = true;
|
||||
for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) {
|
||||
|
|
@ -50,10 +50,6 @@ public class UntapAllDuringEachOtherPlayersUntapStepEffect extends ContinuousEff
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (applied && layer == Layer.RulesEffects) {
|
||||
if (game.getStep().getType() == PhaseStep.END_TURN) {
|
||||
game.getState().setValue(source.getSourceId() + "applied", false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects.common.cost;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -13,14 +12,17 @@ import mage.game.Game;
|
|||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
|
||||
|
||||
private final int amount;
|
||||
private ManaCosts<ManaCost> manaCostsToReduce = null;
|
||||
private final Condition condition;
|
||||
private Condition condition;
|
||||
|
||||
public SpellCostReductionSourceEffect(ManaCosts<ManaCost> manaCostsToReduce) {
|
||||
this(manaCostsToReduce, null);
|
||||
}
|
||||
|
||||
public SpellCostReductionSourceEffect(ManaCosts<ManaCost> manaCostsToReduce, Condition condition) {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
|
||||
|
|
@ -33,19 +35,28 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
|
|||
for (String manaSymbol : manaCostsToReduce.getSymbols()) {
|
||||
sb.append(manaSymbol);
|
||||
}
|
||||
sb.append(" less to if ").append(this.condition.toString());
|
||||
sb.append(" less");
|
||||
if (this.condition != null) {
|
||||
sb.append(" to if ").append(this.condition.toString());
|
||||
}
|
||||
|
||||
this.staticText = sb.toString();
|
||||
}
|
||||
|
||||
public SpellCostReductionSourceEffect(int amount) {
|
||||
this(amount, null);
|
||||
}
|
||||
|
||||
public SpellCostReductionSourceEffect(int amount, Condition condition) {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
|
||||
this.amount = amount;
|
||||
this.condition = condition;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{this} costs {")
|
||||
.append(amount).append("} less to cast ")
|
||||
.append((this.condition.toString().startsWith("if ") ? "" : "if "))
|
||||
.append(this.condition.toString());
|
||||
sb.append("{this} costs {").append(amount).append("} less to cast");
|
||||
if (this.condition != null) {
|
||||
sb.append(" ").append(this.condition.toString().startsWith("if ") ? "" : "if ");
|
||||
sb.append(this.condition.toString());
|
||||
}
|
||||
this.staticText = sb.toString();
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +80,7 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
|
|||
@Override
|
||||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
if (abilityToModify.getSourceId().equals(source.getSourceId()) && (abilityToModify instanceof SpellAbility)) {
|
||||
return condition.apply(game, source);
|
||||
return condition == null || condition.apply(game, source);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
|
||||
package mage.abilities.effects.common.counter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceImpl;
|
||||
import mage.constants.Outcome;
|
||||
import mage.counters.Counter;
|
||||
import mage.filter.common.FilterPermanentOrPlayerWithCounter;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetPermanentOrPlayerWithCounter;
|
||||
import mage.target.common.TargetPermanentOrPlayer;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author nantuko
|
||||
|
|
@ -25,8 +22,19 @@ import mage.target.common.TargetPermanentOrPlayerWithCounter;
|
|||
public class ProliferateEffect extends OneShotEffect {
|
||||
|
||||
public ProliferateEffect() {
|
||||
this("", true);
|
||||
}
|
||||
|
||||
public ProliferateEffect(boolean showAbilityHint) {
|
||||
this("", showAbilityHint);
|
||||
}
|
||||
|
||||
public ProliferateEffect(String afterText, boolean showAbilityHint) {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "proliferate. <i>(You choose any number of permanents and/or players with counters on them, then give each another counter of each kind already there.)</i>";
|
||||
staticText = "proliferate" + afterText;
|
||||
if (showAbilityHint) {
|
||||
staticText += ". <i>(You choose any number of permanents and/or players with counters on them, then give each another counter of each kind already there.)</i>";
|
||||
}
|
||||
}
|
||||
|
||||
public ProliferateEffect(ProliferateEffect effect) {
|
||||
|
|
@ -36,10 +44,11 @@ public class ProliferateEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Counter newCounter = null;
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Target target = new TargetPermanentOrPlayerWithCounter(0, Integer.MAX_VALUE, true);
|
||||
Target target = new TargetPermanentOrPlayer(0, Integer.MAX_VALUE, new FilterPermanentOrPlayerWithCounter(), true);
|
||||
Map<String, Serializable> options = new HashMap<>();
|
||||
options.put("UI.right.btn.text", "Done");
|
||||
controller.choose(Outcome.Benefit, target, source.getSourceId(), game, options);
|
||||
|
|
@ -49,18 +58,30 @@ public class ProliferateEffect extends OneShotEffect {
|
|||
if (permanent != null) {
|
||||
if (!permanent.getCounters(game).isEmpty()) {
|
||||
for (Counter counter : permanent.getCounters(game).values()) {
|
||||
Counter newCounter = new Counter(counter.getName());
|
||||
newCounter = new Counter(counter.getName());
|
||||
permanent.addCounters(newCounter, source, game);
|
||||
}
|
||||
if (newCounter != null) {
|
||||
game.informPlayers(permanent.getName()
|
||||
+ " had 1 "
|
||||
+ newCounter.getName()
|
||||
+ " counter added to it.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Player player = game.getPlayer(chosen);
|
||||
if (player != null) {
|
||||
if (!player.getCounters().isEmpty()) {
|
||||
for (Counter counter : player.getCounters().values()) {
|
||||
Counter newCounter = new Counter(counter.getName());
|
||||
newCounter = new Counter(counter.getName());
|
||||
player.addCounters(newCounter, game);
|
||||
}
|
||||
if (newCounter != null) {
|
||||
game.informPlayers(player.getName()
|
||||
+ " had 1 "
|
||||
+ newCounter.getName()
|
||||
+ " counter added to them.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect {
|
|||
Cards revealedCards = new CardsImpl();
|
||||
numberToReveal = Math.min(player.getHand().size(), numberToReveal);
|
||||
if (player.getHand().size() > numberToReveal) {
|
||||
TargetCardInHand chosenCards = new TargetCardInHand(numberToReveal, numberToReveal, new FilterCard("card in " + player.getLogName() + "'s hand"));
|
||||
TargetCardInHand chosenCards = new TargetCardInHand(numberToReveal, numberToReveal, new FilterCard("card in " + player.getName() + "'s hand"));
|
||||
chosenCards.setNotTarget(true);
|
||||
if (chosenCards.canChoose(player.getId(), game) && player.chooseTarget(Outcome.Discard, player.getHand(), chosenCards, source, game)) {
|
||||
if (!chosenCards.getTargets().isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public class SearchLibraryGraveyardPutInHandEffect extends OneShotEffect {
|
|||
if (forceToSearchBoth || controller.chooseUse(outcome, "Search your library for a card named " + filter.getMessage() + '?', source, game)) {
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter);
|
||||
target.clearChosen();
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
if (controller.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
cardFound = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
package mage.abilities.effects.common.search;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class SearchLibraryGraveyardPutOntoBattlefieldEffect extends OneShotEffect {
|
||||
|
||||
private FilterCard filter;
|
||||
private boolean forceToSearchBoth;
|
||||
|
||||
public SearchLibraryGraveyardPutOntoBattlefieldEffect(FilterCard filter) {
|
||||
this(filter, false);
|
||||
}
|
||||
|
||||
public SearchLibraryGraveyardPutOntoBattlefieldEffect(FilterCard filter, boolean forceToSearchBoth) {
|
||||
this(filter, forceToSearchBoth, false);
|
||||
}
|
||||
|
||||
public SearchLibraryGraveyardPutOntoBattlefieldEffect(FilterCard filter, boolean forceToSearchBoth, boolean youMay) {
|
||||
super(Outcome.Benefit);
|
||||
this.filter = filter;
|
||||
this.forceToSearchBoth = forceToSearchBoth;
|
||||
staticText = (youMay ? "You may" : "") + " search your library and" + (forceToSearchBoth ? "" : "/or") + " graveyard for a card named " + filter.getMessage()
|
||||
+ ", reveal it, and put it into your hand. " + (forceToSearchBoth ? "Then shuffle your library" : "If you search your library this way, shuffle it");
|
||||
}
|
||||
|
||||
public SearchLibraryGraveyardPutOntoBattlefieldEffect(final SearchLibraryGraveyardPutOntoBattlefieldEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
this.forceToSearchBoth = effect.forceToSearchBoth;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchLibraryGraveyardPutOntoBattlefieldEffect copy() {
|
||||
return new SearchLibraryGraveyardPutOntoBattlefieldEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
Card cardFound = null;
|
||||
if (controller != null && sourceObject != null) {
|
||||
if (forceToSearchBoth || controller.chooseUse(outcome, "Search your library for a card named " + filter.getMessage() + '?', source, game)) {
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter);
|
||||
target.clearChosen();
|
||||
if (controller.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
cardFound = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
}
|
||||
controller.shuffleLibrary(source, game);
|
||||
}
|
||||
|
||||
if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a card named " + filter.getMessage() + '?', source, game)) {
|
||||
TargetCard target = new TargetCard(0, 1, Zone.GRAVEYARD, filter);
|
||||
target.clearChosen();
|
||||
if (controller.choose(outcome, controller.getGraveyard(), target, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
cardFound = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cardFound != null) {
|
||||
controller.revealCards(sourceObject.getIdName(), new CardsImpl(cardFound), game);
|
||||
controller.moveCards(cardFound, Zone.BATTLEFIELD, source, game);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package mage.abilities.effects.common.search;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author antoni-g
|
||||
*/
|
||||
public class SearchLibraryGraveyardWithLessCMCPutIntoPlay extends OneShotEffect {
|
||||
|
||||
private final FilterCard filter;
|
||||
|
||||
public SearchLibraryGraveyardWithLessCMCPutIntoPlay() {
|
||||
this(new FilterCard());
|
||||
}
|
||||
|
||||
public SearchLibraryGraveyardWithLessCMCPutIntoPlay(FilterCard filter) {
|
||||
super(Outcome.PutCreatureInPlay);
|
||||
this.filter = filter;
|
||||
staticText = "Search your library or graveyard for a " + filter.getMessage() + " with converted mana cost X or less, put it onto the battlefield, then shuffle your library";
|
||||
}
|
||||
|
||||
public SearchLibraryGraveyardWithLessCMCPutIntoPlay(final SearchLibraryGraveyardWithLessCMCPutIntoPlay effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchLibraryGraveyardWithLessCMCPutIntoPlay copy() {
|
||||
return new SearchLibraryGraveyardWithLessCMCPutIntoPlay(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
Card cardFound = null;
|
||||
if (controller != null && sourceObject != null) {
|
||||
// create x cost filter
|
||||
FilterCard advancedFilter = filter.copy(); // never change static objects so copy the object here before
|
||||
advancedFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1));
|
||||
|
||||
if (controller.chooseUse(outcome, "Search your library for a " + filter.getMessage() + " with CMC X or less" + '?', source, game)) {
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(advancedFilter);
|
||||
target.clearChosen();
|
||||
if (controller.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
cardFound = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
}
|
||||
controller.shuffleLibrary(source, game);
|
||||
}
|
||||
|
||||
if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a " + filter.getMessage() + " with CMC X or less" + '?', source, game)) {
|
||||
TargetCard target = new TargetCard(0, 1, Zone.GRAVEYARD, advancedFilter);
|
||||
target.clearChosen();
|
||||
if (controller.choose(outcome, controller.getGraveyard(), target, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
cardFound = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cardFound != null) {
|
||||
controller.revealCards(sourceObject.getIdName(), new CardsImpl(cardFound), game);
|
||||
controller.moveCards(cardFound, Zone.BATTLEFIELD, source, game);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ public class SearchLibraryPutInHandEffect extends SearchEffect {
|
|||
return false;
|
||||
}
|
||||
target.clearChosen();
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
if (controller.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
Cards cards = new CardsImpl();
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public class SearchLibraryPutInHandOrOnBattlefieldEffect extends SearchEffect {
|
|||
return false;
|
||||
}
|
||||
target.clearChosen();
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
if (controller.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
Cards cards = new CardsImpl();
|
||||
boolean askToPutOntoBf = false;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public class SearchLibraryPutInPlayEffect extends SearchEffect {
|
|||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
if (player.searchLibrary(target, game)) {
|
||||
if (player.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
player.moveCards(new CardsImpl(target.getTargets()).getCards(game),
|
||||
Zone.BATTLEFIELD, source, game, tapped, false, false, null);
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public class SearchLibraryPutInPlayTargetPlayerEffect extends SearchEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
if (player != null) {
|
||||
if (player.searchLibrary(target, game)) {
|
||||
if (player.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
player.moveCards(new CardsImpl(target.getTargets()).getCards(game),
|
||||
Zone.BATTLEFIELD, source, game, tapped, false, ownerIsController, null);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public class SearchLibraryPutOnLibraryEffect extends SearchEffect {
|
|||
if (controller == null || sourceObject == null) {
|
||||
return false;
|
||||
}
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
if (controller.searchLibrary(target, source, game)) {
|
||||
Cards foundCards = new CardsImpl(target.getTargets());
|
||||
if (reveal && !foundCards.isEmpty()) {
|
||||
controller.revealCards(sourceObject.getIdName(), foundCards, game);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public class SearchLibraryWithLessCMCPutInPlayEffect extends OneShotEffect {
|
|||
FilterCard advancedFilter = filter.copy(); // never change static objects so copy the object here before
|
||||
advancedFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1));
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(advancedFilter);
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
if (controller.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
Card card = controller.getLibrary().getCard(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package mage.abilities.effects.keyword;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
|
@ -19,10 +21,10 @@ public class AdaptEffect extends OneShotEffect {
|
|||
public AdaptEffect(int adaptNumber) {
|
||||
super(Outcome.BoostCreature);
|
||||
this.adaptNumber = adaptNumber;
|
||||
staticText = "Adapt " + adaptNumber +
|
||||
" <i>(If this creature has no +1/+1 counters on it, put " +
|
||||
CardUtil.numberToText(adaptNumber) + " +1/+1 counter" +
|
||||
(adaptNumber > 1 ? "s" : "") + " on it.)</i>";
|
||||
staticText = "Adapt " + adaptNumber
|
||||
+ " <i>(If this creature has no +1/+1 counters on it, put "
|
||||
+ CardUtil.numberToText(adaptNumber) + " +1/+1 counter"
|
||||
+ (adaptNumber > 1 ? "s" : "") + " on it.)</i>";
|
||||
}
|
||||
|
||||
private AdaptEffect(final AdaptEffect effect) {
|
||||
|
|
@ -37,7 +39,15 @@ public class AdaptEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
// Verify source object did not change zone and is on the battlefield
|
||||
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
|
||||
if (sourceObject == null) {
|
||||
if (game.getState().getZone(source.getSourceId()).equals(Zone.BATTLEFIELD)
|
||||
&& source.getSourceObjectZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(source.getSourceId())) {
|
||||
sourceObject = game.getPermanent(source.getSourceId());
|
||||
}
|
||||
}
|
||||
Permanent permanent = ((Permanent) sourceObject);
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -48,7 +58,8 @@ public class AdaptEffect extends OneShotEffect {
|
|||
if (game.replaceEvent(event)) {
|
||||
return false;
|
||||
}
|
||||
if (permanent.getCounters(game).getCount(CounterType.P1P1) == 0 || event.getFlag()) {
|
||||
if (permanent.getCounters(game).getCount(CounterType.P1P1) == 0
|
||||
|| event.getFlag()) {
|
||||
permanent.addCounters(CounterType.P1P1.createInstance(event.getAmount()), source, game);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public class AmassEffect extends OneShotEffect {
|
|||
public AmassEffect(int amassNumber) {
|
||||
this(new StaticValue(amassNumber));
|
||||
staticText = "amass " + amassNumber + ". <i>(Put " + CardUtil.numberToText(amassNumber)
|
||||
+ " +1/+1 counter " + (amassNumber > 1 ? "s" : "")
|
||||
+ " +1/+1 counter" + (amassNumber > 1 ? "s " : " ")
|
||||
+ "on an Army you control. If you don’t control one, "
|
||||
+ "create a 0/0 black Zombie Army creature token first.)</i>";
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ public class AmassEffect extends OneShotEffect {
|
|||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
if (!game.getBattlefield().contains(filter, 1, game)) {
|
||||
if (!game.getBattlefield().contains(filter, source.getControllerId(), 1, game)) {
|
||||
new CreateTokenEffect(new ZombieArmyToken()).apply(game, source);
|
||||
}
|
||||
Target target = new TargetPermanent(filter);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsYouControlCount;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.ValueHint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum PermanentsYouControlHint implements Hint {
|
||||
|
||||
instance;
|
||||
private static final Hint hint = new ValueHint("Permanents you control", PermanentsYouControlCount.instance);
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.List;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpecialAction;
|
||||
|
|
@ -24,6 +22,8 @@ import mage.players.Player;
|
|||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 702.65. Delve 702.65a Delve is a static ability that functions while the
|
||||
* spell with delve is on the stack. “Delve” means “For each generic mana in
|
||||
|
|
@ -31,7 +31,7 @@ import mage.util.CardUtil;
|
|||
* pay that mana.” The delve ability isn't an additional or alternative cost and
|
||||
* applies only after the total cost of the spell with delve is determined.
|
||||
* 702.65b Multiple instances of delve on the same spell are redundant.
|
||||
*
|
||||
* <p>
|
||||
* The rules for delve have changed slightly since it was last in an expansion.
|
||||
* Previously, delve reduced the cost to cast a spell. Under the current rules,
|
||||
* you exile cards from your graveyard at the same time you pay the spell's
|
||||
|
|
@ -45,7 +45,7 @@ import mage.util.CardUtil;
|
|||
* it can be used in conjunction with alternative costs.
|
||||
*
|
||||
* @author LevelX2
|
||||
*
|
||||
* <p>
|
||||
* TODO: Change card exiling to a way to pay mana costs, now it's maybe not
|
||||
* possible to pay costs from effects that increase the mana costs.
|
||||
*/
|
||||
|
|
@ -83,7 +83,8 @@ public class DelveAbility extends SimpleStaticAbility implements AlternateManaPa
|
|||
unpaidAmount = 1;
|
||||
}
|
||||
specialAction.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(
|
||||
0, Math.min(controller.getGraveyard().size(), unpaidAmount), new FilterCard(), true)));
|
||||
0, Math.min(controller.getGraveyard().size(), unpaidAmount),
|
||||
new FilterCard("cards to exile for delve's pay from your graveyard"), true)));
|
||||
if (specialAction.canActivate(source.getControllerId(), game).canActivate()) {
|
||||
game.getState().getSpecialActions().add(specialAction);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ class PartnersWithSearchEffect extends OneShotEffect {
|
|||
filter.add(new NamePredicate(partnerName));
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(filter);
|
||||
if (player.chooseUse(Outcome.Benefit, "Search your library for a card named " + partnerName + " and put it into your hand?", source, game)) {
|
||||
player.searchLibrary(target, game);
|
||||
player.searchLibrary(target, source, game);
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
Card card = player.getLibrary().getCard(cardId, game);
|
||||
if (card != null) {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ class TransmuteEffect extends OneShotEffect {
|
|||
FilterCard filter = new FilterCard("card with converted mana cost " + sourceObject.getConvertedManaCost());
|
||||
filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, sourceObject.getConvertedManaCost()));
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(1, filter);
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
if (controller.searchLibrary(target, source, game)) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
Cards revealed = new CardsImpl(target.getTargets());
|
||||
controller.revealCards(sourceObject.getIdName(), revealed, game);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -19,19 +18,17 @@ import mage.game.events.GameEvent.EventType;
|
|||
import mage.game.events.ZoneChangeEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* <p>
|
||||
* 702.82. Unearth
|
||||
*
|
||||
* <p>
|
||||
* 702.82a Unearth is an activated ability that functions while the card with
|
||||
* unearth is in a graveyard. "Unearth [cost]" means "[Cost]: Return this card
|
||||
* from your graveyard to the battlefield. It gains haste. Exile it at the
|
||||
* beginning of the next end step. If it would leave the battlefield, exile it
|
||||
* instead of putting it anywhere else. Activate this ability only any time you
|
||||
* could cast a sorcery."
|
||||
*
|
||||
*/
|
||||
public class UnearthAbility extends ActivatedAbilityImpl {
|
||||
|
||||
|
|
@ -111,7 +108,7 @@ class UnearthLeavesBattlefieldEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return EventType.ZONE_CHANGE == event.getType();
|
||||
return event.getType() == EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -690,27 +690,33 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
sourceId = source.getSourceId();
|
||||
}
|
||||
}
|
||||
GameEvent countersEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTERS, objectId, sourceId, getControllerOrOwner(), counter.getName(), counter.getCount());
|
||||
countersEvent.setAppliedEffects(appliedEffects);
|
||||
countersEvent.setFlag(isEffect);
|
||||
if (!game.replaceEvent(countersEvent)) {
|
||||
int amount = countersEvent.getAmount();
|
||||
GameEvent addingAllEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTERS, objectId, sourceId, getControllerOrOwner(), counter.getName(), counter.getCount());
|
||||
addingAllEvent.setAppliedEffects(appliedEffects);
|
||||
addingAllEvent.setFlag(isEffect);
|
||||
if (!game.replaceEvent(addingAllEvent)) {
|
||||
int amount = addingAllEvent.getAmount();
|
||||
boolean isEffectFlag = addingAllEvent.getFlag();
|
||||
int finalAmount = amount;
|
||||
for (int i = 0; i < amount; i++) {
|
||||
Counter eventCounter = counter.copy();
|
||||
eventCounter.remove(eventCounter.getCount() - 1);
|
||||
GameEvent event = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTER, objectId, sourceId, getControllerOrOwner(), counter.getName(), 1);
|
||||
event.setAppliedEffects(appliedEffects);
|
||||
if (!game.replaceEvent(event)) {
|
||||
GameEvent addingOneEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTER, objectId, sourceId, getControllerOrOwner(), counter.getName(), 1);
|
||||
addingOneEvent.setAppliedEffects(appliedEffects);
|
||||
addingOneEvent.setFlag(isEffectFlag);
|
||||
if (!game.replaceEvent(addingOneEvent)) {
|
||||
getCounters(game).addCounter(eventCounter);
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER_ADDED, objectId, sourceId, getControllerOrOwner(), counter.getName(), 1));
|
||||
GameEvent addedOneEvent = GameEvent.getEvent(GameEvent.EventType.COUNTER_ADDED, objectId, sourceId, getControllerOrOwner(), counter.getName(), 1);
|
||||
addedOneEvent.setFlag(addingOneEvent.getFlag());
|
||||
game.fireEvent(addedOneEvent);
|
||||
} else {
|
||||
finalAmount--;
|
||||
returnCode = false;
|
||||
}
|
||||
}
|
||||
if (finalAmount > 0) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERS_ADDED, objectId, sourceId, getControllerOrOwner(), counter.getName(), amount));
|
||||
GameEvent addedAllEvent = GameEvent.getEvent(GameEvent.EventType.COUNTERS_ADDED, objectId, sourceId, getControllerOrOwner(), counter.getName(), amount);
|
||||
addedAllEvent.setFlag(isEffectFlag);
|
||||
game.fireEvent(addedAllEvent);
|
||||
}
|
||||
} else {
|
||||
returnCode = false;
|
||||
|
|
@ -720,6 +726,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
|
||||
@Override
|
||||
public void removeCounters(String name, int amount, Game game) {
|
||||
int finalAmount = 0;
|
||||
for (int i = 0; i < amount; i++) {
|
||||
if (!getCounters(game).removeCounter(name, 1)) {
|
||||
break;
|
||||
|
|
@ -727,7 +734,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
GameEvent event = GameEvent.getEvent(GameEvent.EventType.COUNTER_REMOVED, objectId, getControllerOrOwner());
|
||||
event.setData(name);
|
||||
game.fireEvent(event);
|
||||
finalAmount++;
|
||||
}
|
||||
GameEvent event = GameEvent.getEvent(GameEvent.EventType.COUNTERS_REMOVED, objectId, getControllerOrOwner());
|
||||
event.setData(name);
|
||||
event.setAmount(finalAmount);
|
||||
game.fireEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ public abstract class ExpansionSet implements Serializable {
|
|||
return booster.stream().anyMatch(card -> card.isLegendary() && card.isCreature());
|
||||
}
|
||||
if (needsPlaneswalker) {
|
||||
return booster.stream().anyMatch(card -> card.isPlaneswalker());
|
||||
return booster.stream().filter(card -> card.isPlaneswalker()).count() == 1;
|
||||
}
|
||||
|
||||
// TODO: add partner check
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package mage.cards.decks.exporter;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.decks.DeckFileFilter;
|
||||
|
|
@ -13,9 +14,11 @@ import java.util.*;
|
|||
*/
|
||||
public class MtgArenaDeckExporter extends DeckExporter {
|
||||
|
||||
private final String ext = "mtga";
|
||||
private final String description = "MTG Arena's deck format (*.mtga)";
|
||||
private final FileFilter fileFilter = new DeckFileFilter(ext, description);
|
||||
private static final String ext = "mtga";
|
||||
private static final String description = "MTG Arena's deck format (*.mtga)";
|
||||
private static final FileFilter fileFilter = new DeckFileFilter(ext, description);
|
||||
|
||||
private static final Map<String, String> SET_CODE_REPLACEMENTS = ImmutableMap.of("DOM", "DAR");
|
||||
|
||||
@Override
|
||||
public void writeDeck(PrintWriter out, DeckCardLists deck) {
|
||||
|
|
@ -33,7 +36,9 @@ public class MtgArenaDeckExporter extends DeckExporter {
|
|||
private List<String> prepareCardsList(List<DeckCardInfo> sourceCards, Map<String, Integer> amount, String prefix) {
|
||||
List<String> res = new ArrayList<>();
|
||||
for (DeckCardInfo card : sourceCards) {
|
||||
String name = card.getCardName() + " (" + card.getSetCode().toUpperCase(Locale.ENGLISH) + ") " + card.getCardNum();
|
||||
String setCode = card.getSetCode().toUpperCase(Locale.ENGLISH);
|
||||
setCode = SET_CODE_REPLACEMENTS.getOrDefault(setCode, setCode);
|
||||
String name = card.getCardName() + " (" + setCode + ") " + card.getCardNum();
|
||||
String code = prefix + name;
|
||||
int curAmount = amount.getOrDefault(code, 0);
|
||||
if (curAmount == 0) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public class MtgArenaDeckExporterTest {
|
|||
deck.getCards().add(new DeckCardInfo("Plains", "2", "RNA", 3));
|
||||
deck.getCards().add(new DeckCardInfo("Plains", "2", "RNA", 5)); // must combine
|
||||
deck.getCards().add(new DeckCardInfo("Mountain", "3", "RNA", 1));
|
||||
deck.getCards().add(new DeckCardInfo("Goblin Chainwhirler", "129", "DOM", 4));
|
||||
deck.getSideboard().add(new DeckCardInfo("Island", "1", "RNA", 2));
|
||||
deck.getSideboard().add(new DeckCardInfo("Island", "1", "RNA", 5)); // must combine
|
||||
deck.getSideboard().add(new DeckCardInfo("Mountain", "2", "RNA", 3));
|
||||
|
|
@ -30,6 +31,7 @@ public class MtgArenaDeckExporterTest {
|
|||
assertEquals("2 Forest (RNA) 1" + System.lineSeparator() +
|
||||
"8 Plains (RNA) 2" + System.lineSeparator() +
|
||||
"1 Mountain (RNA) 3" + System.lineSeparator() +
|
||||
"4 Goblin Chainwhirler (DAR) 129" + System.lineSeparator() +
|
||||
System.lineSeparator() +
|
||||
"7 Island (RNA) 1" + System.lineSeparator() +
|
||||
"3 Mountain (RNA) 2" + System.lineSeparator(),
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ public abstract class DeckImporter {
|
|||
return new CodDeckImporter();
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("o8d")) {
|
||||
return new O8dDeckImporter();
|
||||
} else if (file.toLowerCase(Locale.ENGLISH).endsWith("draft")) {
|
||||
return new DraftLogImporter();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
package mage.cards.decks.importer;
|
||||
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.repository.CardCriteria;
|
||||
import mage.cards.repository.CardInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DraftLogImporter extends PlainTextDeckImporter {
|
||||
|
||||
private static Pattern SET_PATTERN = Pattern.compile("------ (\\p{Alnum}+) ------$");
|
||||
private static Pattern PICK_PATTERN = Pattern.compile("--> (.+)$");
|
||||
|
||||
private String currentSet = null;
|
||||
|
||||
@Override
|
||||
protected void readLine(String line, DeckCardLists deckList) {
|
||||
Matcher setMatcher = SET_PATTERN.matcher(line);
|
||||
if (setMatcher.matches()) {
|
||||
currentSet = setMatcher.group(1);
|
||||
return;
|
||||
}
|
||||
|
||||
Matcher pickMatcher = PICK_PATTERN.matcher(line);
|
||||
if (pickMatcher.matches()) {
|
||||
String name = pickMatcher.group(1);
|
||||
List<CardInfo> cards = getCardLookup().lookupCardInfo(new CardCriteria().setCodes(currentSet).name(name));
|
||||
CardInfo card = null;
|
||||
if (!cards.isEmpty()) {
|
||||
card = cards.get(0);
|
||||
} else {
|
||||
card = getCardLookup().lookupCardInfo(name).orElse(null);
|
||||
}
|
||||
|
||||
if (card != null) {
|
||||
deckList.getCards().add(new DeckCardInfo(card.getName(), card.getCardNumber(), card.getSetCode()));
|
||||
} else {
|
||||
sbMessage.append("couldn't find: \"").append(name).append("\"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -79,8 +79,36 @@ public class TxtDeckImporter extends PlainTextDeckImporter {
|
|||
if (delim < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
String lineNum = line.substring(0, delim).trim();
|
||||
String lineName = line.substring(delim).replace("'", "\'").trim();
|
||||
if (IGNORE_NAMES.contains(lineNum)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// amount
|
||||
int cardAmount = 0;
|
||||
boolean haveCardAmout;
|
||||
try {
|
||||
cardAmount = Integer.parseInt(lineNum.replaceAll("\\D+", ""));
|
||||
if ((cardAmount <= 0) || (cardAmount >= 100)) {
|
||||
sbMessage.append("Invalid number (too small or too big): ").append(lineNum).append(" at line ").append(lineCount).append('\n');
|
||||
return;
|
||||
}
|
||||
haveCardAmout = true;
|
||||
} catch (NumberFormatException nfe) {
|
||||
haveCardAmout = false;
|
||||
//sbMessage.append("Invalid number: ").append(lineNum).append(" at line ").append(lineCount).append('\n');
|
||||
//return;
|
||||
}
|
||||
|
||||
String lineName;
|
||||
if (haveCardAmout) {
|
||||
lineName = line.substring(delim).trim();
|
||||
} else {
|
||||
lineName = line.trim();
|
||||
cardAmount = 1;
|
||||
}
|
||||
|
||||
lineName = lineName
|
||||
.replace("&", "//")
|
||||
.replace("Æ", "Ae")
|
||||
|
|
@ -96,33 +124,23 @@ public class TxtDeckImporter extends PlainTextDeckImporter {
|
|||
}
|
||||
lineName = lineName.replaceFirst("(?<=[^/])\\s*/\\s*(?=[^/])", " // ");
|
||||
|
||||
if (IGNORE_NAMES.contains(lineName) || IGNORE_NAMES.contains(lineNum)) {
|
||||
if (IGNORE_NAMES.contains(lineName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
wasCardLines = true;
|
||||
|
||||
try {
|
||||
int num = Integer.parseInt(lineNum.replaceAll("\\D+", ""));
|
||||
if ((num < 0) || (num > 100)) {
|
||||
sbMessage.append("Invalid number (too small or too big): ").append(lineNum).append(" at line ").append(lineCount).append('\n');
|
||||
return;
|
||||
}
|
||||
|
||||
CardInfo cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(lineName, true);
|
||||
if (cardInfo == null) {
|
||||
sbMessage.append("Could not find card: '").append(lineName).append("' at line ").append(lineCount).append('\n');
|
||||
} else {
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (!sideboard && !singleLineSideBoard) {
|
||||
deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()));
|
||||
} else {
|
||||
deckList.getSideboard().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()));
|
||||
}
|
||||
CardInfo cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(lineName, true);
|
||||
if (cardInfo == null) {
|
||||
sbMessage.append("Could not find card: '").append(lineName).append("' at line ").append(lineCount).append('\n');
|
||||
} else {
|
||||
for (int i = 0; i < cardAmount; i++) {
|
||||
if (!sideboard && !singleLineSideBoard) {
|
||||
deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()));
|
||||
} else {
|
||||
deckList.getSideboard().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()));
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
sbMessage.append("Invalid number: ").append(lineNum).append(" at line ").append(lineCount).append('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,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 = 220;
|
||||
private static final long CARD_CONTENT_VERSION = 222;
|
||||
private Dao<CardInfo, Object> cardDao;
|
||||
private Set<String> classNames;
|
||||
private RepositoryEventSource eventSource = new RepositoryEventSource();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.choices;
|
||||
|
||||
import mage.MageObject;
|
||||
|
|
@ -8,14 +7,13 @@ import mage.ObjectColor;
|
|||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||
*/
|
||||
public class ChoiceColor extends ChoiceImpl {
|
||||
|
||||
private static final ArrayList<String> colorChoices = getBaseColors();
|
||||
private static final ArrayList<String> colorChoices = getBaseColors();
|
||||
|
||||
public static ArrayList<String> getBaseColors(){
|
||||
public static ArrayList<String> getBaseColors() {
|
||||
ArrayList<String> arr = new ArrayList<>();
|
||||
arr.add("Green");
|
||||
arr.add("Blue");
|
||||
|
|
@ -33,15 +31,15 @@ public class ChoiceColor extends ChoiceImpl {
|
|||
this(required, "Choose color");
|
||||
}
|
||||
|
||||
public ChoiceColor(boolean required, String chooseMessage){
|
||||
public ChoiceColor(boolean required, String chooseMessage) {
|
||||
this(required, chooseMessage, "");
|
||||
}
|
||||
|
||||
public ChoiceColor(boolean required, String chooseMessage, MageObject source){
|
||||
public ChoiceColor(boolean required, String chooseMessage, MageObject source) {
|
||||
this(required, chooseMessage, source.getIdName());
|
||||
}
|
||||
|
||||
public ChoiceColor(boolean required, String chooseMessage, String chooseSubMessage){
|
||||
public ChoiceColor(boolean required, String chooseMessage, String chooseSubMessage) {
|
||||
super(required);
|
||||
|
||||
this.choices.addAll(colorChoices);
|
||||
|
|
@ -59,6 +57,10 @@ public class ChoiceColor extends ChoiceImpl {
|
|||
return new ChoiceColor(this);
|
||||
}
|
||||
|
||||
public void removeColorFromChoices(String colorName) {
|
||||
this.choices.remove(colorName);
|
||||
}
|
||||
|
||||
public ObjectColor getColor() {
|
||||
if (choice == null) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,16 @@ public enum CardType {
|
|||
return text;
|
||||
}
|
||||
|
||||
public static CardType fromString(String value) {
|
||||
for (CardType ct : CardType.values()) {
|
||||
if (ct.toString().equals(value)) {
|
||||
return ct;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Can't find card type enum value: " + value);
|
||||
}
|
||||
|
||||
public boolean isPermanentType() {
|
||||
return permanentType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package mage.constants;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
*/
|
||||
public enum Duration {
|
||||
|
|
@ -12,6 +11,7 @@ public enum Duration {
|
|||
WhileInGraveyard("", false),
|
||||
EndOfTurn("until end of turn", true),
|
||||
UntilYourNextTurn("until your next turn", true),
|
||||
UntilEndOfYourNextTurn("until the end of your next turn", true),
|
||||
UntilSourceLeavesBattlefield("until {source} leaves the battlefield", true), // supported for continuous layered effects
|
||||
EndOfCombat("until end of combat", true),
|
||||
EndOfStep("until end of phase step", true),
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ public enum SubType {
|
|||
KOR("Kor", SubTypeSet.CreatureType),
|
||||
KRAKEN("Kraken", SubTypeSet.CreatureType),
|
||||
// L
|
||||
LADYOFPROPERETIQUETTE("Lady of Proper Etiquette", SubTypeSet.CreatureType, true), // Unglued
|
||||
LAMIA("Lamia", SubTypeSet.CreatureType),
|
||||
LAMMASU("Lammasu", SubTypeSet.CreatureType),
|
||||
LEECH("Leech", SubTypeSet.CreatureType),
|
||||
|
|
@ -392,6 +393,7 @@ public enum SubType {
|
|||
HUATLI("Huatli", SubTypeSet.PlaneswalkerType),
|
||||
JACE("Jace", SubTypeSet.PlaneswalkerType),
|
||||
KARN("Karn", SubTypeSet.PlaneswalkerType),
|
||||
KASMINA("Kasmina", SubTypeSet.PlaneswalkerType),
|
||||
KAYA("Kaya", SubTypeSet.PlaneswalkerType),
|
||||
KIORA("Kiora", SubTypeSet.PlaneswalkerType),
|
||||
KOTH("Koth", SubTypeSet.PlaneswalkerType),
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ public enum CounterType {
|
|||
VERSE("verse"),
|
||||
VITALITY("vitality"),
|
||||
VORTEX("vortex"),
|
||||
WAGE("wage"),
|
||||
WINCH("winch"),
|
||||
WIND("wind"),
|
||||
WISH("wish");
|
||||
|
|
@ -193,6 +194,11 @@ public enum CounterType {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static CounterType findByName(String name) {
|
||||
for (CounterType counterType : values()) {
|
||||
if (counterType.getName().equals(name)) {
|
||||
|
|
|
|||
|
|
@ -417,6 +417,12 @@ public final class StaticFilters {
|
|||
FILTER_PERMANENT_PLANESWALKER.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterPlaneswalkerPermanent FILTER_PERMANENT_PLANESWALKERS = new FilterPlaneswalkerPermanent("planeswalkers");
|
||||
|
||||
static {
|
||||
FILTER_PERMANENT_PLANESWALKERS.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterNonlandPermanent FILTER_PERMANENT_NON_LAND = new FilterNonlandPermanent();
|
||||
|
||||
static {
|
||||
|
|
@ -460,6 +466,12 @@ public final class StaticFilters {
|
|||
FILTER_SPELL_NON_CREATURE.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterSpell FILTER_SPELL_A_NON_CREATURE = (FilterSpell) new FilterSpell("a noncreature spell").add(Predicates.not(new CardTypePredicate(CardType.CREATURE)));
|
||||
|
||||
static {
|
||||
FILTER_SPELL_A_NON_CREATURE.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterSpell FILTER_SPELL = new FilterSpell();
|
||||
|
||||
static {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
|
||||
|
||||
package mage.filter.common;
|
||||
|
||||
import mage.MageItem;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageItem;
|
||||
|
||||
/**
|
||||
* @author nantuko
|
||||
|
|
@ -28,24 +26,24 @@ public class FilterPermanentOrPlayerWithCounter extends FilterPermanentOrPlayer
|
|||
|
||||
@Override
|
||||
public boolean match(MageItem o, Game game) {
|
||||
if (o instanceof Player) {
|
||||
if (((Player)o).getCounters().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
} else if (o instanceof Permanent) {
|
||||
if (((Permanent)o).getCounters(game).isEmpty()) {
|
||||
return false;
|
||||
if (super.match(o, game)) {
|
||||
if (o instanceof Player) {
|
||||
return !((Player) o).getCounters().isEmpty();
|
||||
} else if (o instanceof Permanent) {
|
||||
return !((Permanent) o).getCounters(game).isEmpty();
|
||||
}
|
||||
}
|
||||
return super.match(o, game);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(MageItem o, UUID sourceId, UUID playerId, Game game) {
|
||||
if (o instanceof Player) {
|
||||
return playerFilter.match((Player) o, sourceId, playerId, game);
|
||||
} else if (o instanceof Permanent) {
|
||||
return permanentFilter.match((Permanent) o, sourceId, playerId, game);
|
||||
if (super.match(o, sourceId, playerId, game)) {
|
||||
if (o instanceof Player) {
|
||||
return !((Player) o).getCounters().isEmpty();
|
||||
} else if (o instanceof Permanent) {
|
||||
return !((Permanent) o).getCounters(game).isEmpty();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
package mage.filter.common;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class FilterPlaneswalkerPermanent extends FilterPermanent {
|
||||
|
|
@ -16,6 +17,11 @@ public class FilterPlaneswalkerPermanent extends FilterPermanent {
|
|||
this("planeswalker");
|
||||
}
|
||||
|
||||
public FilterPlaneswalkerPermanent(SubType subType) {
|
||||
this(subType.getDescription() + " planeswalker");
|
||||
this.add(new SubtypePredicate(subType));
|
||||
}
|
||||
|
||||
public FilterPlaneswalkerPermanent(String name) {
|
||||
super(name);
|
||||
this.add(new CardTypePredicate(CardType.PLANESWALKER));
|
||||
|
|
|
|||
|
|
@ -1,22 +1,15 @@
|
|||
|
||||
package mage.game;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import mage.cards.Card;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.util.Copyable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class Exile implements Serializable, Copyable<Exile> {
|
||||
|
|
@ -114,4 +107,17 @@ public class Exile implements Serializable, Copyable<Exile> {
|
|||
exile.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanupEndOfTurnZones(Game game) {
|
||||
// moves cards from outdated zone to main exile zone
|
||||
ExileZone mainZone = getExileZone(PERMANENT);
|
||||
for (ExileZone zone : exileZones.values()) {
|
||||
if (zone.isCleanupOnEndTurn()) {
|
||||
for (Card card : zone.getCards(game)) {
|
||||
mainZone.add(card);
|
||||
zone.remove(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
|
||||
|
||||
package mage.game;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.cards.CardsImpl;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class ExileZone extends CardsImpl {
|
||||
|
|
@ -15,16 +12,22 @@ public class ExileZone extends CardsImpl {
|
|||
private UUID id;
|
||||
private String name;
|
||||
private boolean hidden;
|
||||
private boolean cleanupOnEndTurn = false; // moved cards from that zone to default on end of turn (to cleanup exile windows)
|
||||
|
||||
public ExileZone(UUID id, String name) {
|
||||
this(id, name, false);
|
||||
}
|
||||
|
||||
public ExileZone(UUID id, String name, boolean hidden) {
|
||||
this(id, name, false, false);
|
||||
}
|
||||
|
||||
public ExileZone(UUID id, String name, boolean hidden, boolean cleanupOnEndTurn) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.hidden = hidden;
|
||||
this.cleanupOnEndTurn = cleanupOnEndTurn;
|
||||
}
|
||||
|
||||
public ExileZone(final ExileZone zone) {
|
||||
|
|
@ -32,6 +35,7 @@ public class ExileZone extends CardsImpl {
|
|||
this.id = zone.id;
|
||||
this.name = zone.name;
|
||||
this.hidden = zone.hidden;
|
||||
this.cleanupOnEndTurn = zone.cleanupOnEndTurn;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
|
|
@ -46,6 +50,14 @@ public class ExileZone extends CardsImpl {
|
|||
return hidden;
|
||||
}
|
||||
|
||||
public boolean isCleanupOnEndTurn() {
|
||||
return cleanupOnEndTurn;
|
||||
}
|
||||
|
||||
public void setCleanupOnEndTurn(boolean cleanupOnEndTurn) {
|
||||
this.cleanupOnEndTurn = cleanupOnEndTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExileZone copy() {
|
||||
return new ExileZone(this);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.events.Listener;
|
||||
import mage.game.events.PlayerQueryEvent;
|
||||
import mage.game.events.TableEvent;
|
||||
import mage.game.match.Match;
|
||||
import mage.game.match.MatchType;
|
||||
import mage.game.mulligan.Mulligan;
|
||||
import mage.game.permanent.Battlefield;
|
||||
|
|
@ -134,7 +133,7 @@ public interface Game extends MageItem, Serializable {
|
|||
|
||||
|
||||
default boolean isActivePlayer(UUID playerId) {
|
||||
return getActivePlayerId().equals(playerId);
|
||||
return getActivePlayerId() != null && getActivePlayerId().equals(playerId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -433,7 +432,7 @@ public interface Game extends MageItem, Serializable {
|
|||
// game cheats (for tests only)
|
||||
void cheat(UUID ownerId, Map<Zone, String> commands);
|
||||
|
||||
void cheat(UUID ownerId, List<Card> library, List<Card> hand, List<PermanentCard> battlefield, List<Card> graveyard);
|
||||
void cheat(UUID ownerId, UUID activePlayerId, List<Card> library, List<Card> hand, List<PermanentCard> battlefield, List<Card> graveyard, List<Card> command);
|
||||
|
||||
// controlling the behaviour of replacement effects while permanents entering the battlefield
|
||||
void setScopeRelevant(boolean scopeRelevant);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
|
||||
@Override
|
||||
protected void init(UUID choosingPlayerId) {
|
||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
|
||||
//Move commander to command zone
|
||||
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||
Player player = getPlayer(playerId);
|
||||
|
|
@ -49,7 +48,7 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
for (UUID commanderId : player.getCommandersIds()) {
|
||||
Card commander = this.getCard(commanderId);
|
||||
if (commander != null) {
|
||||
initCommander(commander, ability, player);
|
||||
initCommander(commander, player);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -57,20 +56,20 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
Card commander = this.getCard(player.getSideboard().iterator().next());
|
||||
if (commander != null) {
|
||||
player.addCommanderId(commander.getId());
|
||||
initCommander(commander, ability, player);
|
||||
initCommander(commander, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.getState().addAbility(ability, null);
|
||||
super.init(choosingPlayerId);
|
||||
if (startingPlayerSkipsDraw) {
|
||||
state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW));
|
||||
}
|
||||
}
|
||||
|
||||
private void initCommander(Card commander, Ability ability, Player player) {
|
||||
public void initCommander(Card commander, Player player) {
|
||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
|
||||
commander.moveToZone(Zone.COMMAND, null, this, true);
|
||||
commander.getAbilities().setControllerId(player.getId());
|
||||
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary));
|
||||
|
|
@ -79,6 +78,7 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), checkCommanderDamage);
|
||||
getState().addWatcher(watcher);
|
||||
watcher.addCardInfoToCommander(this);
|
||||
this.getState().addAbility(ability, null);
|
||||
}
|
||||
|
||||
//20130711
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import mage.game.command.Emblem;
|
|||
import mage.game.command.Plane;
|
||||
import mage.game.events.*;
|
||||
import mage.game.events.TableEvent.EventType;
|
||||
import mage.game.mulligan.LondonMulligan;
|
||||
import mage.game.mulligan.Mulligan;
|
||||
import mage.game.permanent.Battlefield;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
|
@ -128,7 +127,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
private int priorityTime;
|
||||
|
||||
private final int startLife;
|
||||
protected PlayerList playerList;
|
||||
protected PlayerList playerList; // auto-generated from state, don't copy
|
||||
|
||||
// infinite loop check (no copy of this attributes neccessary)
|
||||
private int infiniteLoopCounter; // used to check if the game is in an infinite loop
|
||||
|
|
@ -138,8 +137,9 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
|
||||
// used to set the counters a permanent adds the battlefield (if no replacement effect is used e.g. Persist)
|
||||
protected Map<UUID, Counters> enterWithCounters = new HashMap<>();
|
||||
// used to proceed player conceding requests
|
||||
private final LinkedList<UUID> concedingPlayers = new LinkedList<>(); // used to handle asynchronous request of a player to leave the game
|
||||
|
||||
// temporary store for income concede commands, don't copy
|
||||
private final LinkedList<UUID> concedingPlayers = new LinkedList<>();
|
||||
|
||||
public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) {
|
||||
this.id = UUID.randomUUID();
|
||||
|
|
@ -2851,25 +2851,40 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void cheat(UUID ownerId, List<Card> library, List<Card> hand, List<PermanentCard> battlefield, List<Card> graveyard) {
|
||||
public void cheat(UUID ownerId, UUID activePlayerId, List<Card> library, List<Card> hand, List<PermanentCard> battlefield, List<Card> graveyard, List<Card> command) {
|
||||
Player player = getPlayer(ownerId);
|
||||
if (player != null) {
|
||||
loadCards(ownerId, library);
|
||||
loadCards(ownerId, hand);
|
||||
loadCards(ownerId, battlefield);
|
||||
loadCards(ownerId, graveyard);
|
||||
loadCards(ownerId, command);
|
||||
|
||||
for (Card card : library) {
|
||||
player.getLibrary().putOnTop(card, this);
|
||||
}
|
||||
|
||||
for (Card card : hand) {
|
||||
card.setZone(Zone.HAND, this);
|
||||
player.getHand().add(card);
|
||||
}
|
||||
|
||||
for (Card card : graveyard) {
|
||||
card.setZone(Zone.GRAVEYARD, this);
|
||||
player.getGraveyard().add(card);
|
||||
}
|
||||
|
||||
// as commander (only commander games, look at init code in GameCommanderImpl)
|
||||
if (this instanceof GameCommanderImpl) {
|
||||
for (Card card : command) {
|
||||
player.addCommanderId(card.getId());
|
||||
// no needs in initCommander call -- it's uses on game startup (init)
|
||||
}
|
||||
} else if (!command.isEmpty()) {
|
||||
throw new IllegalArgumentException("Command zone supports in commander test games");
|
||||
}
|
||||
|
||||
// warning, permanents go to battlefield without resolve, continuus effects must be init
|
||||
for (PermanentCard permanentCard : battlefield) {
|
||||
permanentCard.setZone(Zone.BATTLEFIELD, this);
|
||||
permanentCard.setOwnerId(ownerId);
|
||||
|
|
@ -2882,6 +2897,14 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
if (permanentCard.isTapped()) {
|
||||
newPermanent.setTapped(true);
|
||||
}
|
||||
|
||||
// init effects on static abilities (init continuous effects, warning, game state contains copy)
|
||||
for (ContinuousEffect effect : this.getState().getContinuousEffects().getLayeredEffects(this)) {
|
||||
Optional<Ability> ability = this.getState().getContinuousEffects().getLayeredEffectAbilities(effect).stream().findFirst();
|
||||
if (ability.isPresent() && newPermanent.getId().equals(ability.get().getSourceId())) {
|
||||
effect.init(ability.get(), this, activePlayerId); // game is not setup yet, game.activePlayer is null -- need direct id
|
||||
}
|
||||
}
|
||||
}
|
||||
applyEffects();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -569,17 +569,20 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
combat.checkForRemoveFromCombat(game);
|
||||
}
|
||||
|
||||
// Remove End of Combat effects
|
||||
// remove end of combat effects
|
||||
public void removeEocEffects(Game game) {
|
||||
effects.removeEndOfCombatEffects();
|
||||
delayed.removeEndOfCombatAbilities();
|
||||
game.applyEffects();
|
||||
}
|
||||
|
||||
// remove end of turn effects
|
||||
public void removeEotEffects(Game game) {
|
||||
effects.removeEndOfTurnEffects();
|
||||
delayed.removeEndOfTurnAbilities();
|
||||
effects.removeEndOfTurnEffects(game);
|
||||
delayed.removeEndOfTurnAbilities(game);
|
||||
exile.cleanupEndOfTurnZones(game);
|
||||
game.applyEffects();
|
||||
effects.incYourTurnNumPlayed(game);
|
||||
}
|
||||
|
||||
public void addEffect(ContinuousEffect effect, Ability source) {
|
||||
|
|
@ -787,7 +790,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
public void addCard(Card card) {
|
||||
setZone(card.getId(), Zone.OUTSIDE);
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
addAbility(ability, card);
|
||||
addAbility(ability, null, card);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
|
||||
package mage.game;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
|
|
@ -21,8 +17,11 @@ import mage.game.turn.TurnMod;
|
|||
import mage.players.Player;
|
||||
import mage.watchers.common.CommanderInfoWatcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JRHerlehy
|
||||
*/
|
||||
public abstract class GameTinyLeadersImpl extends GameImpl {
|
||||
|
|
@ -43,7 +42,6 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
|
|||
|
||||
@Override
|
||||
protected void init(UUID choosingPlayerId) {
|
||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
|
||||
//Move tiny leader to command zone
|
||||
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||
Player player = getPlayer(playerId);
|
||||
|
|
@ -55,6 +53,7 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
|
|||
this.loadCards(cards, playerId);
|
||||
player.addCommanderId(commander.getId());
|
||||
commander.moveToZone(Zone.COMMAND, null, this, true);
|
||||
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects"));
|
||||
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary));
|
||||
ability.addEffect(new CommanderCostModification(commander.getId()));
|
||||
// Commander rule #4 was removed Jan. 18, 2016
|
||||
|
|
@ -63,13 +62,13 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
|
|||
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), false);
|
||||
getState().addWatcher(watcher);
|
||||
watcher.addCardInfoToCommander(this);
|
||||
this.getState().addAbility(ability, null);
|
||||
} else {
|
||||
throw new UnknownError("Commander card could not be created. Name: [" + player.getMatchPlayer().getDeck().getName() + ']');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
this.getState().addAbility(ability, null);
|
||||
super.init(choosingPlayerId);
|
||||
if (startingPlayerSkipsDraw) {
|
||||
state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW));
|
||||
|
|
|
|||
|
|
@ -461,18 +461,14 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack);
|
||||
// No need to attack a special defender
|
||||
if (defendersForcedToAttack.isEmpty()) {
|
||||
if (defenders.size() == 1) {
|
||||
player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false);
|
||||
if (defendersCostlessAttackable.size() == 1) {
|
||||
player.declareAttacker(creature.getId(), defendersCostlessAttackable.iterator().next(), game, false);
|
||||
} else {
|
||||
if (!player.isHuman()) { // computer only for multiple defenders
|
||||
player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false);
|
||||
} else { // human players only for multiple defenders
|
||||
TargetDefender target = new TargetDefender(defenders, creature.getId());
|
||||
target.setRequired(true);
|
||||
target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack");
|
||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
|
||||
}
|
||||
TargetDefender target = new TargetDefender(defendersCostlessAttackable, creature.getId());
|
||||
target.setRequired(true);
|
||||
target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack (must attack effect)");
|
||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -481,6 +477,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
} else {
|
||||
TargetDefender target = new TargetDefender(defendersForcedToAttack, creature.getId());
|
||||
target.setRequired(true);
|
||||
target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack (must attack effect)");
|
||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
|
||||
}
|
||||
|
|
@ -555,7 +552,8 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
}
|
||||
for (UUID attackingCreatureID : game.getCombat().getAttackers()) {
|
||||
Permanent permanent = game.getPermanent(attackingCreatureID);
|
||||
if (permanent != null && permanent.getBlocking() == 0) {
|
||||
CombatGroup group = game.getCombat().findGroup(attackingCreatureID);
|
||||
if (permanent != null && group != null && !group.getBlocked()) {
|
||||
game.fireEvent(GameEvent.getEvent(EventType.UNBLOCKED_ATTACKER, attackingCreatureID, attackingPlayerId));
|
||||
}
|
||||
}
|
||||
|
|
@ -1539,6 +1537,18 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean isPlaneswalkerAttacked(UUID defenderId, Game game) {
|
||||
for (CombatGroup group : groups) {
|
||||
if (group.defenderIsPlaneswalker) {
|
||||
Permanent permanent = game.getPermanent(group.getDefenderId());
|
||||
if (permanent.isControlledBy(defenderId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attackerId
|
||||
* @return uuid of defending player or planeswalker
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
|
|||
import mage.game.command.Emblem;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class ElspethKnightErrantEmblem extends Emblem {
|
||||
|
|
@ -28,7 +27,7 @@ public final class ElspethKnightErrantEmblem extends Emblem {
|
|||
new CardTypePredicate(CardType.ENCHANTMENT),
|
||||
new CardTypePredicate(CardType.LAND)));
|
||||
Effect effect = new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter, false);
|
||||
effect.setText("Artifacts, creatures, enchantments, and lands you control are indestructible");
|
||||
effect.setText("Artifacts, creatures, enchantments, and lands you control have indestructible");
|
||||
this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, effect));
|
||||
this.setExpansionSetCodeForImage("MMA");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,10 +64,12 @@ class JayaBallardCastFromGraveyardEffect extends AsThoughEffectImpl {
|
|||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
Card card = game.getCard(objectId);
|
||||
if (card != null) {
|
||||
return (affectedControllerId.equals(source.getControllerId())
|
||||
&& StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game)
|
||||
&& Zone.GRAVEYARD.equals(game.getState().getZone(card.getId())));
|
||||
if (card != null
|
||||
&& affectedControllerId.equals(source.getControllerId())
|
||||
&& StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game)
|
||||
&& Zone.GRAVEYARD.equals(game.getState().getZone(card.getId()))) {
|
||||
game.getState().setValue("JayaBallard", card);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -98,7 +100,7 @@ class JayaBallardReplacementEffect extends ReplacementEffectImpl {
|
|||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
Card card = (Card) game.getState().getValue("JayaBallard");
|
||||
if (card != null) {
|
||||
controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.STACK, true);
|
||||
return true;
|
||||
|
|
@ -116,11 +118,13 @@ class JayaBallardReplacementEffect extends ReplacementEffectImpl {
|
|||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (Zone.GRAVEYARD == ((ZoneChangeEvent) event).getToZone()) {
|
||||
Card card = game.getCard(event.getSourceId());
|
||||
if (card != null && (card.isInstant() || card.isSorcery())) {
|
||||
// TODO: Find a way to check, that the spell from graveyard was really cast by the ability of the emblem.
|
||||
// currently every spell cast from graveyard will be exiled.
|
||||
if (card != null
|
||||
&& (card.isInstant()
|
||||
|| card.isSorcery())) {
|
||||
CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class);
|
||||
return watcher != null && watcher.spellWasCastFromGraveyard(event.getTargetId(), game.getState().getZoneChangeCounter(event.getTargetId()));
|
||||
return watcher != null
|
||||
&& watcher.spellWasCastFromGraveyard(event.getTargetId(),
|
||||
game.getState().getZoneChangeCounter(event.getTargetId()));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
package mage.game.command.emblems;
|
||||
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
|
||||
import mage.abilities.keyword.IndestructibleAbility;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.command.Emblem;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class NissaWhoShakesTheWorldEmblem extends Emblem {
|
||||
|
||||
public NissaWhoShakesTheWorldEmblem() {
|
||||
this.setName("Emblem Nissa");
|
||||
this.getAbilities().add(new SimpleStaticAbility(
|
||||
Zone.COMMAND,
|
||||
new GainAbilityAllEffect(
|
||||
IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield,
|
||||
StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, false
|
||||
)
|
||||
));
|
||||
this.setExpansionSetCodeForImage("WAR");
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import java.util.Objects;
|
|||
import java.util.UUID;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.ExpansionSet;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -13,7 +14,10 @@ import mage.cards.ExpansionSet;
|
|||
*/
|
||||
public class RichManBoosterDraft extends DraftImpl {
|
||||
|
||||
protected int[] richManTimes = {75, 70, 65, 60, 55, 50, 45, 40, 35, 35, 35, 35, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25};
|
||||
private static final Logger logger = Logger.getLogger(RichManBoosterDraft.class);
|
||||
|
||||
//protected int[] richManTimes = {75, 70, 65, 60, 55, 50, 45, 40, 35, 35, 35, 35, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25};
|
||||
protected int[] richManTimes = {70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40};
|
||||
|
||||
public RichManBoosterDraft(DraftOptions options, List<ExpansionSet> sets) {
|
||||
super(options, sets);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ import mage.game.draft.DraftCube.CardIdentity;
|
|||
*/
|
||||
public class RichManCubeBoosterDraft extends DraftImpl {
|
||||
|
||||
protected int[] richManTimes = {75, 70, 65, 60, 55, 50, 45, 40, 35, 35, 35, 35, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25};
|
||||
//protected int[] richManTimes = {75, 70, 65, 60, 55, 50, 45, 40, 35, 35, 35, 35, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25};
|
||||
protected int[] richManTimes = {70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40};
|
||||
protected final Map<String, CardIdentity> cardsInCube = new LinkedHashMap<>();
|
||||
|
||||
public RichManCubeBoosterDraft(DraftOptions options, List<ExpansionSet> sets) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ public class GameEvent implements Serializable {
|
|||
protected UUID sourceId;
|
||||
protected UUID playerId;
|
||||
protected int amount;
|
||||
// flags:
|
||||
// for counters: event is result of effect (+1 from planeswalkers is cost, not effect)
|
||||
// for combat damage: event is preventable damage
|
||||
protected boolean flag;
|
||||
protected String data;
|
||||
protected Zone zone;
|
||||
|
|
@ -292,7 +295,7 @@ public class GameEvent implements Serializable {
|
|||
UNATTACH, UNATTACHED,
|
||||
ADD_COUNTER, COUNTER_ADDED,
|
||||
ADD_COUNTERS, COUNTERS_ADDED,
|
||||
COUNTER_REMOVED,
|
||||
COUNTER_REMOVED, COUNTERS_REMOVED,
|
||||
LOSE_CONTROL,
|
||||
/* LOST_CONTROL
|
||||
targetId id of the creature that lost control
|
||||
|
|
@ -433,6 +436,17 @@ public class GameEvent implements Serializable {
|
|||
this.amount = amount;
|
||||
}
|
||||
|
||||
public void setAmountForCounters(int amount, boolean isEffect) {
|
||||
this.amount = amount;
|
||||
|
||||
// cost event must be "transformed" to effect event, as example:
|
||||
// planeswalker's +1 cost will be affected by Pir, Imaginative Rascal (1 + 1) and applied as effect by Doubling Season (2 * 2)
|
||||
// https://github.com/magefree/mage/issues/5802
|
||||
if (isEffect) {
|
||||
setFlag(true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getFlag() {
|
||||
return flag;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -909,7 +909,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
if (countersToRemove > getCounters(game).getCount(CounterType.LOYALTY)) {
|
||||
countersToRemove = getCounters(game).getCount(CounterType.LOYALTY);
|
||||
}
|
||||
getCounters(game).removeCounter(CounterType.LOYALTY, countersToRemove);
|
||||
removeCounters(CounterType.LOYALTY.getName(), countersToRemove, game);
|
||||
game.fireEvent(new DamagedPlaneswalkerEvent(objectId, sourceId, controllerId, actualDamage, combat));
|
||||
return actualDamage;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ public final class AssassinToken2 extends TokenImpl {
|
|||
toughness = new MageInt(1);
|
||||
addAbility(DeathtouchAbility.getInstance());
|
||||
addAbility(new AssassinToken2TriggeredAbility());
|
||||
|
||||
setOriginalExpansionSetCode("WAR");
|
||||
}
|
||||
|
||||
private AssassinToken2(final AssassinToken2 token) {
|
||||
|
|
@ -40,7 +42,7 @@ public final class AssassinToken2 extends TokenImpl {
|
|||
class AssassinToken2TriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
AssassinToken2TriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new DestroyTargetEffect());
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
}
|
||||
|
||||
private AssassinToken2TriggeredAbility(final AssassinToken2TriggeredAbility effect) {
|
||||
|
|
@ -60,9 +62,10 @@ class AssassinToken2TriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getSourceId().equals(getSourceId())) {
|
||||
for (Effect effect : this.getAllEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||
}
|
||||
Effect effect = new DestroyTargetEffect();
|
||||
effect.setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
this.getEffects().clear();
|
||||
this.addEffect(effect);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
|
||||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public final class DragonToken extends TokenImpl {
|
||||
|
|
@ -19,7 +17,7 @@ public final class DragonToken extends TokenImpl {
|
|||
static final private List<String> tokenImageSets = new ArrayList<>();
|
||||
|
||||
static {
|
||||
tokenImageSets.addAll(Arrays.asList("DTK", "MMA", "ALA", "MM3", "C17"));
|
||||
tokenImageSets.addAll(Arrays.asList("DTK", "MMA", "ALA", "MM3", "C17", "WAR"));
|
||||
}
|
||||
|
||||
public DragonToken() {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public final class GoblinToken extends TokenImpl {
|
|||
static {
|
||||
tokenImageSets.addAll(Arrays.asList("10E", "ALA", "SOM", "M10", "NPH", "M13", "RTR",
|
||||
"MMA", "M15", "C14", "KTK", "EVG", "DTK", "ORI", "DDG", "DDN", "DD3EVG", "MM2",
|
||||
"MM3", "EMA", "C16", "DOM", "ANA", "RNA"));
|
||||
"MM3", "EMA", "C16", "DOM", "ANA", "RNA", "WAR"));
|
||||
}
|
||||
|
||||
public GoblinToken(boolean withHaste) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.keyword.VigilanceAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class GodEternalOketraToken extends TokenImpl {
|
||||
|
||||
public GodEternalOketraToken() {
|
||||
super("Zombie Warrior", "4/4 black Zombie Warrior creature token with vigilance");
|
||||
setOriginalExpansionSetCode("WAR"); // default
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setBlack(true);
|
||||
subtype.add(SubType.ZOMBIE);
|
||||
subtype.add(SubType.WARRIOR);
|
||||
power = new MageInt(4);
|
||||
toughness = new MageInt(4);
|
||||
addAbility(VigilanceAbility.getInstance());
|
||||
}
|
||||
|
||||
private GodEternalOketraToken(final GodEternalOketraToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GodEternalOketraToken copy() {
|
||||
return new GodEternalOketraToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class PlanewideCelebrationToken extends TokenImpl {
|
||||
|
||||
public PlanewideCelebrationToken() {
|
||||
super("Citizen", "2/2 Citizen creature token that's all colors");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setWhite(true);
|
||||
color.setBlue(true);
|
||||
color.setBlack(true);
|
||||
color.setRed(true);
|
||||
color.setGreen(true);
|
||||
|
||||
subtype.add(SubType.CITIZEN);
|
||||
power = new MageInt(2);
|
||||
toughness = new MageInt(2);
|
||||
}
|
||||
|
||||
public PlanewideCelebrationToken(final PlanewideCelebrationToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public PlanewideCelebrationToken copy() {
|
||||
return new PlanewideCelebrationToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.MageInt;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class RevelOfTheFallenGodSatyrToken extends TokenImpl {
|
||||
|
||||
public RevelOfTheFallenGodSatyrToken() {
|
||||
super("Satyr", "2/2 red and green Satyr creature tokens with haste");
|
||||
this.setOriginalExpansionSetCode("THS");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setColor(ObjectColor.RED);
|
||||
color.setColor(ObjectColor.GREEN);
|
||||
subtype.add(SubType.SATYR);
|
||||
power = new MageInt(2);
|
||||
toughness = new MageInt(2);
|
||||
addAbility(HasteAbility.getInstance());
|
||||
}
|
||||
|
||||
public RevelOfTheFallenGodSatyrToken(final RevelOfTheFallenGodSatyrToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public RevelOfTheFallenGodSatyrToken copy() {
|
||||
return new RevelOfTheFallenGodSatyrToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ public final class ServoToken extends TokenImpl {
|
|||
|
||||
static {
|
||||
tokenImageSets.addAll(Collections.singletonList("KLD"));
|
||||
tokenImageSets.addAll(Collections.singletonList("WAR"));
|
||||
}
|
||||
|
||||
public ServoToken() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.keyword.VigilanceAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class SoldierVigilanceToken extends TokenImpl {
|
||||
|
||||
public SoldierVigilanceToken() {
|
||||
super("Soldier", "2/2 white Soldier creature token with vigilance");
|
||||
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setWhite(true);
|
||||
subtype.add(SubType.SOLDIER);
|
||||
power = new MageInt(2);
|
||||
toughness = new MageInt(2);
|
||||
addAbility(VigilanceAbility.getInstance());
|
||||
|
||||
setOriginalExpansionSetCode("WAR");
|
||||
}
|
||||
|
||||
private SoldierVigilanceToken(final SoldierVigilanceToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoldierVigilanceToken copy() {
|
||||
return new SoldierVigilanceToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,8 @@ public final class TeyoToken extends TokenImpl {
|
|||
power = new MageInt(0);
|
||||
toughness = new MageInt(3);
|
||||
addAbility(DefenderAbility.getInstance());
|
||||
|
||||
setOriginalExpansionSetCode("WAR");
|
||||
}
|
||||
|
||||
public TeyoToken(final TeyoToken token) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class UginTheIneffableToken extends TokenImpl {
|
||||
|
||||
public UginTheIneffableToken() {
|
||||
super("Spirit", "2/2 colorless Spirit creature token");
|
||||
setExpansionSetCodeForImage("WAR"); // default
|
||||
cardType.add(CardType.CREATURE);
|
||||
subtype.add(SubType.SPIRIT);
|
||||
power = new MageInt(2);
|
||||
toughness = new MageInt(2);
|
||||
}
|
||||
|
||||
private UginTheIneffableToken(final UginTheIneffableToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UginTheIneffableToken copy() {
|
||||
return new UginTheIneffableToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class VojaFriendToElvesToken extends TokenImpl {
|
||||
|
||||
public VojaFriendToElvesToken() {
|
||||
super("Voja, Friend to Elves", "Voja, Friend to Elves, a legendary 3/3 green and white Wolf creature token");
|
||||
this.cardType.add(CardType.CREATURE);
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.WOLF);
|
||||
|
||||
this.color.setGreen(true);
|
||||
this.color.setWhite(true);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
setOriginalExpansionSetCode("WAR");
|
||||
}
|
||||
|
||||
private VojaFriendToElvesToken(final VojaFriendToElvesToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public VojaFriendToElvesToken copy() {
|
||||
return new VojaFriendToElvesToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
public final class WizardToken extends TokenImpl {
|
||||
|
||||
public WizardToken() {
|
||||
this("WAR");
|
||||
}
|
||||
|
||||
public WizardToken(String setCode) {
|
||||
super("Wizard", "2/2 blue Wizard creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
subtype.add(SubType.WIZARD);
|
||||
color.setBlue(true);
|
||||
power = new MageInt(2);
|
||||
toughness = new MageInt(2);
|
||||
|
||||
setOriginalExpansionSetCode(setCode);
|
||||
}
|
||||
|
||||
private WizardToken(final WizardToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public WizardToken copy() {
|
||||
return new WizardToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ public final class WolfToken extends TokenImpl {
|
|||
static final private List<String> tokenImageSets = new ArrayList<>();
|
||||
|
||||
static {
|
||||
tokenImageSets.addAll(Arrays.asList("BNG", "C14", "CNS", "FNMP", "ISD", "LRW", "M10", "M14", "MM2", "SHM", "SOM", "ZEN", "SOI", "C15", "M15"));
|
||||
tokenImageSets.addAll(Arrays.asList("BNG", "C14", "CNS", "FNMP", "ISD", "LRW", "M10", "M14", "MM2", "SHM", "SOM", "ZEN", "SOI", "C15", "M15", "WAR"));
|
||||
}
|
||||
|
||||
public WolfToken() {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public final class ZombieToken extends TokenImpl {
|
|||
|
||||
static {
|
||||
tokenImageSets.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "C15", "C16", "C17", "CNS",
|
||||
"MMA", "BNG", "KTK", "DTK", "ORI", "OGW", "SOI", "EMN", "EMA", "MM3", "AKH", "CMA", "E01", "RNA"));
|
||||
"MMA", "BNG", "KTK", "DTK", "ORI", "OGW", "SOI", "EMN", "EMA", "MM3", "AKH", "CMA", "E01", "RNA", "WAR"));
|
||||
}
|
||||
|
||||
public ZombieToken() {
|
||||
|
|
|
|||
|
|
@ -188,6 +188,11 @@ public abstract class StackObjImpl implements StackObject {
|
|||
newTarget.clearChosen();
|
||||
}
|
||||
}
|
||||
|
||||
// workaround to stop infinite AI choose (remove after chooseTarget can be called with extra filter to disable some ids)
|
||||
if (iteration > 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (targetController.canRespond() && (targetId.equals(newTarget.getFirstTarget()) || newTarget.getTargets().size() != 1));
|
||||
// choose a new target
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
|
||||
|
||||
package mage.game.tournament;
|
||||
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.game.draft.DraftCube;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.game.draft.DraftCube;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class LimitedOptions implements Serializable {
|
||||
|
|
@ -20,6 +18,7 @@ public class LimitedOptions implements Serializable {
|
|||
protected DraftCube draftCube;
|
||||
protected int numberBoosters;
|
||||
protected boolean isRandom;
|
||||
protected boolean isRichMan;
|
||||
protected Deck cubeFromDeck = null;
|
||||
|
||||
public List<String> getSetCodes() {
|
||||
|
|
@ -66,11 +65,19 @@ public class LimitedOptions implements Serializable {
|
|||
this.numberBoosters = numberBoosters;
|
||||
}
|
||||
|
||||
public boolean getIsRandom(){
|
||||
public boolean getIsRandom() {
|
||||
return isRandom;
|
||||
}
|
||||
public void setIsRandom(boolean isRandom){
|
||||
|
||||
public void setIsRandom(boolean isRandom) {
|
||||
this.isRandom = isRandom;
|
||||
}
|
||||
|
||||
public boolean getIsRichMan() {
|
||||
return isRichMan;
|
||||
}
|
||||
|
||||
public void setIsRichMan(boolean isRichMan) {
|
||||
this.isRichMan = isRichMan;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue