foul-magics/Mage/src/main/java/mage/players/Player.java

1269 lines
40 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package mage.players;
import mage.*;
import mage.abilities.*;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.mana.ManaOptions;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.decks.Deck;
import mage.choices.Choice;
import mage.constants.*;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.counters.Counters;
import mage.designations.Designation;
import mage.designations.DesignationType;
import mage.filter.FilterCard;
import mage.filter.FilterMana;
import mage.filter.FilterPermanent;
import mage.game.*;
import mage.game.draft.Draft;
import mage.game.events.GameEvent;
import mage.game.match.Match;
import mage.game.match.MatchPlayer;
import mage.game.permanent.Permanent;
import mage.game.tournament.Tournament;
import mage.players.net.UserData;
import mage.target.Target;
import mage.target.TargetAmount;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import mage.util.Copyable;
import mage.util.MultiAmountMessage;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Warning, if you add new choose dialogs then must implement it for:
* - PlayerImpl (only if it use another default dialogs inside)
* - HumanPlayer (support client-server in human games)
* - ComputerPlayer (support AI in computer games)
* - StubPlayer (temp)
* - ComputerPlayerControllableProxy (support control of one player type over another player type)
* - TestPlayer (support unit tests)
*
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public interface Player extends MageItem, Copyable<Player> {
/**
* Enum used to indicate what each player is allowed to spend life on.
* By default it is set to `allAbilities`, but can be changed by effects.
* E.g. Angel of Jubilation sets it to `nonSpellnonActivatedAbilities`,
* and Karn's Sylex sets it to `onlyManaAbilities`.
* <p>
* <p>
* Default is PayLifeCostLevel.allAbilities.
*/
enum PayLifeCostLevel {
allAbilities, nonSpellnonActivatedAbilities, onlyManaAbilities, none
}
/**
* Current player is real life player (human). Try to use in GUI and network engine only.
* <p>
* WARNING, you must use isComputer instead isHuman in card's code (for good Human/AI logic testing in unit tests)
* TODO: check combat code and other and replace isHuman to isComputer usage if possible (if AI support that actions)
*
* @return
*/
boolean isHuman();
boolean isTestsMode();
/**
* Current player is AI. Use it in card's code and all other places.
* <p>
* It help to split Human/AI logic and test both by unit tests.
* <p>
* Usage example: AI hint to skip or auto-calculate choices instead call of real choose dialogs
* - unit tests for Human logic: call normal commands
* - unit tests for AI logic: call aiXXX commands
*
* @return
*/
default boolean isComputer() {
return !isHuman();
}
String getName();
String getLogName();
RangeOfInfluence getRange();
Library getLibrary();
Cards getSideboard();
Graveyard getGraveyard();
Abilities<Ability> getAbilities();
void addAbility(Ability ability);
/**
* The counters should be manipulated (adding or removing counters) with the appropriate addCounters/removeCounters/getCounterCount methods.
* This returns a copy for specific usage, to make sure the Player's counters are not altered from there.
*/
Counters getCountersAsCopy();
int getLife();
void initLife(int life);
/**
* Set player's life
*
* @param life
* @param game
* @param source can be null for cheats or game startup setup
*/
void setLife(int life, Game game, Ability source);
/**
* @param amount amount of life loss
* @param game
* @param source can be null for default game events like mana burn
* @param atCombat was the source combat damage
* @param attackerId id of the attacker for combat events (can be null)
* @return
*/
int loseLife(int amount, Game game, Ability source, boolean atCombat, UUID attackerId);
int loseLife(int amount, Game game, Ability source, boolean atCombat);
/**
* @param amount
* @param game
* @param source can be null for default game events life lifelink damage
* @return
*/
int gainLife(int amount, Game game, Ability source);
void exchangeLife(Player player, Ability source, Game game);
int damage(int damage, Ability source, Game game);
int damage(int damage, UUID attackerId, Ability source, Game game);
int damage(int damage, UUID attackerId, Ability source, Game game, boolean combatDamage, boolean preventable);
int damage(int damage, UUID attackerId, Ability source, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects);
// to handle rule changing effects (613.10)
boolean isCanLoseLife();
void setCanLoseLife(boolean canLoseLife);
void setCanGainLife(boolean canGainLife);
boolean isCanGainLife();
/**
* Is the player allowed to pay life for casting spells or activate activated abilities
*
* @param payLifeCostLevel
*/
void setPayLifeCostLevel(PayLifeCostLevel payLifeCostLevel);
PayLifeCostLevel getPayLifeCostLevel();
/**
* Can the player pay life to cast or activate the given ability
*
* @param Ability
* @return
*/
boolean canPayLifeCost(Ability Ability);
void setCanPaySacrificeCostFilter(FilterPermanent filter);
FilterPermanent getSacrificeCostFilter();
boolean canPaySacrificeCost(Permanent permanent, Ability source, UUID controllerId, Game game);
void setLifeTotalCanChange(boolean lifeTotalCanChange);
boolean isLifeTotalCanChange();
void setLoseByZeroOrLessLife(boolean loseByZeroOrLessLife);
boolean canLoseByZeroOrLessLife();
void setPlotFromTopOfLibrary(boolean canPlotFromTopOfLibrary);
boolean canPlotFromTopOfLibrary();
void setDrawsFromBottom(boolean drawsFromBottom);
boolean isDrawsFromBottom();
void setDrawsOnOpponentsTurn(boolean drawsOnOpponentsTurn);
boolean isDrawsOnOpponentsTurn();
int getSpeed();
void initSpeed(Game game);
void increaseSpeed(Game game);
void decreaseSpeed(Game game);
/**
* Returns alternative casting costs a player can cast spells for
*
* @return
*/
List<AlternativeSourceCosts> getAlternativeSourceCosts();
Cards getHand();
void incrementLandsPlayed();
void resetLandsPlayed();
int getLandsPlayed();
int getLandsPerTurn();
void setLandsPerTurn(int landsPerTurn);
int getMaxHandSize();
void setMaxHandSize(int maxHandSize);
int getMaxAttackedBy();
void setMaxAttackedBy(int maxAttackedBy);
boolean isPassed();
void pass(Game game);
void resetPassed();
void resetPlayerPassedActions();
boolean getPassedTurn();
boolean getPassedUntilEndOfTurn();
boolean getPassedUntilNextMain();
boolean getPassedUntilStackResolved();
boolean getPassedUntilEndStepBeforeMyTurn();
boolean getPassedAllTurns();
AbilityType getJustActivatedType();
void setJustActivatedType(AbilityType abilityType);
boolean hasLost();
boolean hasDrew();
boolean hasWon();
boolean hasQuit();
void quit(Game game);
boolean hasTimerTimeout();
void timerTimeout(Game game);
boolean hasIdleTimeout();
void idleTimeout(Game game);
// TODO: research usage of !hasLeft() && !hasLost() replace it by isInGame() if possible
boolean hasLeft();
/**
* Player is still active in game (has not left, lost or won the game).
*
* @return
*/
boolean isInGame();
/**
* Player is still active in game (has not left, lost or won the game) and
* no abort state is given.
*
* @return
*/
boolean canRespond();
ManaPool getManaPool();
/**
* Is checking player in range of current player.
* Warning, range list updates on start of the turn due rules.
*/
boolean hasPlayerInRange(UUID checkingPlayerId);
boolean isTopCardRevealed();
void setTopCardRevealed(boolean topCardRevealed);
/**
* User's settings like avatar or skip buttons.
* WARNING, game related code must use controlling player settings only, e.g. getControllingPlayersUserData
*/
UserData getUserData();
void setUserData(UserData userData);
boolean canLose(Game game);
boolean autoLoseGame();
/**
* Returns a set of players which turns under you control. Doesn't include
* yourself.
*
* @return
*/
Set<UUID> getPlayersUnderYourControl();
/**
* Defines player whose turn this player controls at the moment.
*
* @param game
* @param playerUnderControlId
* @param info additional info to show in game logs like source
* @return false on failed taken control, e.g. on unsupported player type
*/
boolean controlPlayersTurn(Game game, UUID playerUnderControlId, String info);
/**
* Sets player {@link UUID} who controls this player's turn.
*
* @param playerId
*/
void setTurnControlledBy(UUID playerId);
List<UUID> getTurnControllers();
/**
* Current turn controller for a player (return own id for own control)
*/
UUID getTurnControlledBy();
/**
* Resets players whose turns you control at the moment.
*/
void resetOtherTurnsControlled();
/**
* Returns false in case player don't control the game.
* <p>
* Note: For effects like "You control target player during that player's
* next turn".
*
* @return
*/
boolean isGameUnderControl();
/**
* False in case you don't control the game.
* <p>
* Note: For effects like "You control target player during that player's
* next turn".
*
* @param value
*/
void setGameUnderYourControl(boolean value);
/**
* Return player's turn control to prev player
*
* @param value
* @param fullRestore return turn control to own
*/
void setGameUnderYourControl(boolean value, boolean fullRestore);
void setTestMode(boolean value);
void setAllowBadMoves(boolean allowBadMoves);
/**
* Reset values before new game, e.g. for next game
*/
void init(Game game);
void useDeck(Deck deck, Game game);
/**
* Called before each applyEffects, to rest all what can be applied by
* continuous effects
*/
void reset();
/**
* @param source can be null for game default shuffle (non effects, example: mulligans)
* @param game
*/
void shuffleLibrary(Ability source, Game game);
/**
* Draw cards. If you call it in replace events then use method with event param instead (for appliedEffects)
*
* @param num cards to draw
* @param source can be null for game default draws (non effects, example: start of the turn)
* @return number of cards drawn, including as a result of replacement effects
*/
int drawCards(int num, Ability source, Game game);
/**
* Draw cards with applied effects, for replaceEvent
*
* @param num cards to draw
* @param source can be null for game default draws (non effects, example: start of the turn)
* @param event original draw event in replacement code
* @return number of cards drawn, including as a result of replacement effects
*/
int drawCards(int num, Ability source, Game game, GameEvent event);
boolean cast(SpellAbility ability, Game game, boolean noMana, ApprovingObject approvingObject);
/**
* Force player to choose spell ability to cast. Use it in effects while casting cards.
* <p>
* Commands order in all use cases:
* - PlayFromNotOwnHandZone - true (if you put main id then all parts allows, if you put part id then only part allows)
* - chooseAbilityForCast
* - cast
* - PlayFromNotOwnHandZone - false
*
* @param card
* @param game
* @param noMana
* @return
*/
SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana);
ActivatedAbility chooseLandOrSpellAbility(Card card, Game game, boolean noMana);
boolean removeFromHand(Card card, Game game);
boolean removeFromBattlefield(Permanent permanent, Ability source, Game game);
boolean putInGraveyard(Card card, Game game);
boolean removeFromGraveyard(Card card, Game game);
boolean removeFromLibrary(Card card, Game game);
boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game);
/**
* @param target
* @param source
* @param game
* @param targetPlayerId player whose library will be searched
* @return true if search was successful
*/
boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId);
/**
* Gets a random card which matches the given filter and puts it into its owner's hand
* Doesn't reveal the card
*/
boolean seekCard(FilterCard filter, Ability source, Game game);
/**
* Reveals all players' libraries. Useful for abilities like Jace, Architect
* of Thought's -8 that have effects that require information from all
* libraries.
*
* @param source
* @param game
* @return
*/
void lookAtAllLibraries(Ability source, Game game);
boolean canPlayLand();
/**
* Plays a card (play land or cast spell). Works from any zones without timing restriction
*
* @param card the card that can be cast
* @param game
* @param noMana if it's a spell it can be cast without paying mana
* @param approvingObject reference to the ability that allows to play the card
* @return
*/
// TODO: should have a version taking a PlayLandAbility or SpellAbility to handle MDFC/Zoetic Cavern/Adventure/etc...
boolean playCard(Card card, Game game, boolean noMana, ApprovingObject approvingObject);
/**
* @param card the land card to play
* @param game
* @param ignoreTiming false - it won't be checked if the stack is empty and
* you are able to play a Sorcery. It's still checked,
* if you are able to play a land concerning the number
* of lands you already played.
* @return
*/
// TODO: should have a version taking a PlayLandAbility to handle MDFC/Zoetic Cavern/etc...
boolean playLand(Card card, Game game, boolean ignoreTiming);
boolean activateAbility(ActivatedAbility ability, Game game);
boolean triggerAbility(TriggeredAbility ability, Game game);
boolean canBeTargetedBy(MageObject sourceObject, UUID sourceControllerId, Ability source, Game game);
boolean hasProtectionFrom(MageObject source, Game game);
boolean flipCoin(Ability source, Game game, boolean winnable);
boolean flipCoinResult(Game game);
default int rollDice(Outcome outcome, Ability source, Game game, int numSides) {
return rollDice(outcome, source, game, numSides, 1, 0).stream().findFirst().orElse(0);
}
List<Integer> rollDice(Outcome outcome, Ability source, Game game, int numSides, int numDice, int ignoreLowestAmount);
int rollDieResult(int sides, Game game);
default PlanarDieRollResult rollPlanarDie(Outcome outcome, Ability source, Game game) {
return rollPlanarDie(outcome, source, game, GameOptions.PLANECHASE_PLANAR_DIE_CHAOS_SIDES, GameOptions.PLANECHASE_PLANAR_DIE_PLANAR_SIDES);
}
PlanarDieRollResult rollPlanarDie(Outcome outcome, Ability source, Game game, int numberChaosSides, int numberPlanarSides);
Card discardOne(boolean random, boolean payForCost, Ability source, Game game);
Cards discard(int amount, boolean random, boolean payForCost, Ability source, Game game);
Cards discard(int minAmount, int maxAmount, boolean payForCost, Ability source, Game game);
Cards discard(Cards cards, boolean payForCost, Ability source, Game game);
void discardToMax(Game game);
boolean discard(Card card, boolean payForCost, Ability source, Game game);
void lost(Game game);
void lostForced(Game game);
void drew(Game game);
void won(Game game);
void leave();
void concede(Game game);
void abort();
void abortReset();
void signalPlayerConcede(boolean stopCurrentChooseDialog);
void signalPlayerCheat();
void skip();
// priority, undo, ...
void sendPlayerAction(PlayerAction passPriorityAction, Game game, Object data);
int getStoredBookmark();
/**
* Save player's bookmark for undo, e.g. enable undo button on mana payment
*
* @param bookmark
*/
void setStoredBookmark(int bookmark);
/**
* Reset player's bookmark, e.g. disable undo button
*
* @param game
*/
void resetStoredBookmark(Game game);
default GameState restoreState(int bookmark, String text, Game game) {
GameState state = game.restoreState(bookmark, text);
if (getStoredBookmark() >= bookmark) {
resetStoredBookmark(game);
}
return state;
}
void revealCards(Ability source, Cards cards, Game game);
void revealCards(String titleSuffix, Cards cards, Game game);
void revealCards(Ability source, String titleSuffix, Cards cards, Game game);
void revealCards(String titleSuffix, Cards cards, Game game, boolean postToLog);
/**
* Adds the cards to the reveal window and adds the source object's id name
* to the title bar of the revealed cards window
* <p>
* Warning, if you use it from continuous effect, then check with extra call
* isCanLookAtNextTopLibraryCard
* If you use revealCards with face-down permanents, they will be revealed face up.
*
* @param source
* @param name
* @param cards
* @param game
* @param postToLog
*/
void revealCards(Ability source, String name, Cards cards, Game game, boolean postToLog);
void lookAtCards(String name, Card card, Game game);
void lookAtCards(String name, Cards cards, Game game);
/**
* Adds the cards to the look window and adds the source object's id name to
* the title bar of the lookedAt window
* <p>
* Warning, if you use it from continuous effect, then check with extra call
* isCanLookAtNextTopLibraryCard
*
* @param source
* @param name
* @param cards
* @param game
*/
void lookAtCards(Ability source, String name, Cards cards, Game game);
@Override
Player copy();
void restore(Player player);
void setResponseString(String responseString);
void setResponseUUID(UUID responseUUID);
void setResponseBoolean(Boolean responseBoolean);
void setResponseInteger(Integer data);
void setResponseManaType(UUID manaTypePlayerId, ManaType responseManaType);
boolean priority(Game game);
/**
* Warning, any choose and chooseTarget dialogs must return false to stop choosing, e.g. no more possible targets
* Same logic as "something changes" in "apply"
*/
boolean choose(Outcome outcome, Target target, Ability source, Game game);
boolean choose(Outcome outcome, Target target, Ability source, Game game, Map<String, Serializable> options);
boolean choose(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game);
boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game);
boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game);
boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game);
boolean chooseMulligan(Game game);
boolean chooseUse(Outcome outcome, String message, Ability source, Game game);
boolean chooseUse(Outcome outcome, String message, String secondMessage, String trueText, String falseText, Ability source, Game game);
boolean choose(Outcome outcome, Choice choice, Game game);
boolean choosePile(Outcome outcome, String message, List<? extends Card> pile1, List<? extends Card> pile2, Game game);
boolean playMana(Ability ability, ManaCost unpaid, String promptText, Game game);
/**
* Moves the cards from cards to the bottom of the players library.
*
* @param cards - list of cards that have to be moved
* @param game - game
* @param anyOrder - true = if player can determine the order of the cards
* else false = random order 401.4. If an effect puts two or
* more cards in a specific position in a library at the
* same time, the owner of those cards may arrange them in
* any order. That librarys owner doesnt reveal the order
* in which the cards go into the library.
* @param source - source ability
* @return
*/
boolean putCardsOnBottomOfLibrary(Cards cards, Game game, Ability source, boolean anyOrder);
boolean putCardsOnBottomOfLibrary(Card card, Game game, Ability source, boolean anyOrder);
/**
* Moves the card to the top x position of the library
*
* @param card
* @param game
* @param source
* @param xFromTheTop
* @param withName - show card name in game logs for all players
* @return
*/
boolean putCardOnTopXOfLibrary(Card card, Game game, Ability source, int xFromTheTop, boolean withName);
/**
* Moves the cards from cards to the top of players library.
*
* @param cards - list of cards that have to be moved
* @param game - game
* @param anyOrder - true if player can determine the order of the cards
* @param source - source ability
* @return
*/
boolean putCardsOnTopOfLibrary(Cards cards, Game game, Ability source, boolean anyOrder);
boolean putCardsOnTopOfLibrary(Card card, Game game, Ability source, boolean anyOrder);
boolean shuffleCardsToLibrary(Cards cards, Game game, Ability source);
boolean shuffleCardsToLibrary(Card card, Game game, Ability source);
/**
* Set the value for X in spells and abilities
* @param isManaPay helper param for better AI logic
*/
int announceX(int min, int max, String message, Game game, Ability source, boolean isManaPay);
// TODO: rework to use pair's list of effect + ability instead string's map
int chooseReplacementEffect(Map<String, String> effectsMap, Map<String, MageObject> objectsMap, Game game);
TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game);
Mode chooseMode(Modes modes, Ability source, Game game);
void selectAttackers(Game game, UUID attackingPlayerId);
void selectBlockers(Ability source, Game game, UUID defendingPlayerId);
/**
*
* @param source can be null for system actions like define damage
*/
int getAmount(int min, int max, String message, Ability source, Game game);
/**
* Player distributes amount among multiple options
*
* @param outcome AI hint
* @param messages List of options to distribute amount among
* @param optionMin Minimum value per option
* @param totalMin Minimum total amount to be distributed
* @param totalMax Total amount to be distributed
* @param type MultiAmountType enum to set dialog options such as title and header
* @param game Game
* @return List of integers with size equal to messages.size(). The sum of the integers is equal to max.
*/
default List<Integer> getMultiAmount(Outcome outcome, List<String> messages, int optionMin, int totalMin, int totalMax, MultiAmountType type, Game game) {
if (optionMin > totalMax || optionMin * messages.size() > totalMin) {
throw new IllegalArgumentException(String.format("Wrong code usage: getMultiAmount found bad option min/max values: %d/%d", optionMin, totalMax));
}
List<MultiAmountMessage> constraints = messages.stream()
.map(s -> new MultiAmountMessage(s, optionMin, totalMax))
.collect(Collectors.toList());
return getMultiAmountWithIndividualConstraints(outcome, constraints, totalMin, totalMax, type, game);
}
/**
* Player distributes amount among multiple options
*
* @param outcome AI hint
* @param messages List of options to distribute amount among. Each option has a constraint on the min, max chosen for it
* @param totalMin Total minimum amount to be distributed
* @param totalMax Total amount to be distributed
* @param type MultiAmountType enum to set dialog options such as title and header
* @param game Game
* @return List of integers with size equal to messages.size(). The sum of the integers is equal to max.
*/
List<Integer> getMultiAmountWithIndividualConstraints(Outcome outcome, List<MultiAmountMessage> messages, int totalMin, int totalMax, MultiAmountType type, Game game);
void sideboard(Match match, Deck deck);
void construct(Tournament tournament, Deck deck);
void pickCard(List<Card> cards, Deck deck, Draft draft);
// TODO: add result, process it in AI code (if something put creature to attack then it can broke current AI logic)
void declareAttacker(UUID attackerId, UUID defenderId, Game game, boolean allowUndo);
void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game);
void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game, boolean allowUndo);
List<Permanent> getAvailableAttackers(Game game);
List<Permanent> getAvailableAttackers(UUID defenderId, Game game);
List<Permanent> getAvailableBlockers(Game game);
void beginTurn(Game game);
void endOfTurn(Game game);
void phasing(Game game);
void untap(Game game);
void updateRange(Game game);
ManaOptions getManaAvailable(Game originalGame);
void addAvailableTriggeredMana(List<Mana> netManaAvailable);
List<List<Mana>> getAvailableTriggeredMana();
List<ActivatedAbility> getPlayable(Game game, boolean hidden);
List<Ability> getPlayableOptions(Ability ability, Game game);
PlayableObjectsList getPlayableObjects(Game game, Zone zone);
Map<UUID, ActivatedAbility> getPlayableActivatedAbilities(MageObject object, Zone zone, Game originalGame);
/**
* add counter to the player (action verb is `get`, but not using that one to avoid ambiguity with getters)
*/
boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game);
/**
* lose {@param amount} counters of the specified kind.
*/
void loseCounters(String counterName, int amount, Ability source, Game game);
/**
* lose all counters of any kind.
*
* @return the amount of counters removed this way.
*/
int loseAllCounters(Ability source, Game game);
/**
* lose all counters of a specific kind.
*
* @return the amount of counters removed this way.
*/
int loseAllCounters(String counterName, Ability source, Game game);
/**
* @return the amount of counters of the specified kind the player has
*/
int getCountersCount(CounterType counterType);
/**
* @return the amount of counters of the specified kind the player has
*/
int getCountersCount(String counterName);
/**
* @return the amount of counters in total of any kind the player has
*/
int getCountersTotalCount();
List<UUID> getAttachments();
boolean addAttachment(UUID permanentId, Ability source, Game game);
boolean removeAttachment(Permanent permanent, Ability source, Game game);
/**
* Signals that the player becomes active player in this turn.
*/
void becomesActivePlayer();
int getTurns();
/**
* asThough effect to reveal faceDown cards
*
* @param card
* @param game
* @param abilitiesToActivate extra info about abilities that can be
* activated on NO option
* @return player looked at the card
*/
boolean lookAtFaceDownCard(Card card, Game game, int abilitiesToActivate);
/**
* Set seconds left to play the game.
*
* @param timeLeft
*/
void setPriorityTimeLeft(int timeLeft);
/**
* Returns seconds left to play the game.
*
* @return
*/
int getPriorityTimeLeft();
/**
* Set seconds left before priority time starts ticking down.
*
* @param timeLeft
*/
void setBufferTimeLeft(int timeLeft);
/**
* Returns seconds left before priority time starts ticking down.
*
* @return
*/
int getBufferTimeLeft();
void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving);
boolean hasReachedNextTurnAfterLeaving();
/**
* Checks if a AI player is able to join a table i.e. Draft - bot can not
* enter a table with constructed format
*
* @param table
* @return
*/
boolean canJoinTable(Table table);
/**
* Set the commanderId of the player
*
* @param commanderId
*/
void addCommanderId(UUID commanderId);
/**
* Get the commanderIds of the player Deprecated, use
* game.getCommandersIds(xxx) instead
*
* @return
*/
@Deprecated
Set<UUID> getCommandersIds();
/**
* Moves cards from one zone to another
*
* @param cards
* @param toZone
* @param source
* @param game
* @return
*/
boolean moveCards(Cards cards, Zone toZone, Ability source, Game game);
boolean moveCards(Card card, Zone toZone, Ability source, Game game);
boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects);
boolean moveCards(Set<? extends Card> cards, Zone toZone, Ability source, Game game);
/**
* Universal method to move cards from one zone to another. Do not mix
* objects from different zones to move.
*
* @param cards
* @param toZone
* @param source
* @param game
* @param tapped the cards are tapped on the battlefield
* @param faceDown the cards are face down in the to zone
* @param byOwner the card is moved (or put onto battlefield) by the
* owner of the card and if target zone is battlefield
* controls the permanent (instead of the controller
* of the source)
* @param appliedEffects
* @return
*/
boolean moveCards(Set<? extends Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects);
boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName);
boolean moveCardsToExile(Set<Card> cards, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName);
/**
* Uses card.moveToZone and posts a inform message about moving the card
* into the game log
*
* @param card
* @param source
* @param game
* @param withName show the card name in the log
* @return
*/
boolean moveCardToHandWithInfo(Card card, Ability source, Game game, boolean withName);
/**
* Iterates through a set of cards and runs moveCardToHandWithInfo on each item
*
* @param cards
* @param source
* @param game
* @param withName show the card names in the log
* @return
*/
boolean moveCardsToHandWithInfo(Cards cards, Ability source, Game game, boolean withName);
/**
* Uses card.moveToExile and posts a inform message about moving the card to
* exile into the game log. Don't use this in replacement effects, because
* list of applied effects is not saved
*
* @param card
* @param exileId exile zone id (optional)
* @param exileName name of exile zone (optional)
* @param source
* @param game
* @param fromZone
* @param withName for face down: used to hide card name in game logs before real face down status apply
* @return
*/
@Deprecated
// if you want to use it in replaceEvent, then use ((ZoneChangeEvent) event).setToZone(Zone.EXILED);
boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, Ability source, Game game, Zone fromZone, boolean withName);
/**
* Uses card.moveToZone and posts a inform message about moving the card to
* graveyard into the game log
*
* @param card
* @param source
* @param game
* @param fromZone if null, this info isn't postet
* @return
*/
boolean moveCardToGraveyardWithInfo(Card card, Ability source, Game game, Zone fromZone);
/**
* Internal used to move cards Use commonly player.moveCards()
*
* @param cards
* @param source
* @param game
* @param fromZone if null, this info isn't postet
* @return Set<Cards> that were successful moved to graveyard
*/
Set<Card> moveCardsToGraveyardWithInfo(Set<? extends Card> cards, Ability source, Game game, Zone fromZone);
/**
* Uses card.moveToZone and posts a inform message about moving the card to
* library into the game log
*
* @param card
* @param source
* @param game
* @param fromZone if null, this info isn't postet
* @param toTop to the top of the library else to the bottom
* @param withName show the card name in the log
* @return
*/
boolean moveCardToLibraryWithInfo(Card card, Ability source, Game game, Zone fromZone, boolean toTop, boolean withName);
/**
* Uses card.moveToZone and posts a inform message about moving the card to
* library into the game log
*
* @param card
* @param source
* @param game
* @param fromZone if null, this info isn't postet
* @return
*/
boolean moveCardToCommandWithInfo(Card card, Ability source, Game game, Zone fromZone);
Cards millCards(int toMill, Ability source, Game game);
/**
* Checks if the playerToCheckId is from an opponent in range
*
* @param playerToCheckId
* @param game
* @return true if playerToCheckId belongs to an opponent
*/
boolean hasOpponent(UUID playerToCheckId, Game game);
/**
* Free resources on match end
*/
void cleanUpOnMatchEnd();
/**
* If the next spell cast has the set sourceId, the spell will be cast
* without mana (null) or the mana set to manaCosts instead of its normal
* mana costs.
*
* @param sourceId the source that can be cast without mana
* @param manaCosts alternate ManaCost, null if it can be cast without mana
* cost
* @param costs alternate other costs you need to pay
*/
default void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts<ManaCost> manaCosts, Costs<Cost> costs) {
setCastSourceIdWithAlternateMana(sourceId, manaCosts, costs, MageIdentifier.Default);
}
/**
* If the next spell cast has the set sourceId, the spell will be cast
* without mana (null) or the mana set to manaCosts instead of its normal
* mana costs.
*
* @param sourceId the source that can be cast without mana
* @param manaCosts alternate ManaCost, null if it can be cast without mana
* cost
* @param costs alternate other costs you need to pay
* @param identifier if not using the MageIdentifier.Default, only apply the alternate mana when ApprovingSource if of that kind.
*/
void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts<ManaCost> manaCosts, Costs<Cost> costs, MageIdentifier identifier);
Map<UUID, Set<MageIdentifier>> getCastSourceIdWithAlternateMana();
Map<UUID, Map<MageIdentifier, ManaCosts<ManaCost>>> getCastSourceIdManaCosts();
Map<UUID, Map<MageIdentifier, Costs<Cost>>> getCastSourceIdCosts();
void clearCastSourceIdManaCosts();
// permission handling to show hand cards
void addPermissionToShowHandCards(UUID watcherUserId);
boolean hasUserPermissionToSeeHand(UUID userId);
void revokePermissionToSeeHandCards();
boolean isPlayerAllowedToRequestHand(UUID gameId, UUID requesterPlayerId);
void addPlayerToRequestedHandList(UUID gameId, UUID requesterPlayerId);
Set<UUID> getUsersAllowedToSeeHandCards();
void setPayManaMode(boolean payManaMode);
boolean isInPayManaMode();
void setMatchPlayer(MatchPlayer matchPlayer);
MatchPlayer getMatchPlayer();
boolean scry(int value, Ability source, Game game);
/**
* result of the doSurveil action.
* Sometimes more info is needed for the caller after the surveil is done.
*/
class SurveilResult {
private final boolean surveilled;
private final int numberInGraveyard; // how many cards were put into the graveyard
private final int numberOnTop; // how many cards were put into the graveyard
private SurveilResult(boolean surveilled, int inGrave, int onTop) {
this.surveilled = surveilled;
this.numberInGraveyard = inGrave;
this.numberOnTop = onTop;
}
public static SurveilResult noSurveil() {
return new SurveilResult(false, 0, 0);
}
public static SurveilResult surveil(int inGrave, int onTop) {
return new SurveilResult(true, inGrave, onTop);
}
public boolean hasSurveilled() {
return this.surveilled;
}
public int getNumberPutInGraveyard() {
return this.numberInGraveyard;
}
public int getNumberPutOnTop() {
return this.numberOnTop;
}
}
SurveilResult doSurveil(int value, Ability source, Game game);
default boolean surveil(int value, Ability source, Game game) {
SurveilResult result = doSurveil(value, source, game);
return result.hasSurveilled();
}
/**
* Only used for test player for pre-setting targets
*
* @param ability
* @param game
* @return
*/
boolean addTargets(Ability ability, Game game);
boolean hasDesignation(DesignationType designationName);
void addDesignation(Designation designation);
List<Designation> getDesignations();
/**
* Set the mana colors the user can pay with 2 life instead
*
* @param colors
*/
void addPhyrexianToColors(FilterMana colors);
/**
* Mana colors the player can pay instead with 2 life
*/
FilterMana getPhyrexianColors();
Permanent getRingBearer(Game game);
void chooseRingBearer(Game game);
/**
* Function to query if the player has strictChooseMode enabled. Only the test player can have it.
* Function is added here so that the test suite project does not have to be imported into the client/server project.
*
* @return whether the player has strictChooseMode enabled
*/
public default boolean getStrictChooseMode() {
return false;
}
public UserData getControllingPlayersUserData(Game game);
/**
* Some player implementations (TestPlayer, Simulated) uses facade structure with hidden player object,
* so that's method helps to find real player that used by a game (in most use cases it's a PlayerImpl)
*/
Player getRealPlayer();
default Player prepareControllableProxy(Player playerUnderControl) {
return this;
}
}