mirror of
https://github.com/correl/mage.git
synced 2025-01-12 19:25:44 +00: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,5 +1,6 @@
|
||||||
package org.mage.test.multiplayer;
|
package org.mage.test.multiplayer;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import mage.constants.MultiplayerAttackOption;
|
import mage.constants.MultiplayerAttackOption;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.RangeOfInfluence;
|
import mage.constants.RangeOfInfluence;
|
||||||
|
@ -14,8 +15,6 @@ import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
|
import org.mage.test.serverside.base.CardTestMultiPlayerBase;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
|
@ -344,4 +343,54 @@ public class PlayerLeftGameRange1Test extends CardTestMultiPlayerBase {
|
||||||
Assert.assertTrue("Staff of player B could be used", staffPlayerB.isTapped());
|
Assert.assertTrue("Staff of player B could be used", staffPlayerB.isTapped());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Captive Audience doesn't work correctly in multiplayer #5593
|
||||||
|
*
|
||||||
|
* Currently, if the controller of Captive Audience leaves the game, Captive
|
||||||
|
* Audience returns to its owner instead of being exiled.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void TestCaptiveAudienceGoesToExile() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||||
|
// Captive Audience enters the battlefield under the control of an opponent of your choice.
|
||||||
|
// At the beginning of your upkeep, choose one that hasn't been chosen —
|
||||||
|
// • Your life total becomes 4.
|
||||||
|
// • Discard your hand.
|
||||||
|
// • Each opponent creates five 2/2 black Zombie creature tokens.
|
||||||
|
addCard(Zone.HAND, playerA, "Captive Audience"); // Enchantment {5}{B}{R}
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox", 1);
|
||||||
|
|
||||||
|
setChoice(playerA, "PlayerA"); // Starting Player
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Captive Audience");
|
||||||
|
setChoice(playerA, "PlayerD");
|
||||||
|
|
||||||
|
setModeChoice(playerD, "1");
|
||||||
|
|
||||||
|
attack(5, playerA, "Silvercoat Lion", playerD);
|
||||||
|
attack(5, playerA, "Pillarfield Ox", playerD);
|
||||||
|
|
||||||
|
setStopAt(5, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertLife(playerA, 2);
|
||||||
|
|
||||||
|
Assert.assertFalse("Player D is no longer in the game", playerD.isInGame());
|
||||||
|
|
||||||
|
assertPermanentCount(playerD, 0);
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Captive Audience", 0);
|
||||||
|
assertGraveyardCount(playerA, "Captive Audience", 0);
|
||||||
|
assertExileCount(playerA, "Captive Audience", 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
package org.mage.test.serverside.base.impl;
|
package org.mage.test.serverside.base.impl;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
|
@ -35,15 +43,6 @@ import org.mage.test.player.TestPlayer;
|
||||||
import org.mage.test.serverside.base.CardTestAPI;
|
import org.mage.test.serverside.base.CardTestAPI;
|
||||||
import org.mage.test.serverside.base.MageTestPlayerBase;
|
import org.mage.test.serverside.base.MageTestPlayerBase;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API for test initialization and asserting the test results.
|
* API for test initialization and asserting the test results.
|
||||||
*
|
*
|
||||||
|
@ -1353,8 +1352,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raise error on any unused commands, choices or targets
|
* Raise error on any unused commands, choices or targets If you want to
|
||||||
* If you want to test that ability can't be activated then use call checkPlayableAbility()
|
* test that ability can't be activated then use call checkPlayableAbility()
|
||||||
*
|
*
|
||||||
* @throws AssertionError
|
* @throws AssertionError
|
||||||
*/
|
*/
|
||||||
|
@ -1691,9 +1690,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For use choices set "Yes" or "No" the the choice string. For X values set
|
* For use choices set "Yes" or "No" the the choice string.<br>
|
||||||
* "X=[xValue]" example: for X=3 set choice string to "X=3".
|
* For X values set "X=[xValue]" example: for X=3 set choice string to
|
||||||
* <br>For ColorChoice use "Red", "Green", "Blue", "Black" or "White"
|
* "X=3".<br>
|
||||||
|
* For ColorChoice use "Red", "Green", "Blue", "Black" or "White"<br>
|
||||||
|
* use command setModeChoice if you have to set a mode from modal
|
||||||
|
* ability<br>
|
||||||
*
|
*
|
||||||
* @param player
|
* @param player
|
||||||
* @param choice
|
* @param choice
|
||||||
|
|
|
@ -24,7 +24,6 @@ import mage.target.targetpointer.FixedTarget;
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class EntersBattlefieldUnderControlOfOpponentOfChoiceEffect extends OneShotEffect {
|
public class EntersBattlefieldUnderControlOfOpponentOfChoiceEffect extends OneShotEffect {
|
||||||
|
|
||||||
public EntersBattlefieldUnderControlOfOpponentOfChoiceEffect() {
|
public EntersBattlefieldUnderControlOfOpponentOfChoiceEffect() {
|
||||||
|
@ -58,6 +57,8 @@ public class EntersBattlefieldUnderControlOfOpponentOfChoiceEffect extends OneSh
|
||||||
}
|
}
|
||||||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||||
if (permanent != null) {
|
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());
|
game.informPlayers(permanent.getLogName() + " enters the battlefield under the control of " + opponent.getLogName());
|
||||||
}
|
}
|
||||||
ContinuousEffect continuousEffect = new GainControlTargetEffect(
|
ContinuousEffect continuousEffect = new GainControlTargetEffect(
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package mage.game;
|
package mage.game;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import mage.MageException;
|
import mage.MageException;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.*;
|
import mage.abilities.*;
|
||||||
|
@ -67,11 +71,6 @@ import mage.util.functions.ApplyToPermanent;
|
||||||
import mage.watchers.common.*;
|
import mage.watchers.common.*;
|
||||||
import org.apache.log4j.Logger;
|
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 {
|
public abstract class GameImpl implements Game, Serializable {
|
||||||
|
|
||||||
private static final int ROLLBACK_TURNS_MAX = 4;
|
private static final int ROLLBACK_TURNS_MAX = 4;
|
||||||
|
@ -1805,7 +1804,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// triggered abilities that don't use the stack have to be executed first (e.g. Banisher Priest Return exiled creature
|
// 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();
|
TriggeredAbility triggeredAbility = it.next();
|
||||||
if (!triggeredAbility.isUsesStack()) {
|
if (!triggeredAbility.isUsesStack()) {
|
||||||
state.removeTriggeredAbility(triggeredAbility);
|
state.removeTriggeredAbility(triggeredAbility);
|
||||||
|
@ -2596,7 +2595,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
}
|
}
|
||||||
//20100423 - 800.4a
|
//20100423 - 800.4a
|
||||||
Set<Card> toOutside = new HashSet<>();
|
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();
|
Permanent perm = it.next();
|
||||||
if (perm.isOwnedBy(playerId)) {
|
if (perm.isOwnedBy(playerId)) {
|
||||||
if (perm.getAttachedTo() != null) {
|
if (perm.getAttachedTo() != null) {
|
||||||
|
@ -2621,6 +2620,10 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
for (ContinuousEffect effect : getContinuousEffects().getLayeredEffects(this)) {
|
for (ContinuousEffect effect : getContinuousEffects().getLayeredEffects(this)) {
|
||||||
if (effect.hasLayer(Layer.ControlChangingEffects_2)) {
|
if (effect.hasLayer(Layer.ControlChangingEffects_2)) {
|
||||||
for (Ability ability : getContinuousEffects().getLayeredEffectAbilities(effect)) {
|
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 (Target target : ability.getTargets()) {
|
||||||
for (UUID targetId : target.getTargets()) {
|
for (UUID targetId : target.getTargets()) {
|
||||||
if (targetId.equals(perm.getId())) {
|
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);
|
player.moveCards(toOutside, Zone.OUTSIDE, null, this);
|
||||||
// triggered abilities that don't use the stack have to be executed
|
// triggered abilities that don't use the stack have to be executed
|
||||||
List<TriggeredAbility> abilities = state.getTriggered(player.getId());
|
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();
|
TriggeredAbility triggeredAbility = it.next();
|
||||||
if (!triggeredAbility.isUsesStack()) {
|
if (!triggeredAbility.isUsesStack()) {
|
||||||
state.removeTriggeredAbility(triggeredAbility);
|
state.removeTriggeredAbility(triggeredAbility);
|
||||||
|
@ -2661,7 +2665,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
|
|
||||||
// Remove cards from the player in all exile zones
|
// Remove cards from the player in all exile zones
|
||||||
for (ExileZone exile : this.getExile().getExileZones()) {
|
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());
|
Card card = this.getCard(it.next());
|
||||||
if (card != null && card.isOwnedBy(playerId)) {
|
if (card != null && card.isOwnedBy(playerId)) {
|
||||||
it.remove();
|
it.remove();
|
||||||
|
@ -2671,7 +2675,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
|
|
||||||
//Remove all commander/emblems/plane the player controls
|
//Remove all commander/emblems/plane the player controls
|
||||||
boolean addPlaneAgain = false;
|
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();
|
CommandObject obj = it.next();
|
||||||
if (obj.isControlledBy(playerId)) {
|
if (obj.isControlledBy(playerId)) {
|
||||||
if (obj instanceof Emblem) {
|
if (obj instanceof Emblem) {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package mage.game.permanent;
|
package mage.game.permanent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.MageObjectReference;
|
import mage.MageObjectReference;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
@ -10,12 +13,10 @@ import mage.game.Controllable;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.GameState;
|
import mage.game.GameState;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public interface Permanent extends Card, Controllable {
|
public interface Permanent extends Card, Controllable {
|
||||||
|
|
||||||
|
void setOriginalControllerId(UUID controllerId);
|
||||||
|
|
||||||
void setControllerId(UUID controllerId);
|
void setControllerId(UUID controllerId);
|
||||||
|
|
||||||
boolean isTapped();
|
boolean isTapped();
|
||||||
|
@ -103,7 +104,8 @@ public interface Permanent extends Card, Controllable {
|
||||||
/**
|
/**
|
||||||
* @param source
|
* @param source
|
||||||
* @param game
|
* @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
|
* @return
|
||||||
*/
|
*/
|
||||||
boolean cantBeAttachedBy(MageObject source, Game game, boolean silentMode);
|
boolean cantBeAttachedBy(MageObject source, Game game, boolean silentMode);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package mage.game.permanent;
|
package mage.game.permanent;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.*;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.MageObjectReference;
|
import mage.MageObjectReference;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
|
@ -38,9 +40,6 @@ import mage.util.GameLog;
|
||||||
import mage.util.ThreadLocalStringBuilder;
|
import mage.util.ThreadLocalStringBuilder;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
|
@ -184,6 +183,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
abilities.setControllerId(controllerId);
|
abilities.setControllerId(controllerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOriginalControllerId(UUID originalControllerId) {
|
||||||
|
this.originalControllerId = originalControllerId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before each applyEffects or if after a permanent was copied for
|
* Called before each applyEffects or if after a permanent was copied for
|
||||||
* the copied object
|
* the copied object
|
||||||
|
@ -793,7 +797,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
this.attachedTo = attachToObjectId;
|
this.attachedTo = attachToObjectId;
|
||||||
this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(attachToObjectId);
|
this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(attachToObjectId);
|
||||||
for (Ability ability : this.getAbilities()) {
|
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();
|
ContinuousEffect effect = (ContinuousEffect) ite.next();
|
||||||
game.getContinuousEffects().setOrder(effect);
|
game.getContinuousEffects().setOrder(effect);
|
||||||
// It's important to update the timestamp of the copied effect in ContinuousEffects because it does the action
|
// It's important to update the timestamp of the copied effect in ContinuousEffects because it does the action
|
||||||
|
@ -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) {
|
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
|
||||||
Zone fromZone = game.getState().getZone(objectId);
|
Zone fromZone = game.getState().getZone(objectId);
|
||||||
ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects);
|
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
|
//20180810 - 701.3d
|
||||||
detachAllAttachments(game);
|
detachAllAttachments(game);
|
||||||
return successfullyMoved;
|
return successfullyMoved;
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package mage.players;
|
package mage.players;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.ConditionalMana;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.MageObjectReference;
|
import mage.MageObjectReference;
|
||||||
|
@ -66,11 +70,6 @@ import mage.util.GameLog;
|
||||||
import mage.util.RandomUtil;
|
import mage.util.RandomUtil;
|
||||||
import org.apache.log4j.Logger;
|
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 {
|
public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(PlayerImpl.class);
|
private static final Logger logger = Logger.getLogger(PlayerImpl.class);
|
||||||
|
@ -2958,7 +2957,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ability
|
* @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 sourceObject
|
||||||
* @param game
|
* @param game
|
||||||
* @return
|
* @return
|
||||||
|
@ -3290,6 +3290,17 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
return getPlayable(game, hidden, Zone.ALL, true);
|
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) {
|
public List<ActivatedAbility> getPlayable(Game game, boolean hidden, Zone fromZone, boolean hideDuplicatedAbilities) {
|
||||||
List<ActivatedAbility> playable = new ArrayList<>();
|
List<ActivatedAbility> playable = new ArrayList<>();
|
||||||
if (shouldSkipGettingPlayable(game)) {
|
if (shouldSkipGettingPlayable(game)) {
|
||||||
|
@ -4004,7 +4015,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
// identify cards from one owner
|
// identify cards from one owner
|
||||||
Cards cards = new CardsImpl();
|
Cards cards = new CardsImpl();
|
||||||
UUID ownerId = null;
|
UUID ownerId = null;
|
||||||
for (Iterator<Card> it = allCards.iterator(); it.hasNext(); ) {
|
for (Iterator<Card> it = allCards.iterator(); it.hasNext();) {
|
||||||
Card card = it.next();
|
Card card = it.next();
|
||||||
if (cards.isEmpty()) {
|
if (cards.isEmpty()) {
|
||||||
ownerId = card.getOwnerId();
|
ownerId = card.getOwnerId();
|
||||||
|
|
Loading…
Reference in a new issue