@Override public void timerTimeout(Game game) { quit = true; timerTimeout = true; this.concede(game); game.informPlayers(getLogName() + " has run out of time, losing the match."); }
@Override public void idleTimeout(Game game) { quit = true; idleTimeout = true; this.concede(game); game.informPlayers(getLogName() + " was idle for too long, losing the Match."); }
@Override public void quit(Game game) { quit = true; this.concede(game); logger.debug(getName() + " quits the match."); game.informPlayers(getLogName() + " quits the match."); }
@Override public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone ) { if (card == null) { return false; } boolean result = false; // Zone fromZone = game.getState().getZone(card.getId()); if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null && fromZone == Zone.BATTLEFIELD)) { if (!game.isSimulation()) { if (card instanceof PermanentCard && game.getCard(card.getId()) != null) { card = game.getCard(card.getId()); } StringBuilder sb = new StringBuilder(this.getLogName()) .append(" puts ").append(card.getLogName()).append(' ').append(card.isCopy() ? "(Copy) " : "") .append(fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + ' ' : ""); if (card.isOwnedBy(getId())) { sb.append("into their graveyard"); } else { sb.append("it into its owner's graveyard"); } game.informPlayers(sb.toString()); } result = true; } return result; }
@Override public void lostForced(Game game) { logger.debug(this.getName() + " has lost gameId: " + game.getId()); //20100423 - 603.9 if (!this.wins) { this.loses = true; game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId)); game.informPlayers(this.getLogName() + " has lost the game."); } else { logger.debug(this.getName() + " has already won - stop lost"); } // for draw - first all players that have lost have to be set to lost if (!hasLeft()) { logger.debug("Game over playerId: " + playerId); game.setConcedingPlayer(playerId); } }
@Override public void discardToMax(Game game) { if (hand.size() > this.maxHandSize) { if (!game.isSimulation()) { game.informPlayers(getLogName() + " discards down to " + this.maxHandSize + (this.maxHandSize == 1 ? " hand card" : " hand cards")); } discard(hand.size() - this.maxHandSize, null, game); } }
@Override public void drew(Game game) { if (!hasLost()) { this.draws = true; game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DRAW_PLAYER, null, null, playerId)); game.informPlayers("For " + this.getLogName() + " the game is a draw."); game.setConcedingPlayer(playerId); } }
@Override public void revealCards(Ability source, String titleSuffix, Cards cards, Game game, boolean postToLog) { if (cards == null || cards.isEmpty()) { return; } if (postToLog) { game.getState().getRevealed().add(CardUtil.createObjectRealtedWindowTitle(source, game, titleSuffix), cards); } else { game.getState().getRevealed().update(CardUtil.createObjectRealtedWindowTitle(source, game, titleSuffix), cards); } if (postToLog && !game.isSimulation()) { StringBuilder sb = new StringBuilder(getLogName()).append(" reveals "); int current = 0, last = cards.size(); for (Card card : cards.getCards(game)) { current++; sb.append(GameLog.getColoredObjectName(card)); if (current < last) { sb.append(", "); } } game.informPlayers(sb.toString()); } }
@Override public void controlPlayersTurn(Game game, UUID playerId) { Player player = game.getPlayer(playerId); player.setTurnControlledBy(this.getId()); game.informPlayers(getLogName() + " controls the turn of " + player.getLogName()); if (!playerId.equals(this.getId())) { this.playersUnderYourControl.add(playerId); if (!player.hasLeft() && !player.hasLost()) { player.setGameUnderYourControl(false); } DelayedTriggeredAbility ability = new AtTheEndOfTurnStepPostDelayedTriggeredAbility(new LoseControlOnOtherPlayersControllerEffect(this.getLogName(), player.getLogName())); ability.setSourceId(getId()); ability.setControllerId(getId()); game.addDelayedTriggeredAbility(ability); } }
@Override public void shuffleLibrary(Ability source, Game game) { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.SHUFFLE_LIBRARY, playerId, playerId))) { this.library.shuffle(); if (!game.isSimulation()) { game.informPlayers(getLogName() + "'s library is shuffled"); } game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIBRARY_SHUFFLED, playerId, (source == null ? null : source.getSourceId()), playerId)); } }
@Override public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, Game game, Zone fromZone, boolean withName) { if (card == null) { return false; } boolean result = false; if (card.moveToExile(exileId, exileName, sourceId, game)) { if (!game.isSimulation()) { if (card instanceof PermanentCard) { // in case it's face down or name was changed by copying from other permanent Card basicCard = game.getCard(card.getId()); if (basicCard != null) { card = basicCard; } } else if (card instanceof Spell) { final Spell spell = (Spell) card; if (spell.isCopy()) { // Copied spell, only remove from stack game.getStack().remove(spell, game); } } game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() + (card.isCopy() ? " (Copy)" : "") : "a card face down") + ' ' + (fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + ' ' : "") + "to the exile zone"); } result = true; } return result; }
@Override public int loseLife(int amount, Game game, boolean atCombat) { if (!canLoseLife || !this.isInGame()) { return 0; } GameEvent event = new GameEvent(GameEvent.EventType.LOSE_LIFE, playerId, playerId, playerId, amount, atCombat); if (!game.replaceEvent(event)) { // this.life -= event.getAmount(); this.life = CardUtil.subtractWithOverflowCheck(this.life, event.getAmount()); if (!game.isSimulation()) { game.informPlayers(this.getLogName() + " loses " + event.getAmount() + " life"); } if (amount > 0) { game.fireEvent(new GameEvent(GameEvent.EventType.LOST_LIFE, playerId, playerId, playerId, amount, atCombat)); } return amount; } return 0; }
@Override public int gainLife(int amount, Game game, UUID sourceId) { if (!canGainLife || amount <= 0) { return 0; } GameEvent event = new GameEvent(GameEvent.EventType.GAIN_LIFE, playerId, playerId, playerId, amount, false); if (!game.replaceEvent(event)) { // TODO: lock life at Integer.MAX_VALUE if reached, until it's set to a different amount // (https://magic.wizards.com/en/articles/archive/news/unstable-faqawaslfaqpaftidawabiajtbt-2017-12-06 - "infinite" life total stays infinite no matter how much is gained or lost) // this.life += event.getAmount(); this.life = CardUtil.addWithOverflowCheck(this.life, event.getAmount()); if (!game.isSimulation()) { game.informPlayers(this.getLogName() + " gains " + event.getAmount() + " life"); } game.fireEvent(GameEvent.getEvent(GameEvent.EventType.GAINED_LIFE, playerId, sourceId, playerId, event.getAmount())); return event.getAmount(); } return 0; }
@Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, boolean withName ) { boolean result = false; Zone fromZone = game.getState().getZone(card.getId()); if (fromZone == Zone.BATTLEFIELD && !(card instanceof Permanent)) { card = game.getPermanent(card.getId()); } if (card.moveToZone(Zone.HAND, sourceId, game, false)) { if (card instanceof PermanentCard && game.getCard(card.getId()) != null) { card = game.getCard(card.getId()); } if (!game.isSimulation()) { game.informPlayers(getLogName() + " puts " + (withName ? card.getLogName() : (card.isFaceDown(game) ? "a face down card" : "a card")) + " from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + ' ' + (card.isOwnedBy(this.getId()) ? "into their hand" : "into its owner's hand") ); } result = true; } return result; }
/** * @param game * @param appliedEffects * @param numSides Number of sides the dice has * @return the number that the player rolled */ @Override public int rollDice(Game game, ArrayList<UUID> appliedEffects, int numSides) { int result = RandomUtil.nextInt(numSides) + 1; if (!game.isSimulation()) { game.informPlayers("[Roll a die] " + getLogName() + " rolled a " + result + " on a " + numSides + " sided die"); } GameEvent event = new GameEvent(GameEvent.EventType.ROLL_DICE, playerId, null, playerId, result, true); event.setAppliedEffects(appliedEffects); event.setAmount(result); event.setData(numSides + ""); if (!game.replaceEvent(event)) { GameEvent ge = new GameEvent(GameEvent.EventType.DICE_ROLLED, playerId, null, playerId, event.getAmount(), event.getFlag()); ge.setData(numSides + ""); game.fireEvent(ge); } return event.getAmount(); }
@Override public boolean putCardOnTopXOfLibrary(Card card, Game game, Ability source, int xFromTheTop) { if (card.isOwnedBy(getId())) { if (library.size() + 1 < xFromTheTop) { putCardsOnBottomOfLibrary(new CardsImpl(card), game, source, true); } else { if (card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true) && !(card instanceof PermanentToken) && !card.isCopy()) { card = getLibrary().removeFromTop(game); getLibrary().putCardToTopXPos(card, xFromTheTop, game); game.informPlayers(card.getLogName() + " is put into " + getLogName() + "'s library " + CardUtil.numberToOrdinalText(xFromTheTop) + " from the top"); } else { return false; } } } else { return game.getPlayer(card.getOwnerId()).putCardOnTopXOfLibrary(card, game, source, xFromTheTop); } return true; }
protected boolean specialAction(SpecialAction action, Game game) { //20091005 - 114 if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATE_ABILITY, action.getSourceId(), action.getId(), playerId))) { int bookmark = game.bookmarkState(); if (action.activate(game, false)) { game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, action.getSourceId(), action.getId(), playerId)); if (!game.isSimulation()) { game.informPlayers(getLogName() + action.getGameLogMessage(game)); } if (action.resolve(game)) { game.removeBookmark(bookmark); resetStoredBookmark(game); return true; } } restoreState(bookmark, action.getRule(), game); } return false; }
@Override public boolean scry(int value, Ability source, Game game) { game.informPlayers(getLogName() + " scries " + value); Cards cards = new CardsImpl(); cards.addAll(getLibrary().getTopCards(game, value)); if (!cards.isEmpty()) { String text; if (cards.size() == 1) { text = "card if you want to put it on the bottom of your library (Scry)"; } else { text = "cards you want to put on the bottom of your library (Scry)"; } TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard(text)); chooseTarget(Outcome.Benefit, cards, target, source, game); putCardsOnBottomOfLibrary(new CardsImpl(target.getTargets()), game, source, true); cards.removeAll(target.getTargets()); putCardsOnTopOfLibrary(cards, game, source, true); } game.fireEvent(new GameEvent(GameEvent.EventType.SCRY, getId(), source == null ? null : source.getSourceId(), getId(), value, true)); return true; }
@Override public boolean surveil(int value, Ability source, Game game) { GameEvent event = new GameEvent(GameEvent.EventType.SURVEIL, getId(), source == null ? null : source.getSourceId(), getId(), value, true); if (game.replaceEvent(event)) { return false; } game.informPlayers(getLogName() + " surveils " + event.getAmount()); Cards cards = new CardsImpl(); cards.addAll(getLibrary().getTopCards(game, event.getAmount())); if (!cards.isEmpty()) { String text; if (cards.size() == 1) { text = "card if you want to put it into your graveyard (Surveil)"; } else { text = "cards you want to put into your graveyard (Surveil)"; } TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard(text)); chooseTarget(Outcome.Benefit, cards, target, source, game); moveCards(new CardsImpl(target.getTargets()), Zone.GRAVEYARD, source, game); cards.removeAll(target.getTargets()); putCardsOnTopOfLibrary(cards, game, source, true); } game.fireEvent(new GameEvent(GameEvent.EventType.SURVEILED, getId(), source == null ? null : source.getSourceId(), getId(), event.getAmount(), true)); return true; }
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, ability.getId(), ability.getSourceId(), playerId)); if (!game.isSimulation()) { game.informPlayers(getLogName() + ability.getGameLogMessage(game));