mirror of
https://github.com/magefree/mage.git
synced 2025-12-25 21:12:04 -08:00
* Fixed that permanents under non owner control sine they are on the battlefield were no exiled if the controller left the game (e.g. Captive Audience) (fixes #5593).
This commit is contained in:
parent
2c745109e4
commit
d2d892a7cb
7 changed files with 308 additions and 235 deletions
|
|
@ -1,72 +1,73 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import static mage.constants.Outcome.Benefit;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetOpponent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
* Use this effect only with EntersBattlefieldAbility like abilities
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class EntersBattlefieldUnderControlOfOpponentOfChoiceEffect extends OneShotEffect {
|
||||
|
||||
public EntersBattlefieldUnderControlOfOpponentOfChoiceEffect() {
|
||||
super(Benefit);
|
||||
staticText = "under the control of an opponent of your choice";
|
||||
}
|
||||
|
||||
private EntersBattlefieldUnderControlOfOpponentOfChoiceEffect(final EntersBattlefieldUnderControlOfOpponentOfChoiceEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntersBattlefieldUnderControlOfOpponentOfChoiceEffect copy() {
|
||||
return new EntersBattlefieldUnderControlOfOpponentOfChoiceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Target target = new TargetOpponent();
|
||||
target.setNotTarget(true);
|
||||
if (!controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) {
|
||||
return false;
|
||||
}
|
||||
Player opponent = game.getPlayer(target.getFirstTarget());
|
||||
if (opponent == null) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
game.informPlayers(permanent.getLogName() + " enters the battlefield under the control of " + opponent.getLogName());
|
||||
}
|
||||
ContinuousEffect continuousEffect = new GainControlTargetEffect(
|
||||
Duration.Custom, true, opponent.getId()
|
||||
);
|
||||
continuousEffect.setTargetPointer(new FixedTarget(
|
||||
source.getSourceId(), source.getSourceObjectZoneChangeCounter()
|
||||
));
|
||||
game.addEffect(continuousEffect, source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import static mage.constants.Outcome.Benefit;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetOpponent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
* Use this effect only with EntersBattlefieldAbility like abilities
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class EntersBattlefieldUnderControlOfOpponentOfChoiceEffect extends OneShotEffect {
|
||||
|
||||
public EntersBattlefieldUnderControlOfOpponentOfChoiceEffect() {
|
||||
super(Benefit);
|
||||
staticText = "under the control of an opponent of your choice";
|
||||
}
|
||||
|
||||
private EntersBattlefieldUnderControlOfOpponentOfChoiceEffect(final EntersBattlefieldUnderControlOfOpponentOfChoiceEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntersBattlefieldUnderControlOfOpponentOfChoiceEffect copy() {
|
||||
return new EntersBattlefieldUnderControlOfOpponentOfChoiceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Target target = new TargetOpponent();
|
||||
target.setNotTarget(true);
|
||||
if (!controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) {
|
||||
return false;
|
||||
}
|
||||
Player opponent = game.getPlayer(target.getFirstTarget());
|
||||
if (opponent == null) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
permanent.setOriginalControllerId(opponent.getId()); // permanent was controlled by this player since the existance of this object so original controller has to be set to the first controller
|
||||
permanent.setControllerId(opponent.getId()); // neccessary to set already here because spell caster never controlled the permanent (important for rule 800.4a)
|
||||
game.informPlayers(permanent.getLogName() + " enters the battlefield under the control of " + opponent.getLogName());
|
||||
}
|
||||
ContinuousEffect continuousEffect = new GainControlTargetEffect(
|
||||
Duration.Custom, true, opponent.getId()
|
||||
);
|
||||
continuousEffect.setTargetPointer(new FixedTarget(
|
||||
source.getSourceId(), source.getSourceObjectZoneChangeCounter()
|
||||
));
|
||||
game.addEffect(continuousEffect, source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
package mage.game;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import mage.MageException;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.*;
|
||||
|
|
@ -67,11 +71,6 @@ import mage.util.functions.ApplyToPermanent;
|
|||
import mage.watchers.common.*;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public abstract class GameImpl implements Game, Serializable {
|
||||
|
||||
private static final int ROLLBACK_TURNS_MAX = 4;
|
||||
|
|
@ -562,7 +561,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
|
||||
@Override
|
||||
public void saveState(boolean bookmark) {
|
||||
if (!simulation && gameStates != null) {
|
||||
if (!simulation && gameStates != null) {
|
||||
if (bookmark || saveGame) {
|
||||
gameStates.save(state);
|
||||
}
|
||||
|
|
@ -1549,7 +1548,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
/**
|
||||
* @param emblem
|
||||
* @param sourceObject
|
||||
* @param toPlayerId controller and owner of the emblem
|
||||
* @param toPlayerId controller and owner of the emblem
|
||||
*/
|
||||
@Override
|
||||
public void addEmblem(Emblem emblem, MageObject sourceObject, UUID toPlayerId) {
|
||||
|
|
@ -1567,8 +1566,8 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
/**
|
||||
* @param plane
|
||||
* @param sourceObject
|
||||
* @param toPlayerId controller and owner of the plane (may only be one per
|
||||
* game..)
|
||||
* @param toPlayerId controller and owner of the plane (may only be one per
|
||||
* game..)
|
||||
* @return boolean - whether the plane was added successfully or not
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -1642,7 +1641,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
newBluePrint.reset(this);
|
||||
|
||||
//getState().addCard(permanent);
|
||||
if (copyFromPermanent.isMorphed() || copyFromPermanent.isManifested()
|
||||
if (copyFromPermanent.isMorphed() || copyFromPermanent.isManifested()
|
||||
|| copyFromPermanent.isFaceDown(this)) {
|
||||
MorphAbility.setPermanentToFaceDownCreature(newBluePrint);
|
||||
}
|
||||
|
|
@ -1805,7 +1804,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
break;
|
||||
}
|
||||
// triggered abilities that don't use the stack have to be executed first (e.g. Banisher Priest Return exiled creature
|
||||
for (Iterator<TriggeredAbility> it = abilities.iterator(); it.hasNext(); ) {
|
||||
for (Iterator<TriggeredAbility> it = abilities.iterator(); it.hasNext();) {
|
||||
TriggeredAbility triggeredAbility = it.next();
|
||||
if (!triggeredAbility.isUsesStack()) {
|
||||
state.removeTriggeredAbility(triggeredAbility);
|
||||
|
|
@ -1880,7 +1879,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
Zone currentZone = this.getState().getZone(card.getId());
|
||||
String currentZoneInfo = (currentZone == null ? "(error)" : "(" + currentZone.name() + ")");
|
||||
if (player.chooseUse(Outcome.Benefit, "Move " + card.getIdName()
|
||||
+ " to the command zone or leave it in current zone " + currentZoneInfo + "?", "You can only make this choice once per object",
|
||||
+ " to the command zone or leave it in current zone " + currentZoneInfo + "?", "You can only make this choice once per object",
|
||||
"Move to command", "Leave in current zone " + currentZoneInfo, null, this)) {
|
||||
toMove.add(card);
|
||||
} else {
|
||||
|
|
@ -2596,7 +2595,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
//20100423 - 800.4a
|
||||
Set<Card> toOutside = new HashSet<>();
|
||||
for (Iterator<Permanent> it = getBattlefield().getAllPermanents().iterator(); it.hasNext(); ) {
|
||||
for (Iterator<Permanent> it = getBattlefield().getAllPermanents().iterator(); it.hasNext();) {
|
||||
Permanent perm = it.next();
|
||||
if (perm.isOwnedBy(playerId)) {
|
||||
if (perm.getAttachedTo() != null) {
|
||||
|
|
@ -2621,6 +2620,10 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
for (ContinuousEffect effect : getContinuousEffects().getLayeredEffects(this)) {
|
||||
if (effect.hasLayer(Layer.ControlChangingEffects_2)) {
|
||||
for (Ability ability : getContinuousEffects().getLayeredEffectAbilities(effect)) {
|
||||
if (effect.getTargetPointer().getTargets(this, ability).contains(perm.getId())) {
|
||||
effect.discard();
|
||||
continue Effects;
|
||||
}
|
||||
for (Target target : ability.getTargets()) {
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
if (targetId.equals(perm.getId())) {
|
||||
|
|
@ -2630,6 +2633,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2641,7 +2645,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
player.moveCards(toOutside, Zone.OUTSIDE, null, this);
|
||||
// triggered abilities that don't use the stack have to be executed
|
||||
List<TriggeredAbility> abilities = state.getTriggered(player.getId());
|
||||
for (Iterator<TriggeredAbility> it = abilities.iterator(); it.hasNext(); ) {
|
||||
for (Iterator<TriggeredAbility> it = abilities.iterator(); it.hasNext();) {
|
||||
TriggeredAbility triggeredAbility = it.next();
|
||||
if (!triggeredAbility.isUsesStack()) {
|
||||
state.removeTriggeredAbility(triggeredAbility);
|
||||
|
|
@ -2661,7 +2665,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
|
||||
// Remove cards from the player in all exile zones
|
||||
for (ExileZone exile : this.getExile().getExileZones()) {
|
||||
for (Iterator<UUID> it = exile.iterator(); it.hasNext(); ) {
|
||||
for (Iterator<UUID> it = exile.iterator(); it.hasNext();) {
|
||||
Card card = this.getCard(it.next());
|
||||
if (card != null && card.isOwnedBy(playerId)) {
|
||||
it.remove();
|
||||
|
|
@ -2671,7 +2675,7 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
|
||||
//Remove all commander/emblems/plane the player controls
|
||||
boolean addPlaneAgain = false;
|
||||
for (Iterator<CommandObject> it = this.getState().getCommand().iterator(); it.hasNext(); ) {
|
||||
for (Iterator<CommandObject> it = this.getState().getCommand().iterator(); it.hasNext();) {
|
||||
CommandObject obj = it.next();
|
||||
if (obj.isControlledBy(playerId)) {
|
||||
if (obj instanceof Emblem) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package mage.game.permanent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -10,12 +13,10 @@ import mage.game.Controllable;
|
|||
import mage.game.Game;
|
||||
import mage.game.GameState;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface Permanent extends Card, Controllable {
|
||||
|
||||
void setOriginalControllerId(UUID controllerId);
|
||||
|
||||
void setControllerId(UUID controllerId);
|
||||
|
||||
boolean isTapped();
|
||||
|
|
@ -103,7 +104,8 @@ public interface Permanent extends Card, Controllable {
|
|||
/**
|
||||
* @param source
|
||||
* @param game
|
||||
* @param silentMode - use it to ignore warning message for users (e.g. for checking only)
|
||||
* @param silentMode - use it to ignore warning message for users (e.g. for
|
||||
* checking only)
|
||||
* @return
|
||||
*/
|
||||
boolean cantBeAttachedBy(MageObject source, Game game, boolean silentMode);
|
||||
|
|
@ -217,7 +219,7 @@ public interface Permanent extends Card, Controllable {
|
|||
|
||||
/**
|
||||
* @param defenderId id of planeswalker or player to attack - can be empty
|
||||
* to check generally
|
||||
* to check generally
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package mage.game.permanent;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.ObjectColor;
|
||||
|
|
@ -38,9 +40,6 @@ import mage.util.GameLog;
|
|||
import mage.util.ThreadLocalStringBuilder;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -184,6 +183,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
abilities.setControllerId(controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOriginalControllerId(UUID originalControllerId) {
|
||||
this.originalControllerId = originalControllerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before each applyEffects or if after a permanent was copied for
|
||||
* the copied object
|
||||
|
|
@ -793,7 +797,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
this.attachedTo = attachToObjectId;
|
||||
this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(attachToObjectId);
|
||||
for (Ability ability : this.getAbilities()) {
|
||||
for (Iterator<Effect> ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext(); ) {
|
||||
for (Iterator<Effect> ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext();) {
|
||||
ContinuousEffect effect = (ContinuousEffect) ite.next();
|
||||
game.getContinuousEffects().setOrder(effect);
|
||||
// It's important to update the timestamp of the copied effect in ContinuousEffects because it does the action
|
||||
|
|
@ -848,8 +852,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
* @param game
|
||||
* @param preventable
|
||||
* @param combat
|
||||
* @param markDamage If true, damage will be dealt later in applyDamage
|
||||
* method
|
||||
* @param markDamage If true, damage will be dealt later in applyDamage
|
||||
* method
|
||||
* @return
|
||||
*/
|
||||
private int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, List<UUID> appliedEffects) {
|
||||
|
|
@ -1066,9 +1070,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) == null
|
||||
&& abilities.stream()
|
||||
.filter(HexproofBaseAbility.class::isInstance)
|
||||
.map(HexproofBaseAbility.class::cast)
|
||||
.anyMatch(ability -> ability.checkObject(source, game))) {
|
||||
.filter(HexproofBaseAbility.class::isInstance)
|
||||
.map(HexproofBaseAbility.class::cast)
|
||||
.anyMatch(ability -> ability.checkObject(source, game))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1619,9 +1623,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
|
||||
Zone fromZone = game.getState().getZone(objectId);
|
||||
ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects);
|
||||
ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name);
|
||||
ZoneChangeInfo.Exile zcInfo = new ZoneChangeInfo.Exile(event, exileId, name);
|
||||
|
||||
boolean successfullyMoved = ZonesHandler.moveCard(info, game);
|
||||
boolean successfullyMoved = ZonesHandler.moveCard(zcInfo, game);
|
||||
//20180810 - 701.3d
|
||||
detachAllAttachments(game);
|
||||
return successfullyMoved;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package mage.players;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.ConditionalMana;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
|
|
@ -66,11 +70,6 @@ import mage.util.GameLog;
|
|||
import mage.util.RandomUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class PlayerImpl implements Player, Serializable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(PlayerImpl.class);
|
||||
|
|
@ -614,9 +613,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
&& this.hasOpponent(sourceControllerId, game)
|
||||
&& game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) == null
|
||||
&& abilities.stream()
|
||||
.filter(HexproofBaseAbility.class::isInstance)
|
||||
.map(HexproofBaseAbility.class::cast)
|
||||
.anyMatch(ability -> ability.checkObject(source, game))) {
|
||||
.filter(HexproofBaseAbility.class::isInstance)
|
||||
.map(HexproofBaseAbility.class::cast)
|
||||
.anyMatch(ability -> ability.checkObject(source, game))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -656,7 +655,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
game.informPlayers(getLogName() + " discards down to "
|
||||
+ this.maxHandSize
|
||||
+ (this.maxHandSize == 1
|
||||
? " hand card" : " hand cards"));
|
||||
? " hand card" : " hand cards"));
|
||||
}
|
||||
discard(hand.size() - this.maxHandSize, false, null, game);
|
||||
}
|
||||
|
|
@ -805,7 +804,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
GameEvent gameEvent = GameEvent.getEvent(GameEvent.EventType.DISCARD_CARD,
|
||||
card.getId(), source == null
|
||||
? null : source.getSourceId(), playerId);
|
||||
? null : source.getSourceId(), playerId);
|
||||
gameEvent.setFlag(source != null); // event from effect or from cost (source == null)
|
||||
if (game.replaceEvent(gameEvent, source)) {
|
||||
return false;
|
||||
|
|
@ -1842,9 +1841,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
private List<Permanent> getPermanentsThatCanBeUntapped(Game game,
|
||||
List<Permanent> canBeUntapped,
|
||||
RestrictionUntapNotMoreThanEffect handledEffect,
|
||||
Map<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffectsUsage) {
|
||||
List<Permanent> canBeUntapped,
|
||||
RestrictionUntapNotMoreThanEffect handledEffect,
|
||||
Map<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffectsUsage) {
|
||||
List<Permanent> leftForUntap = new ArrayList<>();
|
||||
// select permanents that can still be untapped
|
||||
for (Permanent permanent : canBeUntapped) {
|
||||
|
|
@ -2553,7 +2552,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId,
|
||||
boolean triggerEvents) {
|
||||
boolean triggerEvents) {
|
||||
//20091005 - 701.14c
|
||||
Library searchedLibrary = null;
|
||||
String searchInfo = null;
|
||||
|
|
@ -2755,7 +2754,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
/**
|
||||
* @param game
|
||||
* @param appliedEffects
|
||||
* @param numSides Number of sides the dice has
|
||||
* @param numSides Number of sides the dice has
|
||||
* @return the number that the player rolled
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -2792,16 +2791,16 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
/**
|
||||
* @param game
|
||||
* @param appliedEffects
|
||||
* @param numberChaosSides The number of chaos sides the planar die
|
||||
* currently has (normally 1 but can be 5)
|
||||
* @param numberChaosSides The number of chaos sides the planar die
|
||||
* currently has (normally 1 but can be 5)
|
||||
* @param numberPlanarSides The number of chaos sides the planar die
|
||||
* currently has (normally 1)
|
||||
* currently has (normally 1)
|
||||
* @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll
|
||||
* or NilRoll
|
||||
*/
|
||||
@Override
|
||||
public PlanarDieRoll rollPlanarDie(Game game, List<UUID> appliedEffects, int numberChaosSides,
|
||||
int numberPlanarSides) {
|
||||
int numberPlanarSides) {
|
||||
int result = RandomUtil.nextInt(9) + 1;
|
||||
PlanarDieRoll roll = PlanarDieRoll.NIL_ROLL;
|
||||
if (numberChaosSides + numberPlanarSides > 9) {
|
||||
|
|
@ -2958,7 +2957,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
/**
|
||||
* @param ability
|
||||
* @param availableMana if null, it won't be checked if enough mana is available
|
||||
* @param availableMana if null, it won't be checked if enough mana is
|
||||
* available
|
||||
* @param sourceObject
|
||||
* @param game
|
||||
* @return
|
||||
|
|
@ -3290,6 +3290,17 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return getPlayable(game, hidden, Zone.ALL, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all available spells and abilities the player can
|
||||
* currently cast/activate with his available ressources
|
||||
*
|
||||
* @param game
|
||||
* @param hidden also from hidden objects (e.g. turned face down cards ?)
|
||||
* @param fromZone of objects from which zone (ALL = from all zones)
|
||||
* @param hideDuplicatedAbilities if equal abilities exist return only the
|
||||
* first instance
|
||||
* @return
|
||||
*/
|
||||
public List<ActivatedAbility> getPlayable(Game game, boolean hidden, Zone fromZone, boolean hideDuplicatedAbilities) {
|
||||
List<ActivatedAbility> playable = new ArrayList<>();
|
||||
if (shouldSkipGettingPlayable(game)) {
|
||||
|
|
@ -3655,7 +3666,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId,
|
||||
UUID controllerId, Game game
|
||||
UUID controllerId, Game game
|
||||
) {
|
||||
return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game);
|
||||
}
|
||||
|
|
@ -3808,8 +3819,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCards(Card card, Zone toZone,
|
||||
Ability source, Game game,
|
||||
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
|
||||
Ability source, Game game,
|
||||
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
|
||||
) {
|
||||
Set<Card> cardList = new HashSet<>();
|
||||
if (card != null) {
|
||||
|
|
@ -3820,22 +3831,22 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCards(Cards cards, Zone toZone,
|
||||
Ability source, Game game
|
||||
Ability source, Game game
|
||||
) {
|
||||
return moveCards(cards.getCards(game), toZone, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Set<Card> cards, Zone toZone,
|
||||
Ability source, Game game
|
||||
Ability source, Game game
|
||||
) {
|
||||
return moveCards(cards, toZone, source, game, false, false, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Set<Card> cards, Zone toZone,
|
||||
Ability source, Game game,
|
||||
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
|
||||
Ability source, Game game,
|
||||
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
|
||||
) {
|
||||
if (cards.isEmpty()) {
|
||||
return true;
|
||||
|
|
@ -3937,8 +3948,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardsToExile(Card card, Ability source,
|
||||
Game game, boolean withName, UUID exileId,
|
||||
String exileZoneName
|
||||
Game game, boolean withName, UUID exileId,
|
||||
String exileZoneName
|
||||
) {
|
||||
Set<Card> cards = new HashSet<>();
|
||||
cards.add(card);
|
||||
|
|
@ -3947,8 +3958,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardsToExile(Set<Card> cards, Ability source,
|
||||
Game game, boolean withName, UUID exileId,
|
||||
String exileZoneName
|
||||
Game game, boolean withName, UUID exileId,
|
||||
String exileZoneName
|
||||
) {
|
||||
if (cards.isEmpty()) {
|
||||
return true;
|
||||
|
|
@ -3964,14 +3975,14 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
|
||||
Game game
|
||||
Game game
|
||||
) {
|
||||
return this.moveCardToHandWithInfo(card, sourceId, game, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
|
||||
Game game, boolean withName
|
||||
Game game, boolean withName
|
||||
) {
|
||||
boolean result = false;
|
||||
Zone fromZone = game.getState().getZone(card.getId());
|
||||
|
|
@ -3996,7 +4007,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public Set<Card> moveCardsToGraveyardWithInfo(Set<Card> allCards, Ability source,
|
||||
Game game, Zone fromZone
|
||||
Game game, Zone fromZone
|
||||
) {
|
||||
UUID sourceId = source == null ? null : source.getSourceId();
|
||||
Set<Card> movedCards = new LinkedHashSet<>();
|
||||
|
|
@ -4004,7 +4015,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
// identify cards from one owner
|
||||
Cards cards = new CardsImpl();
|
||||
UUID ownerId = null;
|
||||
for (Iterator<Card> it = allCards.iterator(); it.hasNext(); ) {
|
||||
for (Iterator<Card> it = allCards.iterator(); it.hasNext();) {
|
||||
Card card = it.next();
|
||||
if (cards.isEmpty()) {
|
||||
ownerId = card.getOwnerId();
|
||||
|
|
@ -4067,7 +4078,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId,
|
||||
Game game, Zone fromZone
|
||||
Game game, Zone fromZone
|
||||
) {
|
||||
if (card == null) {
|
||||
return false;
|
||||
|
|
@ -4096,8 +4107,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId,
|
||||
Game game, Zone fromZone,
|
||||
boolean toTop, boolean withName
|
||||
Game game, Zone fromZone,
|
||||
boolean toTop, boolean withName
|
||||
) {
|
||||
if (card == null) {
|
||||
return false;
|
||||
|
|
@ -4162,7 +4173,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId,
|
||||
Game game, Zone fromZone, boolean withName) {
|
||||
Game game, Zone fromZone, boolean withName) {
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -4185,7 +4196,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName()
|
||||
+ (card.isCopy() ? " (Copy)" : "") : "a card face down") + ' '
|
||||
+ (fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH)
|
||||
+ ' ' : "") + "to the exile zone");
|
||||
+ ' ' : "") + "to the exile zone");
|
||||
|
||||
}
|
||||
result = true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue