forked from External/mage
1275 lines
40 KiB
Java
1275 lines
40 KiB
Java
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.VariableCost;
|
||
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.combat.CombatGroup;
|
||
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
|
||
*
|
||
* @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);
|
||
|
||
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 library’s owner doesn’t 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 mana spells and abilities
|
||
int announceXMana(int min, int max, String message, Game game, Ability ability);
|
||
|
||
// set the value for non mana X costs
|
||
int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost);
|
||
|
||
// 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);
|
||
|
||
UUID chooseAttackerOrder(List<Permanent> attacker, Game game);
|
||
|
||
/**
|
||
* Choose the order in which blockers get damage assigned to
|
||
*
|
||
* @param blockers list of blockers where to choose the next one from
|
||
* @param combatGroup the concerning combat group
|
||
* @param blockerOrder the already set order of blockers
|
||
* @param game
|
||
* @return blocker next to add to the blocker order
|
||
*/
|
||
UUID chooseBlockerOrder(List<Permanent> blockers, CombatGroup combatGroup, List<UUID> blockerOrder, Game game);
|
||
|
||
int getAmount(int min, int max, String message, 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;
|
||
}
|
||
}
|