mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
322 lines
13 KiB
Java
322 lines
13 KiB
Java
/*
|
|
* Forge: Play Magic: the Gathering.
|
|
* Copyright (C) 2011 Forge Team
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package forge.game.phase;
|
|
|
|
import forge.AllZone;
|
|
import forge.AllZoneUtil;
|
|
import forge.Card;
|
|
import forge.CardList;
|
|
import forge.CardListFilter;
|
|
import forge.CardListUtil;
|
|
import forge.Counters;
|
|
import forge.Singletons;
|
|
import forge.card.spellability.Ability;
|
|
import forge.card.spellability.SpellAbility;
|
|
import forge.game.GameLossReason;
|
|
import forge.game.player.Player;
|
|
import forge.game.zone.ZoneType;
|
|
import forge.gui.GuiUtils;
|
|
|
|
/**
|
|
* <p>
|
|
* Handles "until end of turn" effects and "at end of turn" triggers.
|
|
* </p>
|
|
*
|
|
* @author Forge
|
|
* @version $Id$
|
|
*/
|
|
public class EndOfTurn extends Phase implements java.io.Serializable {
|
|
/** Constant <code>serialVersionUID=-3656715295379727275L</code>. */
|
|
private static final long serialVersionUID = -3656715295379727275L;
|
|
|
|
/**
|
|
* <p>
|
|
* Handles all the hardcoded events that happen "at end of turn".
|
|
* </p>
|
|
*/
|
|
@Override
|
|
public final void executeAt() {
|
|
|
|
// TODO - should this freeze the Stack?
|
|
|
|
final CardList all = AllZoneUtil.getCardsIn(ZoneType.Battlefield);
|
|
|
|
EndOfTurn.endOfTurnWallOfReverence();
|
|
EndOfTurn.endOfTurnLighthouseChronologist();
|
|
|
|
// reset mustAttackEntity for me
|
|
Singletons.getModel().getGameState().getPhaseHandler().getPlayerTurn().setMustAttackEntity(null);
|
|
|
|
EndOfTurn.removeAttackedBlockedThisTurn();
|
|
|
|
AllZone.getStaticEffects().rePopulateStateBasedList();
|
|
|
|
for (final Card c : all) {
|
|
if (!c.isFaceDown() && c.hasKeyword("At the beginning of the end step, sacrifice CARDNAME.")) {
|
|
final Card card = c;
|
|
final SpellAbility sac = new Ability(card, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
if (AllZoneUtil.isCardInPlay(card)) {
|
|
Singletons.getModel().getGameAction().sacrifice(card, null);
|
|
}
|
|
}
|
|
};
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append("Sacrifice ").append(card);
|
|
sac.setStackDescription(sb.toString());
|
|
sac.setDescription(sb.toString());
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(sac);
|
|
|
|
}
|
|
if (!c.isFaceDown() && c.hasKeyword("At the beginning of the end step, exile CARDNAME.")) {
|
|
final Card card = c;
|
|
final SpellAbility exile = new Ability(card, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
if (AllZoneUtil.isCardInPlay(card)) {
|
|
Singletons.getModel().getGameAction().exile(card);
|
|
}
|
|
}
|
|
};
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append("Exile ").append(card);
|
|
exile.setStackDescription(sb.toString());
|
|
exile.setDescription(sb.toString());
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(exile);
|
|
|
|
}
|
|
if (!c.isFaceDown() && c.hasKeyword("At the beginning of the end step, destroy CARDNAME.")) {
|
|
final Card card = c;
|
|
final SpellAbility destroy = new Ability(card, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
if (AllZoneUtil.isCardInPlay(card)) {
|
|
Singletons.getModel().getGameAction().destroy(card);
|
|
}
|
|
}
|
|
};
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append("Destroy ").append(card);
|
|
destroy.setStackDescription(sb.toString());
|
|
destroy.setDescription(sb.toString());
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(destroy);
|
|
|
|
}
|
|
// Berserk is using this, so don't check isFaceDown()
|
|
if (c.hasKeyword("At the beginning of the next end step, destroy CARDNAME if it attacked this turn.")) {
|
|
if (c.getDamageHistory().getCreatureAttackedThisTurn()) {
|
|
final Card card = c;
|
|
final SpellAbility sac = new Ability(card, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
if (AllZoneUtil.isCardInPlay(card)) {
|
|
Singletons.getModel().getGameAction().destroy(card);
|
|
}
|
|
}
|
|
};
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append("Destroy ").append(card);
|
|
sac.setStackDescription(sb.toString());
|
|
sac.setDescription(sb.toString());
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(sac);
|
|
|
|
} else {
|
|
c.removeAllExtrinsicKeyword("At the beginning of the next end step, "
|
|
+ "destroy CARDNAME if it attacked this turn.");
|
|
}
|
|
}
|
|
if (c.hasKeyword("An opponent gains control of CARDNAME at the beginning of the next end step.")) {
|
|
final Card vale = c;
|
|
final SpellAbility change = new Ability(vale, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
if (AllZoneUtil.isCardInPlay(vale)) {
|
|
vale.addController(vale.getController().getOpponent());
|
|
// Singletons.getModel().getGameAction().changeController(
|
|
// new CardList(vale), vale.getController(),
|
|
// vale.getController().getOpponent());
|
|
|
|
vale.removeAllExtrinsicKeyword("An opponent gains control of CARDNAME "
|
|
+ "at the beginning of the next end step.");
|
|
}
|
|
}
|
|
};
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append(vale.getName()).append(" changes controllers.");
|
|
change.setStackDescription(sb.toString());
|
|
change.setDescription(sb.toString());
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(change);
|
|
|
|
}
|
|
if (c.getName().equals("Erg Raiders") && !c.getDamageHistory().getCreatureAttackedThisTurn() && !c.hasSickness()
|
|
&& Singletons.getModel().getGameState().getPhaseHandler().isPlayerTurn(c.getController())) {
|
|
final Card raider = c;
|
|
final SpellAbility change = new Ability(raider, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
if (AllZoneUtil.isCardInPlay(raider)) {
|
|
raider.getController().addDamage(2, raider);
|
|
}
|
|
}
|
|
};
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append(raider).append(" deals 2 damage to controller.");
|
|
change.setStackDescription(sb.toString());
|
|
change.setDescription(sb.toString());
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(change);
|
|
|
|
}
|
|
if (c.hasKeyword("At the beginning of your end step, return CARDNAME to its owner's hand.")
|
|
&& Singletons.getModel().getGameState().getPhaseHandler().isPlayerTurn(c.getController())) {
|
|
final Card source = c;
|
|
final SpellAbility change = new Ability(source, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
if (AllZoneUtil.isCardInPlay(source)) {
|
|
Singletons.getModel().getGameAction().moveToHand(source);
|
|
}
|
|
}
|
|
};
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append(source).append(" - At the beginning of your end step, return CARDNAME to its owner's hand.");
|
|
change.setStackDescription(sb.toString());
|
|
change.setDescription(sb.toString());
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(change);
|
|
|
|
}
|
|
|
|
}
|
|
Player activePlayer = Singletons.getModel().getGameState().getPhaseHandler().getPlayerTurn();
|
|
if (activePlayer.hasKeyword("At the beginning of the end step, you lose the game.")) {
|
|
final Card source = new Card();
|
|
final SpellAbility change = new Ability(source, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
this.getActivatingPlayer().loseConditionMet(GameLossReason.SpellEffect, "");
|
|
}
|
|
};
|
|
change.setStackDescription("At the beginning of the end step, you lose the game.");
|
|
change.setDescription("At the beginning of the end step, you lose the game.");
|
|
change.setActivatingPlayer(activePlayer);
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(change);
|
|
}
|
|
|
|
this.execute(this.getAt());
|
|
|
|
} // executeAt()
|
|
|
|
private static void endOfTurnWallOfReverence() {
|
|
final Player player = Singletons.getModel().getGameState().getPhaseHandler().getPlayerTurn();
|
|
final CardList list = player.getCardsIn(ZoneType.Battlefield, "Wall of Reverence");
|
|
|
|
Ability ability;
|
|
for (int i = 0; i < list.size(); i++) {
|
|
final Card card = list.get(i);
|
|
ability = new Ability(list.get(i), "0") {
|
|
@Override
|
|
public void resolve() {
|
|
CardList creats = AllZoneUtil.getCreaturesInPlay(player);
|
|
creats = creats.getTargetableCards(this);
|
|
if (creats.size() == 0) {
|
|
return;
|
|
}
|
|
|
|
if (player.isHuman()) {
|
|
final Object o = GuiUtils.chooseOneOrNone(
|
|
"Select target creature for Wall of Reverence life gain", creats.toArray());
|
|
if (o != null) {
|
|
final Card c = (Card) o;
|
|
final int power = c.getNetAttack();
|
|
player.gainLife(power, card);
|
|
}
|
|
} else { // computer
|
|
CardListUtil.sortAttack(creats);
|
|
final Card c = creats.get(0);
|
|
if (c != null) {
|
|
final int power = c.getNetAttack();
|
|
player.gainLife(power, card);
|
|
}
|
|
}
|
|
} // resolve
|
|
}; // ability
|
|
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append(card).append(" - ").append(player).append(" gains life equal to target creature's power.");
|
|
ability.setStackDescription(sb.toString());
|
|
ability.setDescription(sb.toString());
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(ability);
|
|
|
|
}
|
|
} // endOfTurnWallOfReverence()
|
|
|
|
private static void endOfTurnLighthouseChronologist() {
|
|
final Player player = Singletons.getModel().getGameState().getPhaseHandler().getPlayerTurn();
|
|
final Player opponent = player.getOpponent();
|
|
CardList list = opponent.getCardsIn(ZoneType.Battlefield);
|
|
|
|
list = list.filter(new CardListFilter() {
|
|
@Override
|
|
public boolean addCard(final Card c) {
|
|
return c.getName().equals("Lighthouse Chronologist") && (c.getCounters(Counters.LEVEL) >= 7);
|
|
}
|
|
});
|
|
|
|
Ability ability;
|
|
for (int i = 0; i < list.size(); i++) {
|
|
final Card card = list.get(i);
|
|
ability = new Ability(list.get(i), "0") {
|
|
@Override
|
|
public void resolve() {
|
|
Singletons.getModel().getGameState().getPhaseHandler().addExtraTurn(card.getController());
|
|
}
|
|
};
|
|
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append(card).append(" - ").append(card.getController()).append(" takes an extra turn.");
|
|
ability.setStackDescription(sb.toString());
|
|
ability.setDescription(sb.toString());
|
|
|
|
AllZone.getStack().addSimultaneousStackEntry(ability);
|
|
|
|
}
|
|
}
|
|
|
|
private static void removeAttackedBlockedThisTurn() {
|
|
// resets the status of attacked/blocked this turn
|
|
final CardList list = AllZoneUtil.getCreaturesInPlay();
|
|
|
|
for (int i = 0; i < list.size(); i++) {
|
|
final Card c = list.get(i);
|
|
c.getDamageHistory().setCreatureAttackedThisCombat(false);
|
|
c.getDamageHistory().setCreatureBlockedThisCombat(false);
|
|
c.getDamageHistory().setCreatureGotBlockedThisCombat(false);
|
|
}
|
|
}
|
|
|
|
} // end class EndOfTurn
|