mirror of
https://github.com/magefree/mage.git
synced 2026-01-23 03:39:54 -08:00
Merge branch 'master' of https://github.com/magefree/mage.git into MorphRework_v2
# Conflicts: # Mage.Sets/src/mage/cards/b/Banefire.java
This commit is contained in:
commit
26af2602e4
484 changed files with 6960 additions and 5629 deletions
|
|
@ -1480,6 +1480,13 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
|
||||
public AbilityImpl copyWithZone(Zone zone) {
|
||||
if (this instanceof MageSingleton) {
|
||||
// not safe to change zone for singletons
|
||||
// in theory there could be some sort of wrapper to effectively change
|
||||
// the zone here, but currently no use of copyWithZone actually needs
|
||||
// to change the zone of any existing singleton abilities
|
||||
return this;
|
||||
}
|
||||
AbilityImpl copy = ((AbilityImpl)this.copy());
|
||||
copy.zone = zone;
|
||||
copy.newId();
|
||||
|
|
|
|||
|
|
@ -17,10 +17,6 @@ public interface TriggeredAbility extends Ability {
|
|||
* This check for the relevant event types is called at first to prevent
|
||||
* further actions if the current event is ignored from this triggered
|
||||
* ability
|
||||
*
|
||||
* @param event
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
boolean checkEventType(GameEvent event, Game game);
|
||||
|
||||
|
|
@ -30,10 +26,6 @@ public interface TriggeredAbility extends Ability {
|
|||
* multiple times. Because some abilities call this to check if an ability
|
||||
* is relevant (e.g. Torpor Orb), so the method is called multiple times for
|
||||
* the same event.
|
||||
*
|
||||
* @param event
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
boolean checkTrigger(GameEvent event, Game game);
|
||||
|
||||
|
|
@ -45,7 +37,10 @@ public interface TriggeredAbility extends Ability {
|
|||
|
||||
TriggeredAbility setDoOnlyOnceEachTurn(boolean doOnlyOnce);
|
||||
|
||||
TriggeredAbility setReplaceRuleText(boolean replaceRuleText);
|
||||
/**
|
||||
* if true, replaces "{this}" with "it" in the effect text
|
||||
*/
|
||||
TriggeredAbility withRuleTextReplacement(boolean replaceRuleText);
|
||||
|
||||
boolean checkInterveningIfClause(Game game);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
protected boolean leavesTheBattlefieldTrigger;
|
||||
private boolean triggersOnceEachTurn = false;
|
||||
private boolean doOnlyOnceEachTurn = false;
|
||||
protected boolean replaceRuleText = true;
|
||||
protected boolean replaceRuleText = false; // if true, replace "{this}" with "it" in effect text
|
||||
private GameEvent triggerEvent = null;
|
||||
private String triggerPhrase = null;
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
}
|
||||
|
||||
@Override
|
||||
public TriggeredAbility setReplaceRuleText(boolean replaceRuleText) {
|
||||
public TriggeredAbility withRuleTextReplacement(boolean replaceRuleText) {
|
||||
this.replaceRuleText = replaceRuleText;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -220,18 +220,8 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
superRule = superRule.replaceFirst(" (become|block|deal|discard|gain|get|lose|mill|sacrifice)s? ", " $1 ");
|
||||
}
|
||||
}
|
||||
if (replaceRuleText
|
||||
&& triggerPhrase != null
|
||||
&& triggerPhrase.contains("{this}")
|
||||
&& !triggerPhrase.contains("other")
|
||||
&& !triggerPhrase.contains(" of a ")
|
||||
&& !triggerPhrase.contains(" by a ")
|
||||
&& !triggerPhrase.contains(" to a ")
|
||||
&& !triggerPhrase.contains(" blocks a ")
|
||||
&& (superRule.startsWith("{this}")
|
||||
|| superRule.startsWith("sacrifice {this}")
|
||||
)) {
|
||||
superRule = superRule.replace("{this} ", "it ");
|
||||
if (replaceRuleText && triggerPhrase != null) {
|
||||
superRule = superRule.replaceFirst("^(sacrifice )?\\{this\\}", "$1it");
|
||||
}
|
||||
sb.append(superRule);
|
||||
if (triggersOnceEachTurn) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ public class AttacksAloneSourceTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public AttacksAloneSourceTriggeredAbility(Effect effect) {
|
||||
super(Zone.BATTLEFIELD, effect);
|
||||
setTriggerPhrase("Whenever {this} attacks alone, ");
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
}
|
||||
|
||||
protected AttacksAloneSourceTriggeredAbility(final AttacksAloneSourceTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ public class AttacksAndIsNotBlockedTriggeredAbility extends TriggeredAbilityImpl
|
|||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("Whenever {this} attacks and isn't blocked, ");
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
}
|
||||
|
||||
protected AttacksAndIsNotBlockedTriggeredAbility(final AttacksAndIsNotBlockedTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ public class AttacksOrBlocksTriggeredAbility extends TriggeredAbilityImpl {
|
|||
} else {
|
||||
setTriggerPhrase("Whenever {this} attacks or blocks, ");
|
||||
}
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
}
|
||||
|
||||
protected AttacksOrBlocksTriggeredAbility(final AttacksOrBlocksTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public class AttacksTriggeredAbility extends TriggeredAbilityImpl {
|
|||
this.text = text;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("Whenever {this} attacks, ");
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
}
|
||||
|
||||
protected AttacksTriggeredAbility(final AttacksTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public class BecomesBlockedSourceTriggeredAbility extends TriggeredAbilityImpl {
|
|||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("Whenever {this} becomes blocked, ");
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
}
|
||||
|
||||
protected BecomesBlockedSourceTriggeredAbility(final BecomesBlockedSourceTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ public class BecomesTappedSourceTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public BecomesTappedSourceTriggeredAbility(Effect effect, boolean isOptional) {
|
||||
super(Zone.BATTLEFIELD, effect, isOptional);
|
||||
setTriggerPhrase("Whenever {this} becomes tapped, ");
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
}
|
||||
|
||||
protected BecomesTappedSourceTriggeredAbility(final BecomesTappedSourceTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class BecomesTargetAnyTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterPermanent filterTarget;
|
||||
private final FilterStackObject filterStack;
|
||||
private final SetTargetPointer setTargetPointer;
|
||||
|
||||
public BecomesTargetAnyTriggeredAbility(Effect effect, FilterPermanent filterTarget) {
|
||||
this(effect, filterTarget, StaticFilters.FILTER_SPELL_OR_ABILITY_A);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Whenever [a filterTarget] becomes the target of [a filterStack], [effect]"
|
||||
* @param effect defaults to SetTargetPointer.PERMANENT
|
||||
* @param filterTarget permanents to check being targetted
|
||||
* @param filterStack spells/abilities to check targeting
|
||||
*/
|
||||
public BecomesTargetAnyTriggeredAbility(Effect effect, FilterPermanent filterTarget, FilterStackObject filterStack) {
|
||||
this(effect, filterTarget, filterStack, SetTargetPointer.PERMANENT, false);
|
||||
}
|
||||
|
||||
public BecomesTargetAnyTriggeredAbility(Effect effect, FilterPermanent filterTarget, FilterStackObject filterStack,
|
||||
SetTargetPointer setTargetPointer, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filterTarget = filterTarget;
|
||||
this.filterStack = filterStack;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("Whenever " + filterTarget.getMessage() + " becomes the target of "
|
||||
+ filterStack.getMessage() + ", ");
|
||||
}
|
||||
|
||||
protected BecomesTargetAnyTriggeredAbility(final BecomesTargetAnyTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filterTarget = ability.filterTarget;
|
||||
this.filterStack = ability.filterStack;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesTargetAnyTriggeredAbility copy() {
|
||||
return new BecomesTargetAnyTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (permanent == null || !filterTarget.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
StackObject targetingObject = CardUtil.getTargetingStackObject(event, game);
|
||||
if (targetingObject == null || !filterStack.match(targetingObject, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
if (CardUtil.checkTargetedEventAlreadyUsed(this.id.toString(), targetingObject, event, game)) {
|
||||
return false;
|
||||
}
|
||||
switch (setTargetPointer) {
|
||||
case PERMANENT:
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(permanent.getId(), game));
|
||||
break;
|
||||
case PLAYER:
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(targetingObject.getControllerId(), game));
|
||||
break;
|
||||
case SPELL:
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(targetingObject.getId()));
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported SetTargetPointer in BecomesTargetAnyTriggeredAbility");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package mage.abilities.common;
|
|||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.StaticFilters;
|
||||
|
|
@ -9,6 +10,8 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author LoneFox
|
||||
|
|
@ -16,24 +19,23 @@ import mage.game.permanent.Permanent;
|
|||
public class BecomesTargetAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterStackObject filter;
|
||||
private final SetTargetPointer setTargetPointer;
|
||||
|
||||
public BecomesTargetAttachedTriggeredAbility(Effect effect) {
|
||||
this(effect, StaticFilters.FILTER_SPELL_OR_ABILITY_A);
|
||||
this(effect, StaticFilters.FILTER_SPELL_OR_ABILITY_A, SetTargetPointer.NONE, false);
|
||||
}
|
||||
|
||||
public BecomesTargetAttachedTriggeredAbility(Effect effect, FilterStackObject filter) {
|
||||
this(effect, filter, "creature");
|
||||
}
|
||||
|
||||
public BecomesTargetAttachedTriggeredAbility(Effect effect, FilterStackObject filter, String enchantType) {
|
||||
super(Zone.BATTLEFIELD, effect);
|
||||
this.filter = filter.copy();
|
||||
setTriggerPhrase("When enchanted " + enchantType + " becomes the target of " + filter.getMessage() + ", ");
|
||||
public BecomesTargetAttachedTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("When enchanted creature becomes the target of " + filter.getMessage() + ", ");
|
||||
}
|
||||
|
||||
protected BecomesTargetAttachedTriggeredAbility(final BecomesTargetAttachedTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter.copy();
|
||||
this.filter = ability.filter;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -49,13 +51,28 @@ public class BecomesTargetAttachedTriggeredAbility extends TriggeredAbilityImpl
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent enchantment = game.getPermanent(sourceId);
|
||||
StackObject sourceObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (enchantment != null && enchantment.getAttachedTo() != null) {
|
||||
if (event.getTargetId().equals(enchantment.getAttachedTo())
|
||||
&& filter.match(sourceObject, getControllerId(), this, game)) {
|
||||
return true;
|
||||
}
|
||||
if (enchantment == null || enchantment.getAttachedTo() == null || !event.getTargetId().equals(enchantment.getAttachedTo())) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
StackObject targetingObject = CardUtil.getTargetingStackObject(event, game);
|
||||
if (targetingObject == null || !filter.match(targetingObject, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
if (CardUtil.checkTargetedEventAlreadyUsed(this.id.toString(), targetingObject, event, game)) {
|
||||
return false;
|
||||
}
|
||||
switch (setTargetPointer) {
|
||||
case PLAYER:
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(targetingObject.getControllerId(), game));
|
||||
break;
|
||||
case SPELL:
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(targetingObject.getId()));
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported SetTargetPointer in BecomesTargetAttachedTriggeredAbility");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
|
||||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
/**
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class BecomesTargetControllerSpellTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public BecomesTargetControllerSpellTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
setTriggerPhrase("When you become the target of a spell, ");
|
||||
}
|
||||
|
||||
protected BecomesTargetControllerSpellTriggeredAbility(final BecomesTargetControllerSpellTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesTargetControllerSpellTriggeredAbility copy() {
|
||||
return new BecomesTargetControllerSpellTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getTargetId().equals(controllerId)) {
|
||||
if (game.getObject(event.getSourceId()) instanceof Spell) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class BecomesTargetControllerTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterPermanent filterTarget;
|
||||
private final FilterStackObject filterStack;
|
||||
private final SetTargetPointer setTargetPointer;
|
||||
|
||||
/**
|
||||
* Note: filterTarget can be null for "whenever you become the target of...";
|
||||
* if set, then "whenever you or a [filterTarget] becomes the target of..."
|
||||
*/
|
||||
public BecomesTargetControllerTriggeredAbility(Effect effect, FilterPermanent filterTarget, FilterStackObject filterStack,
|
||||
SetTargetPointer setTargetPointer, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filterTarget = filterTarget;
|
||||
this.filterStack = filterStack;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
String filterMessage = (filterTarget == null)
|
||||
? "you become"
|
||||
: "you or " + filterTarget.getMessage() + " becomes";
|
||||
setTriggerPhrase("Whenever " + filterMessage + " the target of " + filterStack.getMessage() + ", ");
|
||||
}
|
||||
|
||||
protected BecomesTargetControllerTriggeredAbility(final BecomesTargetControllerTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filterTarget = ability.filterTarget;
|
||||
this.filterStack = ability.filterStack;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesTargetControllerTriggeredAbility copy() {
|
||||
return new BecomesTargetControllerTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!event.getTargetId().equals(getControllerId())) {
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (permanent == null || filterTarget == null || !filterTarget.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
StackObject targetingObject = CardUtil.getTargetingStackObject(event, game);
|
||||
if (targetingObject == null || !filterStack.match(targetingObject, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
if (CardUtil.checkTargetedEventAlreadyUsed(this.id.toString(), targetingObject, event, game)) {
|
||||
return false;
|
||||
}
|
||||
switch (setTargetPointer) {
|
||||
case SPELL:
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(targetingObject.getId()));
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported SetTargetPointer in BecomesTargetControllerTriggeredAbility");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author weirddan455
|
||||
*/
|
||||
public class BecomesTargetOpponentAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterPermanent filter;
|
||||
|
||||
public BecomesTargetOpponentAllTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, StaticFilters.FILTER_CONTROLLED_A_PERMANENT, optional);
|
||||
}
|
||||
|
||||
public BecomesTargetOpponentAllTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
setTriggerPhrase("Whenever " + filter + " becomes the target of a spell or ability an opponent controls, ");
|
||||
}
|
||||
|
||||
private BecomesTargetOpponentAllTriggeredAbility(final BecomesTargetOpponentAllTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesTargetOpponentAllTriggeredAbility copy() {
|
||||
return new BecomesTargetOpponentAllTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
StackObject sourceObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (sourceObject == null) {
|
||||
return false;
|
||||
}
|
||||
Player targetter = game.getPlayer(event.getPlayerId());
|
||||
if (targetter == null || !targetter.hasOpponent(this.controllerId, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
// If a spell or ability an opponent controls targets a single permanent you control more than once,
|
||||
// Battle Mammoth’s triggered ability will trigger only once.
|
||||
// However, if a spell or ability an opponent controls targets multiple permanents you control,
|
||||
// Battle Mammoth’s triggered ability will trigger once for each of those permanents.
|
||||
|
||||
// targetMap - key - targetId, value - Set of stackObject Ids
|
||||
Map<UUID, Set<UUID>> targetMap = (Map<UUID, Set<UUID>>) game.getState().getValue("targetMap" + this.id);
|
||||
if (targetMap == null) {
|
||||
targetMap = new HashMap<>();
|
||||
}
|
||||
Set<UUID> sourceObjects = targetMap.get(event.getTargetId());
|
||||
if (sourceObjects == null) {
|
||||
sourceObjects = new HashSet<>();
|
||||
}
|
||||
if (!sourceObjects.add(sourceObject.getId())) {
|
||||
return false;
|
||||
}
|
||||
targetMap.put(event.getTargetId(), sourceObjects);
|
||||
game.getState().setValue("targetMap" + this.id, targetMap);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.common.NumberOfTimesPermanentTargetedATurnWatcher;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class BecomesTargetSourceFirstTimeTriggeredAbility extends BecomesTargetSourceTriggeredAbility {
|
||||
|
||||
public BecomesTargetSourceFirstTimeTriggeredAbility(Effect effect, FilterStackObject filter,
|
||||
SetTargetPointer setTargetPointer, boolean optional) {
|
||||
super(effect, filter, setTargetPointer, optional);
|
||||
this.addWatcher(new NumberOfTimesPermanentTargetedATurnWatcher());
|
||||
setTriggerPhrase("Whenever {this} becomes the target of " + filter.getMessage() + " for the first time each turn, ");
|
||||
}
|
||||
|
||||
protected BecomesTargetSourceFirstTimeTriggeredAbility(final BecomesTargetSourceFirstTimeTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesTargetSourceFirstTimeTriggeredAbility copy() {
|
||||
return new BecomesTargetSourceFirstTimeTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
NumberOfTimesPermanentTargetedATurnWatcher watcher = game.getState().getWatcher(NumberOfTimesPermanentTargetedATurnWatcher.class);
|
||||
if (permanent == null || watcher == null || watcher.numTimesTargetedThisTurn(permanent, game) > 1) {
|
||||
return false;
|
||||
}
|
||||
return super.checkTrigger(event, game);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.ExileSourceEffect;
|
||||
import mage.abilities.effects.common.ReturnToHandSourceEffect;
|
||||
import mage.abilities.effects.common.SacrificeSourceEffect;
|
||||
import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author North
|
||||
*/
|
||||
public class BecomesTargetSourceTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterStackObject filter;
|
||||
private final SetTargetPointer setTargetPointer;
|
||||
|
||||
public BecomesTargetSourceTriggeredAbility(Effect effect) {
|
||||
this(effect, StaticFilters.FILTER_SPELL_OR_ABILITY_A);
|
||||
}
|
||||
|
||||
public BecomesTargetSourceTriggeredAbility(Effect effect, FilterStackObject filter) {
|
||||
this(effect, filter, SetTargetPointer.NONE, false);
|
||||
}
|
||||
|
||||
public BecomesTargetSourceTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
boolean textWhen = (effect instanceof SacrificeSourceEffect
|
||||
|| effect instanceof ReturnToHandSourceEffect
|
||||
|| effect instanceof ShuffleIntoLibrarySourceEffect
|
||||
|| effect instanceof ExileSourceEffect);
|
||||
setTriggerPhrase((textWhen ? "When" : "Whenever") + " {this} becomes the target of " + filter.getMessage() + ", ");
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
}
|
||||
|
||||
protected BecomesTargetSourceTriggeredAbility(final BecomesTargetSourceTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesTargetSourceTriggeredAbility copy() {
|
||||
return new BecomesTargetSourceTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!event.getTargetId().equals(getSourceId())) {
|
||||
return false;
|
||||
}
|
||||
StackObject targetingObject = CardUtil.getTargetingStackObject(event, game);
|
||||
if (targetingObject == null || !filter.match(targetingObject, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
if (CardUtil.checkTargetedEventAlreadyUsed(this.id.toString(), targetingObject, event, game)) {
|
||||
return false;
|
||||
}
|
||||
switch (setTargetPointer) {
|
||||
case PLAYER:
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(targetingObject.getControllerId(), game));
|
||||
break;
|
||||
case SPELL:
|
||||
this.getAllEffects().setTargetPointer(new FixedTarget(targetingObject.getId()));
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported SetTargetPointer in BecomesTargetSourceTriggeredAbility");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterPermanent filterTarget;
|
||||
private final FilterStackObject filterStack;
|
||||
|
||||
public BecomesTargetTriggeredAbility(Effect effect, FilterPermanent filterTarget) {
|
||||
this(effect, filterTarget, StaticFilters.FILTER_SPELL_OR_ABILITY_A);
|
||||
}
|
||||
|
||||
public BecomesTargetTriggeredAbility(Effect effect, FilterPermanent filterTarget, FilterStackObject filterStack) {
|
||||
this(effect, filterTarget, filterStack, false);
|
||||
}
|
||||
|
||||
public BecomesTargetTriggeredAbility(Effect effect, FilterPermanent filterTarget, FilterStackObject filterStack,
|
||||
boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filterTarget = filterTarget;
|
||||
this.filterStack = filterStack;
|
||||
setTriggerPhrase("Whenever " + filterTarget.getMessage() + " becomes the target of "
|
||||
+ filterStack.getMessage() + ", ");
|
||||
}
|
||||
|
||||
protected BecomesTargetTriggeredAbility(final BecomesTargetTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filterTarget = ability.filterTarget;
|
||||
this.filterStack = ability.filterStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesTargetTriggeredAbility copy() {
|
||||
return new BecomesTargetTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
StackObject sourceObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (sourceObject == null
|
||||
|| !filterStack.match(sourceObject, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (permanent == null
|
||||
|| !filterTarget.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,13 +14,14 @@ public class CycleTriggeredAbility extends ZoneChangeTriggeredAbility {
|
|||
|
||||
public CycleTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.ALL, effect, "When you cycle {this}, ", optional);
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
}
|
||||
|
||||
public CycleTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public CycleTriggeredAbility(CycleTriggeredAbility ability) {
|
||||
protected CycleTriggeredAbility(CycleTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ public class DiesSourceTriggeredAbility extends ZoneChangeTriggeredAbility {
|
|||
|
||||
public DiesSourceTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, Zone.GRAVEYARD, effect, "When {this} dies, ", optional);
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
}
|
||||
|
||||
public DiesSourceTriggeredAbility(Effect effect) {
|
||||
|
|
|
|||
|
|
@ -11,27 +11,18 @@ import mage.game.events.GameEvent;
|
|||
*/
|
||||
public class EntersBattlefieldTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
protected boolean ignoreRulesGeneration; // use it with custom rules (if you don't want ETB auto-generated text)
|
||||
protected String etbFlavorWord = null;
|
||||
|
||||
public EntersBattlefieldTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public EntersBattlefieldTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, optional, false);
|
||||
}
|
||||
|
||||
public EntersBattlefieldTriggeredAbility(Effect effect, boolean optional, boolean ignoreRulesGeneration) {
|
||||
super(Zone.ALL, effect, optional); // Zone.All because a creature with trigger can be put into play and be sacrificed during the resolution of an effect (discard Obstinate Baloth with Smallpox)
|
||||
this.ignoreRulesGeneration = ignoreRulesGeneration;
|
||||
this.replaceRuleText = true; // default true to replace "{this}" with "it"
|
||||
setTriggerPhrase("When {this} enters the battlefield, ");
|
||||
}
|
||||
|
||||
protected EntersBattlefieldTriggeredAbility(final EntersBattlefieldTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.ignoreRulesGeneration = ability.ignoreRulesGeneration;
|
||||
this.etbFlavorWord = ability.etbFlavorWord;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ public class EntersBattlefieldUntappedTriggeredAbility extends EntersBattlefield
|
|||
|
||||
public EntersBattlefieldUntappedTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(effect, optional);
|
||||
this.ignoreRulesGeneration = true;
|
||||
setTriggerPhrase("When {this} enters the battlefield untapped, ");
|
||||
}
|
||||
|
||||
|
|
@ -33,4 +32,4 @@ public class EntersBattlefieldUntappedTriggeredAbility extends EntersBattlefield
|
|||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
return permanent != null && !permanent.isTapped();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
* @author North
|
||||
*/
|
||||
public class SourceBecomesTargetTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterStackObject filter;
|
||||
private final SetTargetPointer setTargetPointer;
|
||||
|
||||
public SourceBecomesTargetTriggeredAbility(Effect effect) {
|
||||
this(effect, StaticFilters.FILTER_SPELL_OR_ABILITY_A);
|
||||
}
|
||||
|
||||
public SourceBecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter) {
|
||||
this(effect, filter, SetTargetPointer.NONE);
|
||||
}
|
||||
|
||||
public SourceBecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer) {
|
||||
this(effect, filter, setTargetPointer, false);
|
||||
}
|
||||
|
||||
public SourceBecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("When {this} becomes the target of " + filter.getMessage() + ", ");
|
||||
}
|
||||
|
||||
protected SourceBecomesTargetTriggeredAbility(final SourceBecomesTargetTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceBecomesTargetTriggeredAbility copy() {
|
||||
return new SourceBecomesTargetTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
StackObject sourceObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (!event.getTargetId().equals(getSourceId())
|
||||
|| !filter.match(sourceObject, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
switch (setTargetPointer) {
|
||||
case PLAYER:
|
||||
this.getEffects().stream()
|
||||
.forEach(effect -> effect.setTargetPointer(
|
||||
new FixedTarget(sourceObject.getControllerId(), game)
|
||||
));
|
||||
break;
|
||||
case SPELL:
|
||||
this.getEffects().stream()
|
||||
.forEach(effect -> effect.setTargetPointer(
|
||||
new FixedTarget(sourceObject.getId(), game)
|
||||
));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
* "Whenever you or a permanent you control becomes the target of a spell or ability an opponent controls,"
|
||||
* AND
|
||||
* "Whenever you become the target of a spell or ability an opponent controls,"
|
||||
*
|
||||
* @author Alex-Vasile
|
||||
*/
|
||||
public class TargetOfOpponentsSpellOrAbilityTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private boolean onlyController = false;
|
||||
|
||||
public TargetOfOpponentsSpellOrAbilityTriggeredAbility(Effect effect) {
|
||||
this(effect, false, false);
|
||||
}
|
||||
|
||||
public TargetOfOpponentsSpellOrAbilityTriggeredAbility(Effect effect, boolean optional, boolean onlyController) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.onlyController = onlyController;
|
||||
if (this.onlyController) {
|
||||
setTriggerPhrase("Whenever you become the target of a spell or ability an opponent controls, ");
|
||||
} else {
|
||||
setTriggerPhrase("Whenever you or a permanent you control becomes the target of a spell or ability an opponent controls, ");
|
||||
}
|
||||
}
|
||||
|
||||
private TargetOfOpponentsSpellOrAbilityTriggeredAbility(final TargetOfOpponentsSpellOrAbilityTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.onlyController = ability.onlyController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Player controller = game.getPlayer(this.getControllerId());
|
||||
Player targetter = game.getPlayer(event.getPlayerId());
|
||||
if (controller == null || targetter == null || controller.getId().equals(targetter.getId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if player was targeted
|
||||
if (controller.getId().equals(event.getTargetId())) {
|
||||
// Add target for effects which need it (e.g. the counter effect from AmuletOfSafekeeping)
|
||||
this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
// If only the controller is
|
||||
if (this.onlyController) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if permanent was targeted
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (permanent == null || !controller.getId().equals(permanent.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add target for effects which need it (e.g. the counter effect from AmuletOfSafekeeping)
|
||||
this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetOfOpponentsSpellOrAbilityTriggeredAbility copy() {
|
||||
return new TargetOfOpponentsSpellOrAbilityTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ import mage.abilities.effects.Effect;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
|
|
@ -14,7 +13,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
|
||||
public class TurnedFaceUpSourceTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private boolean setTargetPointer;
|
||||
private final boolean setTargetPointer;
|
||||
|
||||
public TurnedFaceUpSourceTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
|
|
@ -30,6 +29,7 @@ public class TurnedFaceUpSourceTriggeredAbility extends TriggeredAbilityImpl {
|
|||
this.setWorksFaceDown(true);
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
setTriggerPhrase("When {this} is turned face up, ");
|
||||
this.replaceRuleText = true;
|
||||
}
|
||||
|
||||
protected TurnedFaceUpSourceTriggeredAbility(final TurnedFaceUpSourceTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ public class AttachedToMatchesFilterCondition implements Condition {
|
|||
|
||||
public AttachedToMatchesFilterCondition(FilterPermanent filter) {
|
||||
this.filter = filter;
|
||||
if (filter == null) {
|
||||
throw new IllegalStateException("Wrong code usage. Filter must be non-nullable.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ import mage.game.Game;
|
|||
/**
|
||||
* This condition always returns false outside of the combat phase.
|
||||
*
|
||||
* The name is bad, but "No Source" is refering to the fact this is to be used outside
|
||||
* a "Whenever ~ attacks," or similar, where the "defending player" takes another
|
||||
* meaning. {@link DefendingPlayerControlsNoSourcePredicate} for more info.
|
||||
*
|
||||
* @author Susucr
|
||||
*/
|
||||
public class DefendingPlayerControlsNoSourceCondition implements Condition {
|
||||
|
|
|
|||
|
|
@ -66,11 +66,6 @@ public class ConditionalContinuousRuleModifyingEffect extends ContinuousRuleModi
|
|||
return effect.isDiscarded() || (otherwiseEffect != null && otherwiseEffect.isDiscarded());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
if (effect.checksEventType(event, game)) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.abilities.effects;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
|
|||
|
|
@ -59,24 +59,11 @@ public abstract class ContinuousRuleModifyingEffectImpl extends ContinuousEffect
|
|||
this.messageToGameLog = effect.messageToGameLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* An early check for the event types this effect applies to. This check was
|
||||
* added to speed up event handling. Once all existing
|
||||
* ContinuousRuleModifiyingEffects have implemented this method, the method
|
||||
* should be changed to abstract here or removed.
|
||||
*
|
||||
* @param event
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
final public boolean apply(Game game, Ability source) {
|
||||
// not used in rule modifying effects because it allows or disallows related event only without data
|
||||
// modification or choose dialogs (see applies method)
|
||||
throw new IllegalStateException("Wrong code usage. Rules modifying effects don't use apply methods");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -29,11 +29,6 @@ public class CantActivateAbilitiesAttachedEffect extends ContinuousRuleModifying
|
|||
return new CantActivateAbilitiesAttachedEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATE_ABILITY;
|
||||
|
|
|
|||
|
|
@ -45,11 +45,6 @@ public class CantBeCounteredControlledEffect extends ContinuousRuleModifyingEffe
|
|||
return new CantBeCounteredControlledEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.COUNTER;
|
||||
|
|
|
|||
|
|
@ -32,11 +32,6 @@ public class CantBeCounteredSourceEffect extends ContinuousRuleModifyingEffectIm
|
|||
return new CantBeCounteredSourceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
StackObject stackObject = game.getStack().getStackObject(event.getTargetId());
|
||||
|
|
|
|||
|
|
@ -31,11 +31,6 @@ public class CantBeRegeneratedSourceEffect extends ContinuousRuleModifyingEffect
|
|||
return new CantBeRegeneratedSourceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.REGENERATE;
|
||||
|
|
|
|||
|
|
@ -27,11 +27,6 @@ public class CantBeRegeneratedTargetEffect extends ContinuousRuleModifyingEffect
|
|||
return new CantBeRegeneratedTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.REGENERATE;
|
||||
|
|
|
|||
|
|
@ -49,11 +49,6 @@ public class CantBeTargetedAllEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
return new CantBeTargetedAllEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGET;
|
||||
|
|
|
|||
|
|
@ -44,11 +44,6 @@ public class CantBeTargetedAttachedEffect extends ContinuousRuleModifyingEffectI
|
|||
return new CantBeTargetedAttachedEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGET;
|
||||
|
|
|
|||
|
|
@ -30,11 +30,6 @@ public class CantBeTargetedCardsGraveyardsEffect extends ContinuousRuleModifying
|
|||
return new CantBeTargetedCardsGraveyardsEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGET;
|
||||
|
|
@ -46,7 +41,7 @@ public class CantBeTargetedCardsGraveyardsEffect extends ContinuousRuleModifying
|
|||
StackObject stackObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (targetCard != null && stackObject != null) {
|
||||
Zone zone = game.getState().getZone(targetCard.getId());
|
||||
if (zone != null && zone == Zone.GRAVEYARD) {
|
||||
if (zone == Zone.GRAVEYARD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,11 +36,6 @@ public class CantBeTargetedSourceEffect extends ContinuousRuleModifyingEffectImp
|
|||
return new CantBeTargetedSourceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGET;
|
||||
|
|
|
|||
|
|
@ -39,11 +39,6 @@ public class CantBeTargetedTargetEffect extends ContinuousRuleModifyingEffectImp
|
|||
return new CantBeTargetedTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGET;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public class ChooseModeEffect extends OneShotEffect {
|
|||
if (sourcePermanent == null) {
|
||||
sourcePermanent = game.getPermanentEntering(source.getSourceId());
|
||||
}
|
||||
if (controller != null) {
|
||||
if (controller != null && sourcePermanent != null) {
|
||||
Choice choice = new ChoiceImpl(true);
|
||||
choice.setMessage(choiceMessage);
|
||||
choice.getChoices().addAll(modes);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
|||
private final List<Permanent> addedTokenPermanents;
|
||||
private final List<Ability> additionalAbilities;
|
||||
private final CardType additionalCardType;
|
||||
private SubType additionalSubType;
|
||||
private final List<SubType> additionalSubTypes = new ArrayList<>();
|
||||
private final UUID attackedPlayer;
|
||||
private UUID attachedTo = null;
|
||||
private final boolean attacking;
|
||||
|
|
@ -133,7 +133,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
|||
this.addedTokenPermanents = new ArrayList<>(effect.addedTokenPermanents);
|
||||
this.additionalAbilities = new ArrayList<>(effect.additionalAbilities);
|
||||
this.additionalCardType = effect.additionalCardType;
|
||||
this.additionalSubType = effect.additionalSubType;
|
||||
this.additionalSubTypes.addAll(effect.additionalSubTypes);
|
||||
this.attackedPlayer = effect.attackedPlayer;
|
||||
this.attachedTo = effect.attachedTo;
|
||||
this.attacking = effect.attacking;
|
||||
|
|
@ -236,8 +236,10 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
|||
token.removeAllCreatureTypes();
|
||||
token.addSubType(onlySubType);
|
||||
}
|
||||
if (additionalSubType != null) {
|
||||
token.addSubType(additionalSubType);
|
||||
if (!additionalSubTypes.isEmpty()) {
|
||||
for (SubType additionalSubType : additionalSubTypes) {
|
||||
token.addSubType(additionalSubType);
|
||||
}
|
||||
}
|
||||
if (color != null) {
|
||||
token.setColor(color);
|
||||
|
|
@ -322,8 +324,8 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
|||
return addedTokenPermanents;
|
||||
}
|
||||
|
||||
public CreateTokenCopyTargetEffect setAdditionalSubType(SubType additionalSubType) {
|
||||
this.additionalSubType = additionalSubType;
|
||||
public CreateTokenCopyTargetEffect withAdditionalSubType(SubType additionalSubType) {
|
||||
this.additionalSubTypes.add(additionalSubType);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
|
@ -40,12 +38,7 @@ public class DamageAttachedControllerEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// In the case that the enchantment is blinked
|
||||
Permanent enchantment = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
|
||||
if (enchantment == null) {
|
||||
// It was not blinked, use the standard method
|
||||
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
}
|
||||
Permanent enchantment = source.getSourcePermanentOrLKI(game);
|
||||
if (enchantment == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
|
|
@ -47,12 +45,7 @@ public class DamageAttachedEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// In the case that the enchantment is blinked
|
||||
Permanent enchantment = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
|
||||
if (enchantment == null) {
|
||||
// It was not blinked, use the standard method
|
||||
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
}
|
||||
Permanent enchantment = source.getSourcePermanentOrLKI(game);
|
||||
if (enchantment == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,11 +28,6 @@ public class DontUntapInControllersNextUntapStepSourceEffect extends ContinuousR
|
|||
return new DontUntapInControllersNextUntapStepSourceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
MageObject mageObject = game.getObject(source);
|
||||
|
|
@ -44,7 +39,8 @@ public class DontUntapInControllersNextUntapStepSourceEffect extends ContinuousR
|
|||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP || event.getType() == GameEvent.EventType.UNTAP;
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP
|
||||
|| event.getType() == GameEvent.EventType.UNTAP;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -71,11 +71,6 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR
|
|||
return new DontUntapInControllersNextUntapStepTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
MageObject mageObject = game.getObject(source);
|
||||
|
|
@ -88,7 +83,8 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR
|
|||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP || event.getType() == GameEvent.EventType.UNTAP;
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP
|
||||
|| event.getType() == GameEvent.EventType.UNTAP;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -41,11 +41,6 @@ public class DontUntapInControllersUntapStepAllEffect extends ContinuousRuleModi
|
|||
return new DontUntapInControllersUntapStepAllEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.UNTAP;
|
||||
|
|
|
|||
|
|
@ -27,11 +27,6 @@ public class DontUntapInControllersUntapStepEnchantedEffect extends ContinuousRu
|
|||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DontUntapInControllersUntapStepEnchantedEffect copy() {
|
||||
return new DontUntapInControllersUntapStepEnchantedEffect(this);
|
||||
|
|
|
|||
|
|
@ -34,11 +34,6 @@ public class DontUntapInControllersUntapStepSourceEffect extends ContinuousRuleM
|
|||
return new DontUntapInControllersUntapStepSourceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.UNTAP;
|
||||
|
|
|
|||
|
|
@ -38,11 +38,6 @@ public class DontUntapInControllersUntapStepTargetEffect extends ContinuousRuleM
|
|||
return new DontUntapInControllersUntapStepTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.UNTAP;
|
||||
|
|
|
|||
|
|
@ -46,11 +46,6 @@ public class DontUntapInPlayersNextUntapStepAllEffect extends ContinuousRuleModi
|
|||
return new DontUntapInPlayersNextUntapStepAllEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
MageObject mageObject = game.getObject(source);
|
||||
|
|
@ -63,7 +58,8 @@ public class DontUntapInPlayersNextUntapStepAllEffect extends ContinuousRuleModi
|
|||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP || event.getType() == GameEvent.EventType.UNTAP;
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP
|
||||
|| event.getType() == GameEvent.EventType.UNTAP;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -75,11 +75,6 @@ class EpicReplacementEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EpicReplacementEffect copy() {
|
||||
return new EpicReplacementEffect(this);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package mage.abilities.effects.common;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
|
@ -31,12 +30,7 @@ public class ExileAttachedEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
// The LKI must be used for this step. 608.2g
|
||||
// In the case that the enchantment is blinked
|
||||
Permanent enchantment = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
|
||||
if (enchantment == null) {
|
||||
// It was not blinked, use the standard method
|
||||
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
}
|
||||
Permanent enchantment = source.getSourcePermanentOrLKI(game);
|
||||
if (controller != null
|
||||
&& enchantment != null
|
||||
&& enchantment.getAttachedTo() != null) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package mage.abilities.effects.common;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
|
|
@ -28,12 +27,7 @@ public class PhaseOutAttachedEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// In the case that the enchantment is blinked
|
||||
Permanent enchantment = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
|
||||
if (enchantment == null) {
|
||||
// It was not blinked, use the standard method
|
||||
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
}
|
||||
Permanent enchantment = source.getSourcePermanentOrLKI(game);
|
||||
if (enchantment != null) {
|
||||
Permanent enchanted = game.getPermanent(enchantment.getAttachedTo());
|
||||
if (enchanted != null) {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ import mage.constants.Zone;
|
|||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
|
@ -63,7 +61,7 @@ public class ReturnToHandTargetEffect extends OneShotEffect {
|
|||
if (staticText != null && !staticText.isEmpty()) {
|
||||
return staticText;
|
||||
}
|
||||
return "return " + getTargetPointer().describeTargets(mode.getTargets(), "") +
|
||||
return "return " + getTargetPointer().describeTargets(mode.getTargets(), "that creature") +
|
||||
(getTargetPointer().isPlural(mode.getTargets()) ? " to their owners' hands" : " to its owner's hand");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,11 +58,15 @@ public class SkipUntapStepEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
return new SkipUntapStepEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP
|
||||
&& controller != null
|
||||
return controller != null
|
||||
&& game.getState().getPlayersInRange(controller.getId(), game).contains(event.getPlayerId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public class TapEnchantedEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
Permanent permanent = source.getSourcePermanentOrLKI(game);
|
||||
if (permanent != null) {
|
||||
Permanent attach = game.getPermanent(permanent.getAttachedTo());
|
||||
if (attach != null) {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class UntapAttachedEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
Permanent permanent = source.getSourcePermanentOrLKI(game);
|
||||
if (permanent != null) {
|
||||
Permanent attach = game.getPermanent(permanent.getAttachedTo());
|
||||
if (attach != null) {
|
||||
|
|
|
|||
|
|
@ -28,11 +28,6 @@ public class ChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
return new ChooseBlockersEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DECLARING_BLOCKERS;
|
||||
|
|
|
|||
|
|
@ -33,11 +33,6 @@ public class CantCastMoreThanOneSpellEffect extends ContinuousRuleModifyingEffec
|
|||
return new CantCastMoreThanOneSpellEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.CAST_SPELL;
|
||||
|
|
|
|||
|
|
@ -23,11 +23,6 @@ public class DamageCantBePreventedEffect extends ContinuousRuleModifyingEffectIm
|
|||
return new DamageCantBePreventedEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.PREVENT_DAMAGE;
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ import mage.constants.SubLayer;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -128,31 +126,10 @@ public class GainControlTargetEffect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
if (!staticText.isEmpty()) {
|
||||
if (staticText != null && !staticText.isEmpty()) {
|
||||
return staticText;
|
||||
}
|
||||
|
||||
if (mode.getTargets().isEmpty()) {
|
||||
return "gain control of target permanent";
|
||||
}
|
||||
|
||||
Target target = mode.getTargets().get(0);
|
||||
StringBuilder sb = new StringBuilder("gain control of ");
|
||||
if (target.getMaxNumberOfTargets() > 1) {
|
||||
if (target.getMinNumberOfTargets() == 0) {
|
||||
sb.append("up to ");
|
||||
}
|
||||
sb.append(CardUtil.numberToText(target.getMaxNumberOfTargets())).append(" target ");
|
||||
} else if (!target.getTargetName().startsWith("another")) {
|
||||
if (target.getMinNumberOfTargets() == 0) {
|
||||
sb.append("up to one ");
|
||||
}
|
||||
sb.append("target ");
|
||||
}
|
||||
sb.append(mode.getTargets().get(0).getTargetName());
|
||||
if (!duration.toString().isEmpty() && duration != Duration.EndOfGame) {
|
||||
sb.append(' ').append(duration.toString());
|
||||
}
|
||||
return sb.toString();
|
||||
return "gain control of " + getTargetPointer().describeTargets(mode.getTargets(), "that creature")
|
||||
+ (duration.toString().isEmpty() || duration == Duration.EndOfGame ? "" : " " + duration.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,11 +30,6 @@ public class CantCastOrActivateOpponentsYourTurnEffect extends ContinuousRuleMod
|
|||
return new CantCastOrActivateOpponentsYourTurnEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
Player activePlayer = game.getPlayer(game.getActivePlayerId());
|
||||
|
|
|
|||
|
|
@ -32,11 +32,6 @@ public class CantRegenerateTargetEffect extends ContinuousRuleModifyingEffectImp
|
|||
return new CantRegenerateTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.REGENERATE;
|
||||
|
|
|
|||
|
|
@ -39,11 +39,6 @@ public class CastOnlyIfYouHaveCastAnotherSpellEffect extends ContinuousRuleModif
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastOnlyIfYouHaveCastAnotherSpellEffect copy() {
|
||||
return new CastOnlyIfYouHaveCastAnotherSpellEffect(this);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects.common.ruleModifying;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -7,17 +6,25 @@ import mage.constants.Duration;
|
|||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* @author TheElk801, xanderhall
|
||||
*/
|
||||
public class CombatDamageByToughnessAllEffect extends ContinuousEffectImpl {
|
||||
|
||||
private final FilterCreaturePermanent filter;
|
||||
|
||||
public CombatDamageByToughnessAllEffect() {
|
||||
this(StaticFilters.FILTER_PERMANENT_CREATURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Each [] assigns combat damage equal to its toughness rather than its power"
|
||||
* @param filter Warning: ObjectSourcePlayer predicates will be ignored
|
||||
*/
|
||||
public CombatDamageByToughnessAllEffect(FilterCreaturePermanent filter) {
|
||||
this(filter, Duration.WhileOnBattlefield);
|
||||
}
|
||||
|
|
@ -25,9 +32,8 @@ public class CombatDamageByToughnessAllEffect extends ContinuousEffectImpl {
|
|||
public CombatDamageByToughnessAllEffect(FilterCreaturePermanent filter, Duration duration) {
|
||||
super(duration, Layer.RulesEffects, SubLayer.NA, Outcome.Neutral);
|
||||
this.filter = filter;
|
||||
this.staticText = filter.getMessage() + " assigns combat damage equal to its toughness rather than its power";
|
||||
this.staticText = "each " + filter.getMessage() + " assigns combat damage equal to its toughness rather than its power";
|
||||
}
|
||||
|
||||
|
||||
private CombatDamageByToughnessAllEffect(final CombatDamageByToughnessAllEffect effect) {
|
||||
super(effect);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
package mage.abilities.effects.common.ruleModifying;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author TheElk801, xenohedron
|
||||
*/
|
||||
public class CombatDamageByToughnessControlledEffect extends ContinuousEffectImpl {
|
||||
|
||||
private final FilterCreaturePermanent filter;
|
||||
|
||||
public CombatDamageByToughnessControlledEffect() {
|
||||
this(StaticFilters.FILTER_PERMANENT_CREATURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Each [] you control assigns combat damage equal to its toughness rather than its power"
|
||||
* @param filter Warning: ObjectSourcePlayer predicates will be ignored
|
||||
*/
|
||||
public CombatDamageByToughnessControlledEffect(FilterCreaturePermanent filter) {
|
||||
this(filter, Duration.WhileOnBattlefield);
|
||||
}
|
||||
|
||||
public CombatDamageByToughnessControlledEffect(FilterCreaturePermanent filter, Duration duration) {
|
||||
super(duration, Layer.RulesEffects, SubLayer.NA, Outcome.Neutral);
|
||||
this.filter = filter;
|
||||
this.staticText = "each " + filter.getMessage()
|
||||
+ (filter.getMessage().contains("you control") ? "" : " you control")
|
||||
+ " assigns combat damage equal to its toughness rather than its power";
|
||||
}
|
||||
|
||||
private CombatDamageByToughnessControlledEffect(final CombatDamageByToughnessControlledEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatDamageByToughnessControlledEffect copy() {
|
||||
return new CombatDamageByToughnessControlledEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
FilterCreaturePermanent filterPermanent = filter.copy();
|
||||
filterPermanent.add(new ControllerIdPredicate(source.getControllerId()));
|
||||
game.getCombat().setUseToughnessForDamage(true);
|
||||
game.getCombat().addUseToughnessForDamageFilter(filterPermanent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -104,11 +104,6 @@ class AftermathCantCastFromHand extends ContinuousRuleModifyingEffectImpl {
|
|||
return new AftermathCantCastFromHand(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.CAST_SPELL;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public class FabricateAbility extends EntersBattlefieldTriggeredAbility {
|
|||
private final int value;
|
||||
|
||||
public FabricateAbility(int value) {
|
||||
super(new FabricateEffect(value), false, true);
|
||||
super(new FabricateEffect(value), false);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,8 @@ class SplitSecondEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.CAST_SPELL || event.getType() == GameEvent.EventType.ACTIVATE_ABILITY;
|
||||
return event.getType() == GameEvent.EventType.CAST_SPELL
|
||||
|| event.getType() == GameEvent.EventType.ACTIVATE_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -76,11 +77,6 @@ class SplitSecondEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SplitSecondEffect copy() {
|
||||
return new SplitSecondEffect(this);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import mage.constants.Zone;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.target.Target;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
|
|
@ -22,7 +21,6 @@ public class WardAbility extends TriggeredAbilityImpl {
|
|||
|
||||
private final Cost cost;
|
||||
private final DynamicValue genericMana;
|
||||
|
||||
private final boolean showAbilityHint;
|
||||
private final String whereXIs;
|
||||
|
||||
|
|
@ -74,29 +72,19 @@ public class WardAbility extends TriggeredAbilityImpl {
|
|||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
private StackObject getTargetingObject(GameEvent event, Game game) {
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
if (stackObject.getId().equals(event.getSourceId()) || stackObject.getSourceId().equals(event.getSourceId())) {
|
||||
for (Target target : stackObject.getStackAbility().getTargets()) {
|
||||
if (target.contains(getSourceId())) {
|
||||
return stackObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!getSourceId().equals(event.getTargetId())) {
|
||||
return false;
|
||||
}
|
||||
StackObject stackObject = getTargetingObject(event, game);
|
||||
if (stackObject == null || !game.getOpponents(getControllerId()).contains(stackObject.getControllerId())) {
|
||||
StackObject targetingObject = CardUtil.getTargetingStackObject(event, game);
|
||||
if (targetingObject == null || !game.getOpponents(getControllerId()).contains(targetingObject.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setTargetPointer(new FixedTarget(stackObject.getId(), game));
|
||||
if (CardUtil.checkTargetedEventAlreadyUsed(this.id.toString(), targetingObject, event, game)) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setTargetPointer(new FixedTarget(targetingObject.getId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import mage.abilities.effects.mana.ManaEffect;
|
|||
import mage.cards.Card;
|
||||
import mage.choices.Choice;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
|
|
@ -88,7 +89,7 @@ class AnyColorCardInYourGraveyardManaEffect extends ManaEffect {
|
|||
choice.setChoice(choice.getChoices().iterator().next());
|
||||
} else {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null || !player.choose(outcome, choice, game)) {
|
||||
if (player == null || !player.choose(Outcome.PutManaInPool, choice, game)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.mana.ManaEffect;
|
||||
import mage.choices.Choice;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
|
|
@ -117,7 +118,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
|||
choice.setChoice(choice.getChoices().iterator().next());
|
||||
} else {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null || !player.choose(outcome, choice, game)) {
|
||||
if (player == null || !player.choose(Outcome.PutManaInPool, choice, game)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import mage.abilities.costs.common.TapSourceCost;
|
|||
import mage.abilities.effects.mana.ManaEffect;
|
||||
import mage.choices.Choice;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
|
|
@ -90,7 +91,7 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect {
|
|||
choice.setChoice(choice.getChoices().iterator().next());
|
||||
} else {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null || !player.choose(outcome, choice, game)) {
|
||||
if (player == null || !player.choose(Outcome.PutManaInPool, choice, game)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import mage.choices.Choice;
|
|||
import mage.choices.ChoiceImpl;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.CommanderCardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.game.Game;
|
||||
|
|
@ -132,7 +133,7 @@ class CommanderIdentityManaEffect extends ManaEffect {
|
|||
if (choice.getChoices().size() == 1) {
|
||||
choice.setChoice(choice.getChoices().iterator().next());
|
||||
} else {
|
||||
if (!controller.choose(outcome, choice, game)) {
|
||||
if (!controller.choose(Outcome.PutManaInPool, choice, game)) {
|
||||
return mana;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ package mage.constants;
|
|||
*/
|
||||
public enum MatchBufferTime {
|
||||
NONE(0, "None"),
|
||||
SEC__01(1, "1 Second"),
|
||||
SEC__02(2, "2 Seconds"),
|
||||
SEC__03(3, "3 Seconds"),
|
||||
SEC__05(5, "5 Seconds"),
|
||||
SEC__10(10, "10 Seconds"),
|
||||
SEC__15(15, "15 Seconds"),
|
||||
|
|
|
|||
|
|
@ -1229,10 +1229,4 @@ public final class StaticFilters {
|
|||
FILTER_CONTROLLED_FOOD.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterCreaturePermanent FILTER_CONTROLLED_CREATURE_EACH = new FilterCreaturePermanent("each creature you control");
|
||||
|
||||
static {
|
||||
FILTER_CONTROLLED_CREATURE_EACH.add(TargetController.YOU.getPlayerPredicate());
|
||||
FILTER_CONTROLLED_CREATURE_EACH.setLockedFilter(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ public class ExpansionSetPredicate implements Predicate<Card> {
|
|||
|
||||
private final String setCode;
|
||||
|
||||
/**
|
||||
* Per CR 206.1, the expansion symbol has no effect on game play.
|
||||
* Use only for utility or silver-bordered / acorn mechanics.
|
||||
*/
|
||||
public ExpansionSetPredicate(String setCode) {
|
||||
this.setCode = setCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package mage.filter.predicate.other;
|
||||
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
|
||||
/**
|
||||
* Needed for "becomes the target of an Aura spell" to work correctly with e.g. Disturb, Bestow
|
||||
*
|
||||
* @author xenohedron
|
||||
*/
|
||||
public enum AuraSpellPredicate implements Predicate<StackObject> {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(StackObject input, Game game) {
|
||||
if (!(input instanceof Spell)) {
|
||||
return false;
|
||||
}
|
||||
SpellAbility spellAbility = ((Spell) input).getSpellAbility();
|
||||
return spellAbility != null && spellAbility.getCharacteristics(game).hasSubtype(SubType.AURA, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "an Aura spell";
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ import mage.abilities.mana.TriggeredManaAbility;
|
|||
import mage.actions.impl.MageAction;
|
||||
import mage.cards.*;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.choices.Choice;
|
||||
import mage.constants.*;
|
||||
import mage.counters.CounterType;
|
||||
|
|
@ -41,6 +42,7 @@ import mage.game.combat.Combat;
|
|||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.command.*;
|
||||
import mage.game.command.dungeons.UndercityDungeon;
|
||||
import mage.game.command.emblems.EmblemOfCard;
|
||||
import mage.game.command.emblems.TheRingEmblem;
|
||||
import mage.game.events.*;
|
||||
import mage.game.events.TableEvent.EventType;
|
||||
|
|
@ -1317,6 +1319,22 @@ public abstract class GameImpl implements Game {
|
|||
addPlane(plane, startingPlayerId);
|
||||
state.setPlaneChase(this, gameOptions.planeChase);
|
||||
}
|
||||
|
||||
if (!gameOptions.perPlayerEmblemCards.isEmpty()) {
|
||||
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||
for (DeckCardInfo info : gameOptions.perPlayerEmblemCards) {
|
||||
Card card = EmblemOfCard.cardFromDeckInfo(info);
|
||||
addEmblem(new EmblemOfCard(card), card, playerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gameOptions.globalEmblemCards.isEmpty()) {
|
||||
for (DeckCardInfo info : gameOptions.globalEmblemCards) {
|
||||
Card card = EmblemOfCard.cardFromDeckInfo(info);
|
||||
addEmblem(new EmblemOfCard(card), card, startingPlayerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void initGameDefaultWatchers() {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
package mage.game;
|
||||
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.util.Copyable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
|
@ -52,6 +55,15 @@ public class GameOptions implements Serializable, Copyable<GameOptions> {
|
|||
*/
|
||||
public Set<String> bannedUsers = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* Cards to be given to each player as emblems
|
||||
*/
|
||||
public Collection<DeckCardInfo> perPlayerEmblemCards = Collections.emptySet();
|
||||
/**
|
||||
* Cards to be given to the starting player as emblems
|
||||
*/
|
||||
public Collection<DeckCardInfo> globalEmblemCards = Collections.emptySet();
|
||||
|
||||
|
||||
// PLANECHASE game mode
|
||||
public boolean planeChase = false;
|
||||
|
|
@ -73,6 +85,8 @@ public class GameOptions implements Serializable, Copyable<GameOptions> {
|
|||
this.rollbackTurnsAllowed = options.rollbackTurnsAllowed;
|
||||
this.bannedUsers.addAll(options.bannedUsers);
|
||||
this.planeChase = options.planeChase;
|
||||
this.perPlayerEmblemCards = new HashSet<>(options.perPlayerEmblemCards);
|
||||
this.globalEmblemCards = new HashSet<>(options.globalEmblemCards);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public abstract class Emblem extends CommandObjectImpl {
|
|||
private static final ManaCosts emptyCost = new ManaCostsImpl<>();
|
||||
|
||||
private UUID controllerId;
|
||||
private MageObject sourceObject;
|
||||
protected MageObject sourceObject;
|
||||
private boolean copy;
|
||||
private MageObject copyFrom; // copied card INFO (used to call original adjusters)
|
||||
private FrameStyle frameStyle;
|
||||
|
|
|
|||
108
Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java
Normal file
108
Mage/src/main/java/mage/game/command/emblems/EmblemOfCard.java
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
package mage.game.command.emblems;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.AbilityImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.cards.mock.MockCard;
|
||||
import mage.cards.repository.CardCriteria;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.command.Emblem;
|
||||
import mage.util.CardUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author artemiswkearney
|
||||
* Emblem with all the abilities of an existing card.
|
||||
* Can be used for custom gamemodes like Omniscience Draft (as seen on Arena),
|
||||
* mana burn with Yurlok of Scorch Thrash, and anything else players might think of.
|
||||
*/
|
||||
public final class EmblemOfCard extends Emblem {
|
||||
private final boolean usesVariousArt;
|
||||
private static final Logger logger = Logger.getLogger(EmblemOfCard.class);
|
||||
|
||||
public static Card lookupCard(
|
||||
String cardName,
|
||||
String cardNumber,
|
||||
String setCode,
|
||||
String infoTypeForError
|
||||
) {
|
||||
int cardNumberInt = CardUtil.parseCardNumberAsInt(cardNumber);
|
||||
List<CardInfo> found = CardRepository.instance.findCards(new CardCriteria()
|
||||
.name(cardName)
|
||||
.minCardNumber(cardNumberInt)
|
||||
.maxCardNumber(cardNumberInt)
|
||||
.setCodes(setCode));
|
||||
return found.stream()
|
||||
.filter(ci -> ci.getCardNumber().equals(cardNumber))
|
||||
.findFirst()
|
||||
.orElseGet(() -> found.stream()
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No real card for " + infoTypeForError + " " + cardName)))
|
||||
.getCard();
|
||||
}
|
||||
|
||||
public static Card cardFromDeckInfo(DeckCardInfo info) {
|
||||
return lookupCard(
|
||||
info.getCardName(),
|
||||
info.getCardNum(),
|
||||
info.getSetCode(),
|
||||
"DeckCardInfo"
|
||||
);
|
||||
}
|
||||
|
||||
public EmblemOfCard(Card card, Zone zone) {
|
||||
super(card.getName());
|
||||
if (card instanceof MockCard) {
|
||||
card = lookupCard(
|
||||
card.getName(),
|
||||
card.getCardNumber(),
|
||||
card.getExpansionSetCode(),
|
||||
"MockCard"
|
||||
);
|
||||
}
|
||||
this.getAbilities().addAll(card.getAbilities().stream().filter(
|
||||
ability -> zone.match(ability.getZone())
|
||||
).map(ability -> {
|
||||
if (ability instanceof AbilityImpl && ability.getZone() == zone) {
|
||||
return ((AbilityImpl)ability).copyWithZone(Zone.COMMAND);
|
||||
}
|
||||
return ability;
|
||||
}).collect(Collectors.toList()));
|
||||
this.getAbilities().setSourceId(this.getId());
|
||||
this.setExpansionSetCode(card.getExpansionSetCode());
|
||||
this.setCardNumber(card.getCardNumber());
|
||||
this.setImageNumber(card.getImageNumber());
|
||||
this.usesVariousArt = card.getUsesVariousArt();
|
||||
}
|
||||
|
||||
public EmblemOfCard(Card card) {
|
||||
this(card, Zone.BATTLEFIELD);
|
||||
}
|
||||
|
||||
private EmblemOfCard(EmblemOfCard eoc) {
|
||||
super(eoc);
|
||||
this.usesVariousArt = eoc.usesVariousArt;
|
||||
}
|
||||
@Override
|
||||
public EmblemOfCard copy() {
|
||||
return new EmblemOfCard(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceObject(MageObject sourceObject) {
|
||||
this.sourceObject = sourceObject;
|
||||
// super method would try and fail to find the emblem image here
|
||||
// (not sure why that would be setSoureObject's job; we get our image during construction)
|
||||
}
|
||||
|
||||
public boolean getUsesVariousArt() {
|
||||
return usesVariousArt;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,8 +51,9 @@ class GideonOfTheTrialsCantLoseEffect extends ContinuousRuleModifyingEffectImpl
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.WINS
|
||||
|| event.getType() == GameEvent.EventType.LOSES;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -52,11 +52,6 @@ class NarsetTranscendentCantCastEffect extends ContinuousRuleModifyingEffectImpl
|
|||
return new NarsetTranscendentCantCastEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
MageObject mageObject = game.getObject(source);
|
||||
|
|
|
|||
|
|
@ -84,11 +84,6 @@ class EdgeOfMalacolEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
return new EdgeOfMalacolEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.UNTAP;
|
||||
|
|
|
|||
|
|
@ -62,16 +62,14 @@ public class TheEonFogPlane extends Plane {
|
|||
|
||||
class TheEonFogSkipUntapStepEffect extends ContinuousRuleModifyingEffectImpl {
|
||||
|
||||
boolean allPlayers = false;
|
||||
final boolean allPlayers;
|
||||
|
||||
public TheEonFogSkipUntapStepEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Neutral, false, false);
|
||||
this.allPlayers = false;
|
||||
staticText = "Players skip their untap steps";
|
||||
this(Duration.WhileOnBattlefield, false);
|
||||
}
|
||||
|
||||
public TheEonFogSkipUntapStepEffect(Duration d, boolean allPlayers) {
|
||||
super(d, Outcome.Neutral, false, false);
|
||||
public TheEonFogSkipUntapStepEffect(Duration duration, boolean allPlayers) {
|
||||
super(duration, Outcome.Neutral, false, false);
|
||||
this.allPlayers = allPlayers;
|
||||
staticText = "Players skip their untap steps";
|
||||
}
|
||||
|
|
@ -86,6 +84,11 @@ class TheEonFogSkipUntapStepEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
return new TheEonFogSkipUntapStepEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Plane cPlane = game.getState().getCurrentPlane();
|
||||
|
|
@ -95,6 +98,6 @@ class TheEonFogSkipUntapStepEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
if (!cPlane.getPlaneType().equals(Planes.PLANE_THE_EON_FOG)) {
|
||||
return false;
|
||||
}
|
||||
return event.getType() == GameEvent.EventType.UNTAP_STEP;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import mage.game.draft.Draft;
|
|||
import mage.game.match.MatchOptions;
|
||||
import mage.game.tournament.MultiplayerRound;
|
||||
import mage.game.tournament.TournamentPairing;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.EventObject;
|
||||
|
|
@ -17,11 +18,15 @@ import java.util.UUID;
|
|||
*/
|
||||
public class TableEvent extends EventObject implements ExternalEvent, Serializable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TableEvent.class);
|
||||
|
||||
public enum EventType {
|
||||
UPDATE, INFO, STATUS, START_DRAFT, START_MATCH, SIDEBOARD, CONSTRUCT, SUBMIT_DECK, END, END_GAME_INFO, ERROR,
|
||||
INIT_TIMER, RESUME_TIMER, PAUSE_TIMER, CHECK_STATE_PLAYERS, START_MULTIPLAYER_MATCH
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Game game;
|
||||
private Draft draft;
|
||||
private EventType eventType;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
package mage.game.match;
|
||||
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.constants.MatchBufferTime;
|
||||
import mage.constants.MatchTimeLimit;
|
||||
import mage.constants.MultiplayerAttackOption;
|
||||
|
|
@ -11,10 +12,7 @@ import mage.game.result.ResultProtos;
|
|||
import mage.players.PlayerType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -52,6 +50,9 @@ public class MatchOptions implements Serializable {
|
|||
protected MatchBufferTime matchBufferTime; // Amount of time each player gets before their normal time limit counts down. Refreshes each time the normal timer is invoked.
|
||||
protected MulliganType mulliganType;
|
||||
|
||||
protected Collection<DeckCardInfo> perPlayerEmblemCards;
|
||||
protected Collection<DeckCardInfo> globalEmblemCards;
|
||||
|
||||
/*public MatchOptions(String name, String gameType) {
|
||||
this.name = name;
|
||||
this.gameType = gameType;
|
||||
|
|
@ -65,6 +66,8 @@ public class MatchOptions implements Serializable {
|
|||
this.password = "";
|
||||
this.multiPlayer = multiPlayer;
|
||||
this.numSeats = numSeats;
|
||||
this.perPlayerEmblemCards = Collections.emptySet();
|
||||
this.globalEmblemCards = Collections.emptySet();
|
||||
}
|
||||
|
||||
public void setNumSeats (int numSeats) {
|
||||
|
|
@ -288,4 +291,19 @@ public class MatchOptions implements Serializable {
|
|||
return mulliganType;
|
||||
}
|
||||
|
||||
public Collection<DeckCardInfo> getPerPlayerEmblemCards() {
|
||||
return perPlayerEmblemCards;
|
||||
}
|
||||
|
||||
public void setPerPlayerEmblemCards(Collection<DeckCardInfo> perPlayerEmblemCards) {
|
||||
this.perPlayerEmblemCards = perPlayerEmblemCards;
|
||||
}
|
||||
|
||||
public Collection<DeckCardInfo> getGlobalEmblemCards() {
|
||||
return globalEmblemCards;
|
||||
}
|
||||
|
||||
public void setGlobalEmblemCards(Collection<DeckCardInfo> globalEmblemCards) {
|
||||
this.globalEmblemCards = globalEmblemCards;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.BecomesTargetSourceTriggeredAbility;
|
||||
import mage.abilities.effects.common.SacrificeSourceEffect;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.common.SacrificeSourceEffect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.filter.StaticFilters;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
|
|
@ -26,10 +21,11 @@ public final class JaceCunningCastawayIllusionToken extends TokenImpl {
|
|||
power = new MageInt(2);
|
||||
toughness = new MageInt(2);
|
||||
|
||||
this.addAbility(new IllusionTokenTriggeredAbility());
|
||||
this.addAbility(new BecomesTargetSourceTriggeredAbility(new SacrificeSourceEffect().setText("sacrifice it"), StaticFilters.FILTER_SPELL_A)
|
||||
.setTriggerPhrase("When this creature becomes the target of a spell, "));
|
||||
}
|
||||
|
||||
protected JaceCunningCastawayIllusionToken(final JaceCunningCastawayIllusionToken token) {
|
||||
private JaceCunningCastawayIllusionToken(final JaceCunningCastawayIllusionToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
|
|
@ -38,39 +34,3 @@ public final class JaceCunningCastawayIllusionToken extends TokenImpl {
|
|||
return new JaceCunningCastawayIllusionToken(this);
|
||||
}
|
||||
}
|
||||
|
||||
class IllusionTokenTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public IllusionTokenTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new SacrificeSourceEffect(), false);
|
||||
}
|
||||
|
||||
protected IllusionTokenTriggeredAbility(final IllusionTokenTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IllusionTokenTriggeredAbility copy() {
|
||||
return new IllusionTokenTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TARGETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
MageObject eventSourceObject = game.getObject(event.getSourceId());
|
||||
if (event.getTargetId().equals(this.getSourceId()) && eventSourceObject instanceof Spell) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "When this creature becomes the target of a spell, sacrifice it.";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class UserData implements Serializable {
|
|||
protected boolean manaPoolAutomaticRestricted;
|
||||
protected boolean passPriorityCast;
|
||||
protected boolean passPriorityActivation;
|
||||
protected boolean autoOrderTrigger;
|
||||
protected boolean autoOrderTrigger; // auto-order triggers with same rule text
|
||||
protected int autoTargetLevel;
|
||||
protected boolean useSameSettingsForReplacementEffects;
|
||||
protected boolean useFirstManaAbility = false;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import mage.game.permanent.PermanentMeld;
|
|||
import mage.game.permanent.PermanentToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetCard;
|
||||
|
|
@ -1009,6 +1010,63 @@ public final class CardUtil {
|
|||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* For finding the spell or ability on the stack for "becomes the target" triggers.
|
||||
* @param event the GameEvent.EventType.TARGETED from checkTrigger() or watch()
|
||||
* @param game the Game from checkTrigger() or watch()
|
||||
* @return the StackObject which targeted the source, or null if not found
|
||||
*/
|
||||
public static StackObject getTargetingStackObject(GameEvent event, Game game) {
|
||||
// In case of multiple simultaneous triggered abilities from the same source,
|
||||
// need to get the actual one that targeted, see #8026, #8378
|
||||
// Also avoids triggering on cancelled selections, see #8802
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
Ability stackAbility = stackObject.getStackAbility();
|
||||
if (stackAbility == null || !stackAbility.getSourceId().equals(event.getSourceId())) {
|
||||
continue;
|
||||
}
|
||||
for (Target target : stackAbility.getTargets()) {
|
||||
if (target.getTargets().contains(event.getTargetId())) {
|
||||
return stackObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* For ensuring that spells/abilities that target the same object twice only trigger each "becomes the target" ability once.
|
||||
* If this is the first attempt at triggering for a given ability targeting a given object,
|
||||
* this method records that in the game state for later checks by this same method.
|
||||
* @param checkingReference must be unique for each usage (this.id.toString() of the TriggeredAbility, or this.getKey() of the watcher)
|
||||
* @param targetingObject from getTargetingStackObject
|
||||
* @param event the GameEvent.EventType.TARGETED from checkTrigger() or watch()
|
||||
* @param game the Game from checkTrigger() or watch()
|
||||
* @return true if already triggered/watched, false if this is the first/only trigger/watch
|
||||
*/
|
||||
public static boolean checkTargetedEventAlreadyUsed(String checkingReference, StackObject targetingObject, GameEvent event, Game game) {
|
||||
String stateKey = "targetedMap" + checkingReference;
|
||||
// If a spell or ability an opponent controls targets a single permanent you control more than once,
|
||||
// Battle Mammoth's triggered ability will trigger only once.
|
||||
// However, if a spell or ability an opponent controls targets multiple permanents you control,
|
||||
// Battle Mammoth's triggered ability will trigger once for each of those permanents. (2021-02-05)
|
||||
Map<UUID, Set<UUID>> targetMap = (Map<UUID, Set<UUID>>) game.getState().getValue(stateKey);
|
||||
// targetMap: key - targetId; value - Set of stackObject Ids
|
||||
if (targetMap == null) {
|
||||
targetMap = new HashMap<>();
|
||||
} else {
|
||||
targetMap = new HashMap<>(targetMap); // must have new object reference if saved back to game state
|
||||
}
|
||||
Set<UUID> targetingObjects = targetMap.computeIfAbsent(event.getTargetId(), k -> new HashSet<>());
|
||||
if (!targetingObjects.add(targetingObject.getId())) {
|
||||
return true; // The trigger/watcher already recorded that target of the stack object
|
||||
}
|
||||
// Otherwise, store this combination of trigger/watcher + target + stack object
|
||||
targetMap.put(event.getTargetId(), targetingObjects);
|
||||
game.getState().setValue(stateKey, targetMap);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put card to battlefield without resolve (for cheats and tests only)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
|
||||
|
||||
package mage.watchers.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import mage.MageObjectReference;
|
||||
import mage.constants.WatcherScope;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.util.CardUtil;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
|
|
@ -25,24 +26,23 @@ public class NumberOfTimesPermanentTargetedATurnWatcher extends Watcher {
|
|||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.TARGETED) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent != null) {
|
||||
MageObjectReference mor = new MageObjectReference(permanent, game);
|
||||
int amount = 0;
|
||||
if (permanentsTargeted.containsKey(mor)) {
|
||||
amount = permanentsTargeted.get(mor);
|
||||
}
|
||||
permanentsTargeted.put(mor, ++amount);
|
||||
}
|
||||
if (event.getType() != GameEvent.EventType.TARGETED) {
|
||||
return;
|
||||
}
|
||||
StackObject targetingObject = CardUtil.getTargetingStackObject(event, game);
|
||||
if (targetingObject == null || CardUtil.checkTargetedEventAlreadyUsed(this.getKey(), targetingObject, event, game)) {
|
||||
return;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent != null) {
|
||||
MageObjectReference mor = new MageObjectReference(permanent, game);
|
||||
int nTimes = permanentsTargeted.getOrDefault(mor, 0);
|
||||
permanentsTargeted.put(mor, nTimes + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean notMoreThanOnceTargetedThisTurn(Permanent creature, Game game) {
|
||||
if (permanentsTargeted.containsKey(new MageObjectReference(creature, game))) {
|
||||
return permanentsTargeted.get(new MageObjectReference(creature, game)) < 2;
|
||||
}
|
||||
return true;
|
||||
public int numTimesTargetedThisTurn(Permanent permanent, Game game) {
|
||||
return permanentsTargeted.getOrDefault(new MageObjectReference(permanent, game), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue