mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
2302 lines
91 KiB
Java
2302 lines
91 KiB
Java
package forge;
|
|
|
|
|
|
import forge.Constant.Zone;
|
|
import forge.card.abilityFactory.AbilityFactory;
|
|
import forge.card.abilityFactory.AbilityFactory_Attach;
|
|
import forge.card.abilityFactory.AbilityFactory_Charm;
|
|
import forge.card.cardFactory.CardFactoryInterface;
|
|
import forge.card.cardFactory.CardFactoryUtil;
|
|
import forge.card.cost.Cost;
|
|
import forge.card.cost.Cost_Payment;
|
|
import forge.card.mana.ManaCost;
|
|
import forge.card.mana.ManaPool;
|
|
import forge.card.spellability.Ability;
|
|
import forge.card.spellability.Ability_Static;
|
|
import forge.card.spellability.SpellAbility;
|
|
import forge.card.spellability.SpellAbility_Requirements;
|
|
import forge.card.spellability.Target;
|
|
import forge.card.spellability.Target_Selection;
|
|
import forge.card.staticAbility.StaticAbility;
|
|
import forge.card.trigger.Trigger;
|
|
import forge.deck.Deck;
|
|
import forge.game.GameEndReason;
|
|
import forge.game.GameSummary;
|
|
import forge.game.GameType;
|
|
import forge.gui.GuiUtils;
|
|
import forge.gui.input.Input_Mulligan;
|
|
import forge.gui.input.Input_PayManaCost;
|
|
import forge.gui.input.Input_PayManaCost_Ability;
|
|
import forge.item.CardPrinted;
|
|
import forge.properties.ForgeProps;
|
|
import forge.properties.NewConstants.LANG.GameAction.GAMEACTION_TEXT;
|
|
import forge.quest.gui.QuestWinLoseHandler;
|
|
import forge.quest.gui.main.QuestChallenge;
|
|
import forge.quest.gui.main.QuestEvent;
|
|
import forge.view.swing.WinLoseFrame;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.Map.Entry;
|
|
import java.util.Random;
|
|
|
|
import javax.swing.JFrame;
|
|
import javax.swing.JOptionPane;
|
|
|
|
/**
|
|
* <p>GameAction class.</p>
|
|
*
|
|
* @author Forge
|
|
* @version $Id$
|
|
*/
|
|
public class GameAction {
|
|
|
|
/** This variable prevents WinLose dialog from popping several times, ie on each state effect check after a win.*/
|
|
private boolean canShowWinLose = true;
|
|
|
|
/**
|
|
* <p>resetActivationsPerTurn.</p>
|
|
*/
|
|
public final void resetActivationsPerTurn() {
|
|
CardList all = AllZoneUtil.getCardsInGame();
|
|
|
|
// Reset Activations per Turn
|
|
for (Card card : all) {
|
|
for (SpellAbility sa : card.getSpellAbility()) {
|
|
sa.getRestrictions().resetTurnActivations();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>changeZone.</p>
|
|
*
|
|
* @param prev a {@link forge.PlayerZone} object.
|
|
* @param zone a {@link forge.PlayerZone} object.
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public static Card changeZone(final PlayerZone prev, final PlayerZone zone, final Card c) {
|
|
if (prev == null && !c.isToken()) {
|
|
zone.add(c);
|
|
return c;
|
|
}
|
|
|
|
boolean suppress;
|
|
if (prev == null && !c.isToken()) {
|
|
suppress = true;
|
|
} else if (c.isToken()) {
|
|
suppress = false;
|
|
} else {
|
|
suppress = prev.equals(zone);
|
|
}
|
|
|
|
Card copied = null;
|
|
Card lastKnownInfo = null;
|
|
|
|
// Don't copy Tokens, Cards staying in same zone, or cards entering Battlefield
|
|
if (c.isToken() || suppress || zone.is(Constant.Zone.Battlefield)) {
|
|
lastKnownInfo = c;
|
|
copied = c;
|
|
} else {
|
|
copied = AllZone.getCardFactory().copyCard(c);
|
|
lastKnownInfo = CardUtil.getLKICopy(c);
|
|
|
|
// TODO improve choices here
|
|
// Certain attributes need to be copied from Hand->Stack and Stack->Battlefield
|
|
// these probably can be moved back to SubtractCounters
|
|
if (c.wasSuspendCast()) {
|
|
copied = addSuspendTriggers(c);
|
|
}
|
|
copied.setUnearthed(c.isUnearthed()); // this might be unnecessary
|
|
}
|
|
|
|
for (Trigger trigger : c.getTriggers()) {
|
|
trigger.setHostCard(copied);
|
|
}
|
|
|
|
if (suppress) {
|
|
AllZone.getTriggerHandler().suppressMode("ChangesZone");
|
|
}
|
|
|
|
zone.add(copied);
|
|
|
|
//Tokens outside the battlefield disappear immideately.
|
|
if (copied.isToken() && !zone.is(Constant.Zone.Battlefield)) {
|
|
zone.remove(copied);
|
|
}
|
|
|
|
HashMap<String, Object> runParams = new HashMap<String, Object>();
|
|
runParams.put("Card", lastKnownInfo);
|
|
if (prev != null) {
|
|
runParams.put("Origin", prev.getZoneType().name());
|
|
} else {
|
|
runParams.put("Origin", null);
|
|
}
|
|
runParams.put("Destination", zone.getZoneType().name());
|
|
AllZone.getTriggerHandler().runTrigger("ChangesZone", runParams);
|
|
//AllZone.getStack().chooseOrderOfSimultaneousStackEntryAll();
|
|
|
|
if (suppress) {
|
|
AllZone.getTriggerHandler().clearSuppression("ChangesZone");
|
|
}
|
|
|
|
if (prev != null) {
|
|
if (prev.is(Constant.Zone.Battlefield) && c.isCreature()) {
|
|
AllZone.getCombat().removeFromCombat(c);
|
|
}
|
|
|
|
prev.remove(c);
|
|
}
|
|
|
|
/*
|
|
if (!(c.isToken() || suppress || zone.is(Constant.Zone.Battlefield)) && !zone.is(Constant.Zone.Battlefield))
|
|
copied = AllZone.getCardFactory().copyCard(copied);
|
|
*/
|
|
//remove all counters from the card if destination is not the battlefield
|
|
//UNLESS we're dealing with Skullbriar, the Walking Grave
|
|
if (!zone.is(Constant.Zone.Battlefield) && !(c.getName().equals("Skullbriar, the Walking Grave")
|
|
&& !zone.is(Constant.Zone.Hand) && !zone.is(Constant.Zone.Library)))
|
|
{
|
|
copied.clearCounters();
|
|
}
|
|
|
|
copied.setTimestamp(AllZone.getNextTimestamp());
|
|
|
|
return copied;
|
|
}
|
|
|
|
/**
|
|
* <p>moveTo.</p>
|
|
*
|
|
* @param zone a {@link forge.PlayerZone} object.
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveTo(final PlayerZone zone, Card c) {
|
|
// Ideally move to should never be called without a prevZone
|
|
// Remove card from Current Zone, if it has one
|
|
PlayerZone prev = AllZone.getZoneOf(c);
|
|
//String prevName = prev != null ? prev.getZoneName() : "";
|
|
|
|
if (c.hasKeyword("If CARDNAME would leave the battlefield, exile it instead of putting it anywhere else.")
|
|
&& !zone.is(Constant.Zone.Exile))
|
|
{
|
|
PlayerZone removed = c.getOwner().getZone(Constant.Zone.Exile);
|
|
c.removeExtrinsicKeyword("If CARDNAME would leave the battlefield, exile it instead of putting it anywhere else.");
|
|
return moveTo(removed, c);
|
|
}
|
|
|
|
//Card lastKnownInfo = c;
|
|
|
|
c = changeZone(prev, zone, c);
|
|
|
|
if (c.isAura() && zone.is(Constant.Zone.Battlefield) && (prev == null || !prev.is(Constant.Zone.Stack))) {
|
|
// TODO Need a way to override this for Abilities that put Auras into play attached to things
|
|
AbilityFactory_Attach.attachAuraOnIndirectEnterBattlefield(c);
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* <p>moveToPlayFromHand.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveToPlayFromHand(Card c) {
|
|
//handles the case for Clone, etc where prev was null
|
|
|
|
PlayerZone hand = c.getOwner().getZone(Constant.Zone.Hand);
|
|
PlayerZone play = c.getController().getZone(Constant.Zone.Battlefield);
|
|
|
|
c = changeZone(hand, play, c);
|
|
|
|
return c;
|
|
}
|
|
|
|
/*
|
|
public void changeController(CardList list, Player oldController, Player newController) {
|
|
if (oldController.equals(newController))
|
|
return;
|
|
|
|
// Consolidating this code for now. In the future I want moveTo to handle this garbage
|
|
PlayerZone oldBattlefield = oldController.getZone(Constant.Zone.Battlefield);
|
|
PlayerZone newBattlefield = newController.getZone(Constant.Zone.Battlefield);
|
|
|
|
AllZone.getTriggerHandler().suppressMode("ChangesZone");
|
|
((PlayerZone_ComesIntoPlay) AllZone.getHumanPlayer().getZone(Zone.Battlefield)).setTriggers(false);
|
|
((PlayerZone_ComesIntoPlay) AllZone.getComputerPlayer().getZone(Zone.Battlefield)).setTriggers(false);
|
|
//so "enters the battlefield" abilities don't trigger
|
|
|
|
for (Card c : list) {
|
|
int turnInZone = c.getTurnInZone();
|
|
oldBattlefield.remove(c);
|
|
c.setController(newController);
|
|
newBattlefield.add(c);
|
|
//set summoning sickness
|
|
c.setSickness(true);
|
|
c.setTurnInZone(turnInZone); // The number of turns in the zone should not change
|
|
if (c.isCreature())
|
|
AllZone.getCombat().removeFromCombat(c);
|
|
}
|
|
|
|
AllZone.getTriggerHandler().clearSuppression("ChangesZone");
|
|
((PlayerZone_ComesIntoPlay) AllZone.getHumanPlayer().getZone(Zone.Battlefield)).setTriggers(true);
|
|
((PlayerZone_ComesIntoPlay) AllZone.getComputerPlayer().getZone(Zone.Battlefield)).setTriggers(true);
|
|
}*/
|
|
|
|
/**
|
|
*
|
|
* @param c a Card object
|
|
*/
|
|
public final void controllerChangeZoneCorrection(final Card c) {
|
|
System.out.println("Correcting zone for " + c.toString());
|
|
PlayerZone oldBattlefield = AllZone.getZoneOf(c);
|
|
PlayerZone newBattlefield = c.getController().getZone(oldBattlefield.getZoneType());
|
|
|
|
if (oldBattlefield == null || newBattlefield == null) {
|
|
return;
|
|
}
|
|
|
|
AllZone.getTriggerHandler().suppressMode("ChangesZone");
|
|
((PlayerZoneComesIntoPlay) AllZone.getHumanPlayer().getZone(Zone.Battlefield)).setTriggers(false);
|
|
((PlayerZoneComesIntoPlay) AllZone.getComputerPlayer().getZone(Zone.Battlefield)).setTriggers(false);
|
|
|
|
int tiz = c.getTurnInZone();
|
|
|
|
oldBattlefield.remove(c);
|
|
newBattlefield.add(c);
|
|
|
|
c.setTurnInZone(tiz);
|
|
|
|
AllZone.getTriggerHandler().clearSuppression("ChangesZone");
|
|
((PlayerZoneComesIntoPlay) AllZone.getHumanPlayer().getZone(Zone.Battlefield)).setTriggers(true);
|
|
((PlayerZoneComesIntoPlay) AllZone.getComputerPlayer().getZone(Zone.Battlefield)).setTriggers(true);
|
|
}
|
|
|
|
/**
|
|
* <p>moveToStack.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveToStack(final Card c) {
|
|
PlayerZone stack = AllZone.getStackZone();
|
|
return moveTo(stack, c);
|
|
}
|
|
|
|
/**
|
|
* <p>moveToGraveyard.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveToGraveyard(Card c) {
|
|
final PlayerZone origZone = AllZone.getZoneOf(c);
|
|
final PlayerZone grave = c.getOwner().getZone(Constant.Zone.Graveyard);
|
|
|
|
if (AllZoneUtil.isCardInPlay("Leyline of the Void", c.getOwner().getOpponent())) {
|
|
return moveTo(c.getOwner().getZone(Constant.Zone.Exile), c);
|
|
}
|
|
|
|
if (c.getName().equals("Nissa's Chosen") && origZone.is(Constant.Zone.Battlefield)) {
|
|
return moveToLibrary(c, -1);
|
|
}
|
|
|
|
if (c.hasKeyword("If CARDNAME would be put into a graveyard this turn, exile it instead.")) {
|
|
return moveTo(c.getOwner().getZone(Constant.Zone.Exile), c);
|
|
}
|
|
|
|
if (c.hasKeyword("If CARDNAME is put into a graveyard this turn, its controller gets a poison counter.")) {
|
|
c.getController().addPoisonCounters(1);
|
|
}
|
|
|
|
//must put card in OWNER's graveyard not controller's
|
|
c = moveTo(grave, c);
|
|
|
|
//Recover keyword
|
|
if (c.isCreature() && origZone.is(Constant.Zone.Battlefield)) {
|
|
for (final Card recoverable : c.getOwner().getCardsIn(Zone.Graveyard)) {
|
|
if (recoverable.hasStartOfKeyword("Recover")) {
|
|
SpellAbility abRecover = new Ability(recoverable, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
AllZone.getGameAction().moveToHand(recoverable);
|
|
}
|
|
|
|
@Override
|
|
public String getStackDescription() {
|
|
StringBuilder sd = new StringBuilder(recoverable.getName());
|
|
sd.append(" - Recover.");
|
|
|
|
return sd.toString();
|
|
}
|
|
};
|
|
|
|
Command notPaid = new Command() {
|
|
private static final long serialVersionUID = 5812397026869965462L;
|
|
|
|
public void execute() {
|
|
AllZone.getGameAction().exile(recoverable);
|
|
}
|
|
};
|
|
|
|
abRecover.setCancelCommand(notPaid);
|
|
abRecover.setTrigger(true);
|
|
|
|
String recoverCost = recoverable.getKeyword().get(recoverable.getKeywordPosition("Recover")).split(":")[1];
|
|
Cost abCost = new Cost(recoverCost, recoverable.getName(), false);
|
|
abRecover.setPayCosts(abCost);
|
|
|
|
StringBuilder question = new StringBuilder("Recover ");
|
|
question.append(recoverable.getName());
|
|
question.append("(");
|
|
question.append(recoverable.getUniqueNumber());
|
|
question.append(")");
|
|
question.append("?");
|
|
|
|
boolean shouldRecoverForAI = false;
|
|
boolean shouldRecoverForHuman = false;
|
|
|
|
if (c.getOwner().isHuman()) {
|
|
shouldRecoverForHuman = GameActionUtil.showYesNoDialog(recoverable, question.toString());
|
|
} else if (c.getOwner().isComputer()) {
|
|
shouldRecoverForAI = ComputerUtil.canPayCost(abRecover);
|
|
}
|
|
|
|
if (shouldRecoverForHuman) {
|
|
AllZone.getStack().addSimultaneousStackEntry(abRecover);
|
|
//AllZone.getGameAction().playSpellAbility(abRecover);
|
|
} else if (shouldRecoverForAI) {
|
|
AllZone.getStack().addSimultaneousStackEntry(abRecover);
|
|
//ComputerUtil.playStack(abRecover);
|
|
}
|
|
|
|
if (!grave.hasChanged()) {
|
|
//If the controller declined Recovery or didn't pay the cost, exile the recoverable
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* <p>moveToHand.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveToHand(final Card c) {
|
|
PlayerZone hand = c.getOwner().getZone(Constant.Zone.Hand);
|
|
return moveTo(hand, c);
|
|
}
|
|
|
|
/**
|
|
* <p>moveToPlay.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveToPlay(final Card c) {
|
|
PlayerZone play = c.getOwner().getZone(Constant.Zone.Battlefield);
|
|
return moveTo(play, c);
|
|
}
|
|
|
|
/**
|
|
* <p>moveToPlay.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @param p a {@link forge.Player} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveToPlay(final Card c, final Player p) {
|
|
// move to a specific player's Battlefield
|
|
PlayerZone play = p.getZone(Constant.Zone.Battlefield);
|
|
return moveTo(play, c);
|
|
}
|
|
|
|
/**
|
|
* <p>moveToBottomOfLibrary.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveToBottomOfLibrary(final Card c) {
|
|
return moveToLibrary(c, -1);
|
|
}
|
|
|
|
/**
|
|
* <p>moveToLibrary.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveToLibrary(final Card c) {
|
|
return moveToLibrary(c, 0);
|
|
}
|
|
|
|
/**
|
|
* <p>moveToLibrary.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @param libPosition a int.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveToLibrary(Card c, int libPosition) {
|
|
PlayerZone p = AllZone.getZoneOf(c);
|
|
PlayerZone library = c.getOwner().getZone(Constant.Zone.Library);
|
|
|
|
if (c.hasKeyword("If CARDNAME would leave the battlefield, exile it instead of putting it anywhere else.")) {
|
|
PlayerZone removed = c.getOwner().getZone(Constant.Zone.Exile);
|
|
c.removeExtrinsicKeyword("If CARDNAME would leave the battlefield, exile it instead of putting it anywhere else.");
|
|
return moveTo(removed, c);
|
|
}
|
|
|
|
if (p != null) {
|
|
p.remove(c);
|
|
}
|
|
|
|
|
|
if (c.isToken()) {
|
|
return c;
|
|
}
|
|
|
|
if (p != null && p.is(Constant.Zone.Battlefield)) {
|
|
c = AllZone.getCardFactory().copyCard(c);
|
|
}
|
|
|
|
c.clearCounters(); //remove all counters
|
|
|
|
if (libPosition == -1 || libPosition > library.size()) {
|
|
libPosition = library.size();
|
|
}
|
|
|
|
library.add(c, libPosition);
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* <p>exile.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card exile(final Card c) {
|
|
if (AllZoneUtil.isCardExiled(c)) {
|
|
return c;
|
|
}
|
|
|
|
PlayerZone removed = c.getOwner().getZone(Constant.Zone.Exile);
|
|
|
|
return AllZone.getGameAction().moveTo(removed, c);
|
|
}
|
|
|
|
/**
|
|
* <p>moveTo.</p>
|
|
*
|
|
* @param name a {@link java.lang.String} object.
|
|
* @param c a {@link forge.Card} object.
|
|
* @param libPosition a int.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card moveTo(final Zone name, final Card c, final int libPosition) {
|
|
// Call specific functions to set PlayerZone, then move onto moveTo
|
|
if (name.equals(Constant.Zone.Hand)) {
|
|
return moveToHand(c);
|
|
} else if (name.equals(Constant.Zone.Library)) {
|
|
return moveToLibrary(c, libPosition);
|
|
} else if (name.equals(Constant.Zone.Battlefield)) {
|
|
return moveToPlay(c);
|
|
} else if (name.equals(Constant.Zone.Graveyard)) {
|
|
return moveToGraveyard(c);
|
|
} else if (name.equals(Constant.Zone.Exile)) {
|
|
return exile(c);
|
|
} else {
|
|
return moveToStack(c);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>discard_PutIntoPlayInstead.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
*/
|
|
public void discard_PutIntoPlayInstead(Card c) {
|
|
moveToPlay(c);
|
|
|
|
if (c.getName().equals("Dodecapod")) {
|
|
c.setCounter(Counters.P1P1, 2, false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>discard_madness.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
*/
|
|
public final void discard_madness(Card c) {
|
|
// Whenever a card with madness is discarded, you may cast it for it's madness cost
|
|
if (!c.hasMadness()) {
|
|
return;
|
|
}
|
|
|
|
final Card madness = c;
|
|
final Ability cast = new Ability(madness, madness.getMadnessCost()) {
|
|
@Override
|
|
public void resolve() {
|
|
playCardNoCost(madness);
|
|
System.out.println("Madness cost paid");
|
|
}
|
|
};
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(madness.getName()).append(" - Cast via Madness");
|
|
cast.setStackDescription(sb.toString());
|
|
|
|
final Ability activate = new Ability(madness, "0") {
|
|
@Override
|
|
public void resolve() {
|
|
// pay madness cost here.
|
|
if (madness.getOwner().isHuman()) {
|
|
if (GameActionUtil.showYesNoDialog(madness, madness + " - Discarded. Pay Madness Cost?")) {
|
|
if (cast.getManaCost().equals("0")) {
|
|
AllZone.getStack().add(cast);
|
|
} else {
|
|
AllZone.getInputControl().setInput(new Input_PayManaCost(cast));
|
|
}
|
|
}
|
|
} else {
|
|
// computer will ALWAYS pay a madness cost if he has the mana.
|
|
ComputerUtil.playStack(cast);
|
|
}
|
|
}
|
|
};
|
|
|
|
StringBuilder sbAct = new StringBuilder();
|
|
sbAct.append(madness.getName()).append(" - Discarded. Pay Madness Cost?");
|
|
activate.setStackDescription(sbAct.toString());
|
|
|
|
AllZone.getStack().add(activate);
|
|
}
|
|
|
|
/**
|
|
* <p>checkEndGameSate.</p>
|
|
*
|
|
* @return a boolean.
|
|
*/
|
|
public final boolean checkEndGameSate() {
|
|
// Win / Lose
|
|
GameSummary game = AllZone.getGameInfo();
|
|
boolean humanWins = false;
|
|
boolean computerWins = false;
|
|
Player computer = AllZone.getComputerPlayer();
|
|
Player human = AllZone.getHumanPlayer();
|
|
|
|
if (human.hasWon() || computer.hasLost()) { // Winning Conditions can be worth more than losing conditions
|
|
// Human wins
|
|
humanWins = true;
|
|
|
|
if (human.getAltWin()) {
|
|
game.end(GameEndReason.WinsGameSpellEffect, human.getName(), human.getWinConditionSource());
|
|
} else {
|
|
game.end(GameEndReason.AllOpponentsLost, human.getName(), null);
|
|
}
|
|
}
|
|
|
|
|
|
if (computer.hasWon() || human.hasLost()) {
|
|
if (humanWins) {
|
|
// both players won/lost at the same time.
|
|
game.end(GameEndReason.Draw, null, null);
|
|
} else {
|
|
computerWins = true;
|
|
|
|
if (computer.getAltWin()) {
|
|
game.end(GameEndReason.WinsGameSpellEffect, computer.getName(), computer.getWinConditionSource());
|
|
} else {
|
|
game.end(GameEndReason.AllOpponentsLost, computer.getName(), null);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
boolean isGameDone = humanWins || computerWins;
|
|
if (isGameDone) {
|
|
game.getPlayerRating(computer.getName()).setLossReason(computer.getLossState(), computer.getLossConditionSource());
|
|
game.getPlayerRating(human.getName()).setLossReason(human.getLossState(), human.getLossConditionSource());
|
|
AllZone.getMatchState().addGamePlayed(game);
|
|
}
|
|
|
|
return isGameDone;
|
|
}
|
|
|
|
/**
|
|
* <p>checkStateEffects.</p>
|
|
*/
|
|
public final void checkStateEffects() {
|
|
checkStateEffects(false);
|
|
}
|
|
|
|
/**
|
|
* <p>checkStateEffects.</p>
|
|
*
|
|
* @param force a boolean. States wether or not state effect checking should be forced, even if a spell is in the middle of resolving.
|
|
*/
|
|
public final void checkStateEffects(boolean force) {
|
|
|
|
// sol(10/29) added for Phase updates, state effects shouldn't be checked during Spell Resolution (except when persist-returning
|
|
if (AllZone.getStack().getResolving() && !force) {
|
|
return;
|
|
}
|
|
|
|
boolean refreeze = AllZone.getStack().isFrozen();
|
|
AllZone.getStack().setFrozen(true);
|
|
|
|
JFrame frame = (JFrame) AllZone.getDisplay();
|
|
if (!frame.isDisplayable()) {
|
|
return;
|
|
}
|
|
|
|
if (canShowWinLose && checkEndGameSate()) {
|
|
AllZone.getDisplay().savePrefs();
|
|
frame.setEnabled(false);
|
|
//frame.dispose();
|
|
|
|
//Gui_WinLose gwl = new Gui_WinLose(AllZone.getMatchState(), AllZone.getQuestData(), AllZone.getQuestChallenge());
|
|
|
|
// New WinLoseFrame below. Old Gui_WinLose above.
|
|
// Old code should still work if any problems with new. Doublestrike 02-10-11
|
|
WinLoseFrame gwl;
|
|
|
|
if(AllZone.getQuestData() != null) {
|
|
gwl = new WinLoseFrame(new QuestWinLoseHandler());
|
|
}
|
|
else {
|
|
gwl = new WinLoseFrame();
|
|
}
|
|
|
|
//gwl.setAlwaysOnTop(true);
|
|
gwl.toFront();
|
|
canShowWinLose = false;
|
|
return;
|
|
}
|
|
|
|
|
|
//do this twice, sometimes creatures/permanents will survive when they shouldn't
|
|
for (int q = 0; q < 9; q++) {
|
|
|
|
boolean checkAgain = false;
|
|
|
|
//remove old effects
|
|
AllZone.getStaticEffects().clearStaticEffects();
|
|
|
|
//search for cards with static abilities
|
|
CardList allCards = AllZoneUtil.getCardsInGame();
|
|
CardList cardsWithStAbs = new CardList();
|
|
for (Card card : allCards) {
|
|
ArrayList<StaticAbility> staticAbilities = card.getStaticAbilities();
|
|
if (!staticAbilities.isEmpty() && !card.isFaceDown()) {
|
|
cardsWithStAbs.add(card);
|
|
}
|
|
}
|
|
|
|
cardsWithStAbs.reverse(); //roughly timestamp order
|
|
|
|
//apply continuous effects
|
|
for (int layer = 4; layer < 11; layer++) {
|
|
for (Card card : cardsWithStAbs) {
|
|
ArrayList<StaticAbility> staticAbilities = card.getStaticAbilities();
|
|
for (StaticAbility stAb : staticAbilities) {
|
|
if (stAb.getLayer() == layer) {
|
|
stAb.applyAbility("Continuous");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HashMap<String, Object> runParams = new HashMap<String, Object>();
|
|
AllZone.getTriggerHandler().runTrigger("Always", runParams);
|
|
|
|
//card state effects like Glorious Anthem
|
|
for (String effect : AllZone.getStaticEffects().getStateBasedMap().keySet()) {
|
|
Command com = GameActionUtil.commands.get(effect);
|
|
com.execute();
|
|
}
|
|
|
|
CardList list = AllZoneUtil.getCardsIn(Zone.Battlefield);
|
|
Card c;
|
|
|
|
Iterator<Card> it = list.iterator();
|
|
|
|
while (it.hasNext()) {
|
|
c = it.next();
|
|
|
|
if (c.isEquipped()) {
|
|
for (Card equipment : c.getEquippedBy()) {
|
|
if (!AllZoneUtil.isCardInPlay(equipment)) {
|
|
equipment.unEquipCard(c);
|
|
checkAgain = true;
|
|
}
|
|
}
|
|
} //if isEquipped()
|
|
|
|
if (c.isEquipping()) {
|
|
Card equippedCreature = c.getEquipping().get(0);
|
|
if (!AllZoneUtil.isCardInPlay(equippedCreature)) {
|
|
c.unEquipCard(equippedCreature);
|
|
checkAgain = true;
|
|
}
|
|
|
|
//make sure any equipment that has become a creature stops equipping
|
|
if (c.isCreature()) {
|
|
c.unEquipCard(equippedCreature);
|
|
checkAgain = true;
|
|
}
|
|
} //if isEquipping()
|
|
|
|
if (c.isAura()) {
|
|
// Check if Card Aura is attached to is a legal target
|
|
GameEntity entity = c.getEnchanting();
|
|
SpellAbility sa = c.getSpellPermanent();
|
|
Target tgt = null;
|
|
if (sa != null) {
|
|
tgt = sa.getTarget();
|
|
}
|
|
|
|
if (entity instanceof Card){
|
|
Card perm = (Card)entity;
|
|
// I think the Keyword checks might be superfluous with the isValid check
|
|
if (!AllZoneUtil.isCardInPlay(perm)
|
|
|| CardFactoryUtil.hasProtectionFrom(c, perm)
|
|
|| ((c.hasKeyword("Enchant creature") || c.hasKeyword("Enchant tapped creature"))
|
|
&& !perm.isCreature())
|
|
|| (c.hasKeyword("Enchant tapped creature") && perm.isUntapped())
|
|
|| (tgt != null && !perm.isValid(tgt.getValidTgts(), c.getController(), c))){
|
|
c.unEnchantEntity(perm);
|
|
moveToGraveyard(c);
|
|
checkAgain = true;
|
|
}
|
|
}
|
|
else{
|
|
Player pl = (Player)entity;
|
|
boolean invalid = false;
|
|
|
|
if (tgt.canOnlyTgtOpponent() && !c.getController().getOpponent().isPlayer(pl)){
|
|
invalid = true;
|
|
}
|
|
else{
|
|
// TODO: Check Player Protection once it's added.
|
|
}
|
|
if (invalid){
|
|
c.unEnchantEntity(pl);
|
|
moveToGraveyard(c);
|
|
checkAgain = true;
|
|
}
|
|
}
|
|
|
|
} //if isAura
|
|
|
|
if (c.isCreature()) {
|
|
if (c.getNetDefense() <= c.getDamage() && !c.hasKeyword("Indestructible")) {
|
|
destroy(c);
|
|
//this is untested with instants and abilities but required for First Strike combat phase
|
|
AllZone.getCombat().removeFromCombat(c);
|
|
checkAgain = true;
|
|
} else if (c.getNetDefense() <= 0) {
|
|
// TODO This shouldn't be a destroy, and should happen before the damage check probably
|
|
destroy(c);
|
|
AllZone.getCombat().removeFromCombat(c);
|
|
checkAgain = true;
|
|
}
|
|
}
|
|
|
|
} //while it.hasNext()
|
|
|
|
if (!checkAgain) {
|
|
break; //do not continue the loop
|
|
}
|
|
|
|
} //for q=0;q<2
|
|
|
|
destroyLegendaryCreatures();
|
|
destroyPlaneswalkers();
|
|
|
|
GameActionUtil.stLandManaAbilities.execute();
|
|
|
|
if (!refreeze) {
|
|
AllZone.getStack().unfreezeStack();
|
|
}
|
|
} //checkStateEffects()
|
|
|
|
|
|
/**
|
|
* <p>destroyPlaneswalkers.</p>
|
|
*/
|
|
private void destroyPlaneswalkers() {
|
|
//get all Planeswalkers
|
|
CardList list = AllZoneUtil.getCardsIn(Zone.Battlefield).getType("Planeswalker");
|
|
|
|
Card c;
|
|
for (int i = 0; i < list.size(); i++) {
|
|
c = list.get(i);
|
|
|
|
if (c.getCounters(Counters.LOYALTY) <= 0) {
|
|
AllZone.getGameAction().moveToGraveyard(c);
|
|
}
|
|
|
|
ArrayList<String> types = c.getType();
|
|
for (String type : types) {
|
|
if(!CardUtil.isAPlaneswalkerType(type))
|
|
continue;
|
|
|
|
CardList cl = list.getType(type);
|
|
|
|
if (cl.size() > 1) {
|
|
for (Card crd : cl) {
|
|
AllZone.getGameAction().moveToGraveyard(crd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>destroyLegendaryCreatures.</p>
|
|
*/
|
|
private void destroyLegendaryCreatures() {
|
|
CardList a = AllZoneUtil.getCardsIn(Zone.Battlefield).getType("Legendary");
|
|
|
|
while (!a.isEmpty() && !AllZoneUtil.isCardInPlay("Mirror Gallery")) {
|
|
CardList b = AllZoneUtil.getCardsIn(Zone.Battlefield, a.get(0).getName());
|
|
b = b.getType("Legendary");
|
|
b = b.filter(new CardListFilter() {
|
|
public boolean addCard(final Card c) {
|
|
return !c.isFaceDown();
|
|
}
|
|
});
|
|
a.remove(0);
|
|
if (1 < b.size()) {
|
|
for (int i = 0; i < b.size(); i++) {
|
|
AllZone.getGameAction().sacrificeDestroy(b.get(i));
|
|
}
|
|
}
|
|
}
|
|
} //destroyLegendaryCreatures()
|
|
|
|
/**
|
|
* <p>sacrifice.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a boolean.
|
|
*/
|
|
public final boolean sacrifice(final Card c) {
|
|
if (c.getName().equals("Mana Pool")) {
|
|
System.out.println("Trying to sacrifice mana pool...");
|
|
return false;
|
|
}
|
|
sacrificeDestroy(c);
|
|
|
|
//Run triggers
|
|
HashMap<String, Object> runParams = new HashMap<String, Object>();
|
|
runParams.put("Card", c);
|
|
AllZone.getTriggerHandler().runTrigger("Sacrificed", runParams);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* <p>destroyNoRegeneration.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a boolean.
|
|
*/
|
|
public final boolean destroyNoRegeneration(final Card c) {
|
|
if (!AllZoneUtil.isCardInPlay(c) || c.hasKeyword("Indestructible")) {
|
|
return false;
|
|
}
|
|
|
|
if (c.isEnchanted()) {
|
|
CardList list = new CardList(c.getEnchantedBy().toArray());
|
|
list = list.filter(new CardListFilter() {
|
|
public boolean addCard(final Card crd) {
|
|
return crd.hasKeyword("Totem armor");
|
|
}
|
|
});
|
|
CardListUtil.sortCMC(list);
|
|
|
|
if (list.size() != 0) {
|
|
final Card crd;
|
|
if (list.size() == 1) {
|
|
crd = list.get(0);
|
|
} else {
|
|
if (c.getController().isHuman()) {
|
|
crd = GuiUtils.getChoiceOptional("Select totem armor to destroy", list.toArray());
|
|
} else {
|
|
crd = list.get(0);
|
|
}
|
|
}
|
|
|
|
final Card card = c;
|
|
Ability_Static ability = new Ability_Static(crd, "0") {
|
|
public void resolve() {
|
|
destroy(crd);
|
|
card.setDamage(0);
|
|
|
|
}
|
|
};
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(crd).append(" - Totem armor: destroy this aura.");
|
|
ability.setStackDescription(sb.toString());
|
|
|
|
AllZone.getStack().add(ability);
|
|
return false;
|
|
}
|
|
} //totem armor
|
|
|
|
return sacrificeDestroy(c);
|
|
}
|
|
|
|
/**
|
|
* <p>addSuspendTriggers.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public static Card addSuspendTriggers(final Card c) {
|
|
c.setSVar("HasteFromSuspend", "True");
|
|
|
|
Command intoPlay = new Command() {
|
|
private static final long serialVersionUID = -4514610171270596654L;
|
|
|
|
public void execute() {
|
|
if (AllZoneUtil.isCardInPlay(c) && c.isCreature()) {
|
|
c.addExtrinsicKeyword("Haste");
|
|
}
|
|
} //execute()
|
|
};
|
|
|
|
c.addComesIntoPlayCommand(intoPlay);
|
|
|
|
Command loseControl = new Command() {
|
|
private static final long serialVersionUID = -4514610171270596654L;
|
|
|
|
public void execute() {
|
|
if (c.getSVar("HasteFromSuspend").equals("True")) {
|
|
c.setSVar("HasteFromSuspend", "False");
|
|
c.removeExtrinsicKeyword("Haste");
|
|
}
|
|
} //execute()
|
|
};
|
|
|
|
c.addChangeControllerCommand(loseControl);
|
|
c.addLeavesPlayCommand(loseControl);
|
|
return c;
|
|
}
|
|
|
|
/**
|
|
* <p>sacrificeDestroy.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a boolean.
|
|
*/
|
|
public final boolean sacrificeDestroy(final Card c) {
|
|
if (!AllZoneUtil.isCardInPlay(c)) {
|
|
return false;
|
|
}
|
|
|
|
Player owner = c.getOwner();
|
|
if (!(owner.isComputer() || owner.isHuman())) {
|
|
throw new RuntimeException("GameAction : destroy() invalid card.getOwner() - " + c + " " + owner);
|
|
}
|
|
|
|
boolean persist = (c.hasKeyword("Persist") && c.getCounters(Counters.M1M1) == 0) && !c.isToken();
|
|
|
|
Card newCard = moveToGraveyard(c);
|
|
|
|
// Destroy needs to be called with Last Known Information
|
|
c.destroy();
|
|
|
|
//System.out.println("Card " + c.getName() + " is getting sent to GY, and this turn it got damaged by: ");
|
|
for (Card crd : c.getReceivedDamageFromThisTurn().keySet()) {
|
|
if (c.getReceivedDamageFromThisTurn().get(crd) > 0) {
|
|
//System.out.println(crd.getName() );
|
|
GameActionUtil.executeVampiricEffects(crd);
|
|
}
|
|
}
|
|
|
|
if (persist) {
|
|
final Card persistCard = newCard;
|
|
Ability persistAb = new Ability(persistCard, "0") {
|
|
|
|
@Override
|
|
public void resolve() {
|
|
if (AllZone.getZoneOf(persistCard).is(Constant.Zone.Graveyard)) {
|
|
PlayerZone ownerPlay = persistCard.getOwner().getZone(Constant.Zone.Battlefield);
|
|
Card card = moveTo(ownerPlay, persistCard);
|
|
AllZone.getGameAction().checkStateEffects(true);
|
|
card.addCounter(Counters.M1M1, 1);
|
|
}
|
|
}
|
|
};
|
|
persistAb.setStackDescription(newCard.getName() + " - Returning from Persist");
|
|
AllZone.getStack().add(persistAb);
|
|
}
|
|
return true;
|
|
} //sacrificeDestroy()
|
|
|
|
|
|
/**
|
|
* <p>destroy.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a boolean.
|
|
*/
|
|
public final boolean destroy(final Card c) {
|
|
if (!AllZoneUtil.isCardInPlay(c)
|
|
|| (c.hasKeyword("Indestructible")
|
|
&& (!c.isCreature() || c.getNetDefense() > 0)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (c.canBeShielded() && c.getShield() > 0) {
|
|
c.subtractShield();
|
|
c.setDamage(0);
|
|
c.tap();
|
|
AllZone.getCombat().removeFromCombat(c);
|
|
return false;
|
|
}
|
|
|
|
if (c.isEnchanted()) {
|
|
CardList list = new CardList(c.getEnchantedBy().toArray());
|
|
list = list.filter(new CardListFilter() {
|
|
public boolean addCard(final Card crd) {
|
|
return crd.hasKeyword("Totem armor");
|
|
}
|
|
});
|
|
CardListUtil.sortCMC(list);
|
|
|
|
|
|
if (list.size() != 0) {
|
|
final Card crd;
|
|
if (list.size() == 1) {
|
|
crd = list.get(0);
|
|
} else {
|
|
if (c.getController().isHuman()) {
|
|
crd = GuiUtils.getChoiceOptional("Select totem armor to destroy", list.toArray());
|
|
} else {
|
|
crd = list.get(0);
|
|
}
|
|
}
|
|
|
|
c.setDamage(0);
|
|
destroy(crd);
|
|
System.out.println("Totem armor destroyed instead of original card");
|
|
return false;
|
|
}
|
|
} //totem armor
|
|
|
|
return sacrificeDestroy(c);
|
|
}
|
|
|
|
/**
|
|
* <p>newGame.</p>
|
|
* for Quest fantasy mode
|
|
*
|
|
* @param humanDeck a {@link forge.deck.Deck} object.
|
|
* @param computerDeck a {@link forge.deck.Deck} object.
|
|
* @param human a {@link forge.CardList} object.
|
|
* @param humanLife a int.
|
|
* @param computerLife a int.
|
|
* @param qa a {@link forge.Quest_Assignment} object.
|
|
* @param computer a {@link forge.CardList} object.
|
|
*/
|
|
public final void newGame(final Deck humanDeck, final Deck computerDeck, final CardList human,
|
|
final CardList computer, final int humanLife, final int computerLife, final QuestEvent qe)
|
|
{
|
|
this.newGame(humanDeck, computerDeck);
|
|
|
|
AllZone.getComputerPlayer().setLife(computerLife, null);
|
|
AllZone.getHumanPlayer().setLife(humanLife, null);
|
|
|
|
if (qe != null && qe instanceof QuestChallenge){
|
|
QuestChallenge challenge = (QuestChallenge)qe;
|
|
if (challenge.getEventType().equals("challenge")) {
|
|
computer.addAll(forge.quest.data.QuestUtil.getComputerStartingCards(AllZone.getQuestData(), AllZone.getQuestEvent()));
|
|
}
|
|
}
|
|
|
|
for (Card c : human) {
|
|
for (Trigger trig : c.getTriggers()) {
|
|
AllZone.getTriggerHandler().registerTrigger(trig);
|
|
}
|
|
|
|
AllZone.getHumanPlayer().getZone(Zone.Battlefield).add(c);
|
|
c.setSickness(true);
|
|
}
|
|
|
|
for (Card c : computer) {
|
|
for (Trigger trig : c.getTriggers()) {
|
|
AllZone.getTriggerHandler().registerTrigger(trig);
|
|
}
|
|
|
|
AllZone.getComputerPlayer().getZone(Zone.Battlefield).add(c);
|
|
c.setSickness(true);
|
|
}
|
|
Constant.Quest.fantasyQuest[0] = true;
|
|
}
|
|
|
|
private boolean Start_Cut = false;
|
|
|
|
/**
|
|
* <p>newGame.</p>
|
|
*
|
|
* @param humanDeck a {@link forge.deck.Deck} object.
|
|
* @param computerDeck a {@link forge.deck.Deck} object.
|
|
*/
|
|
public final void newGame(final Deck humanDeck, final Deck computerDeck) {
|
|
//AllZone.getComputer() = new ComputerAI_Input(new ComputerAI_General());
|
|
Constant.Quest.fantasyQuest[0] = false;
|
|
|
|
AllZone.newGameCleanup();
|
|
canShowWinLose = true;
|
|
forge.card.trigger.Trigger.resetIDs();
|
|
AllZone.getTriggerHandler().clearTriggerSettings();
|
|
|
|
{ //re-number cards just so their unique numbers are low, just for user friendliness
|
|
CardFactoryInterface c = AllZone.getCardFactory();
|
|
|
|
Card.resetUniqueNumber();
|
|
|
|
boolean canRandomFoil = Constant.Runtime.RndCFoil[0] && Constant.Runtime.gameType.equals(GameType.Constructed);
|
|
|
|
Random generator = MyRandom.random;
|
|
for (Entry<CardPrinted, Integer> stackOfCards : humanDeck.getMain()) {
|
|
CardPrinted cardPrinted = stackOfCards.getKey();
|
|
for (int i = 0; i < stackOfCards.getValue(); i++) {
|
|
|
|
Card card = c.getCard(cardPrinted.getName(), AllZone.getHumanPlayer());
|
|
card.setCurSetCode(cardPrinted.getSet());
|
|
|
|
int cntVariants = cardPrinted.getCard().getSetInfo(cardPrinted.getSet()).getCopiesCount();
|
|
if (cntVariants > 1) { card.setRandomPicture(generator.nextInt(cntVariants - 1) + 1); }
|
|
|
|
card.setImageFilename(CardUtil.buildFilename(card));
|
|
|
|
// Assign random foiling on approximately 1:20 cards
|
|
if (cardPrinted.isFoil() || (canRandomFoil && MyRandom.percentTrue(5))) {
|
|
int iFoil = MyRandom.random.nextInt(9) + 1;
|
|
card.setFoil(iFoil);
|
|
}
|
|
|
|
AllZone.getHumanPlayer().getZone(Zone.Library).add(card);
|
|
|
|
for (Trigger trig : card.getTriggers()) {
|
|
AllZone.getTriggerHandler().registerTrigger(trig);
|
|
}
|
|
}
|
|
}
|
|
|
|
ArrayList<String> RAICards = new ArrayList<String>();
|
|
for (Entry<CardPrinted, Integer> stackOfCards : computerDeck.getMain()) {
|
|
CardPrinted cardPrinted = stackOfCards.getKey();
|
|
for (int i = 0; i < stackOfCards.getValue(); i++) {
|
|
|
|
Card card = c.getCard(cardPrinted.getName(), AllZone.getComputerPlayer());
|
|
card.setCurSetCode(cardPrinted.getSet());
|
|
|
|
int cntVariants = cardPrinted.getCard().getSetInfo(cardPrinted.getSet()).getCopiesCount();
|
|
if (cntVariants > 1) { card.setRandomPicture(generator.nextInt(cntVariants - 1) + 1); }
|
|
|
|
card.setImageFilename(CardUtil.buildFilename(card));
|
|
|
|
// Assign random foiling on approximately 1:20 cards
|
|
if (cardPrinted.isFoil() || (canRandomFoil && MyRandom.percentTrue(5))) {
|
|
int iFoil = MyRandom.random.nextInt(9) + 1;
|
|
card.setFoil(iFoil);
|
|
}
|
|
|
|
AllZone.getComputerPlayer().getZone(Zone.Library).add(card);
|
|
|
|
for (Trigger trig : card.getTriggers()) {
|
|
AllZone.getTriggerHandler().registerTrigger(trig);
|
|
}
|
|
|
|
if (card.getSVar("RemAIDeck").equals("True")) {
|
|
RAICards.add(card.getName());
|
|
//get card picture so that it is in the image cache
|
|
// ImageCache.getImage(card);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (RAICards.size() > 0) {
|
|
StringBuilder sb = new StringBuilder("AI deck contains the following cards that it can't play or may be buggy:\n");
|
|
for (int i = 0; i < RAICards.size(); i++) {
|
|
sb.append(RAICards.get(i));
|
|
if (((i % 4) == 0) && (i > 0)) {
|
|
sb.append("\n");
|
|
} else if (i != (RAICards.size() - 1)) {
|
|
sb.append(", ");
|
|
}
|
|
}
|
|
|
|
JOptionPane.showMessageDialog(null, sb.toString(), "", JOptionPane.INFORMATION_MESSAGE);
|
|
|
|
}
|
|
} //end re-numbering
|
|
|
|
for (int i = 0; i < 100; i++) {
|
|
AllZone.getHumanPlayer().shuffle();
|
|
}
|
|
|
|
//do this instead of shuffling Computer's deck
|
|
boolean smoothLand = Constant.Runtime.Smooth[0];
|
|
|
|
if (smoothLand) {
|
|
Card[] c = smoothComputerManaCurve(AllZone.getComputerPlayer().getCardsIn(Zone.Library).toArray());
|
|
AllZone.getComputerPlayer().getZone(Zone.Library).setCards(c);
|
|
} else {
|
|
// WTF? (it was so before refactor)
|
|
AllZone.getComputerPlayer().getZone(Zone.Library).setCards(AllZone.getComputerPlayer().getCardsIn(Zone.Library).toArray());
|
|
AllZone.getComputerPlayer().shuffle();
|
|
}
|
|
|
|
// Only cut/coin toss if it's the first game of the match
|
|
if (AllZone.getMatchState().getGamesPlayedCount() == 0) {
|
|
// New code to determine who goes first. Delete this if it doesn't work properly
|
|
if (isStartCut()) {
|
|
seeWhoPlaysFirst();
|
|
} else {
|
|
seeWhoPlaysFirst_CoinToss();
|
|
}
|
|
} else if (AllZone.getMatchState().hasWonLastGame(AllZone.getHumanPlayer().getName())) {
|
|
// if player won last, AI starts
|
|
computerStartsGame();
|
|
}
|
|
|
|
for (int i = 0; i < 7; i++) {
|
|
AllZone.getHumanPlayer().drawCard();
|
|
AllZone.getComputerPlayer().drawCard();
|
|
}
|
|
|
|
// TODO ManaPool should be moved to Player and be represented in the player panel
|
|
ManaPool mp = AllZone.getHumanPlayer().getManaPool();
|
|
mp.setImageFilename("mana_pool");
|
|
AllZone.getHumanPlayer().getZone(Zone.Battlefield).add(mp);
|
|
|
|
AllZone.getInputControl().setInput(new Input_Mulligan());
|
|
Phase.setGameBegins(1);
|
|
} //newGame()
|
|
|
|
//this is where the computer cheats
|
|
//changes AllZone.getComputerPlayer().getZone(Zone.Library)
|
|
|
|
/**
|
|
* <p>smoothComputerManaCurve.</p>
|
|
*
|
|
* @param in an array of {@link forge.Card} objects.
|
|
* @return an array of {@link forge.Card} objects.
|
|
*/
|
|
final Card[] smoothComputerManaCurve(final Card[] in) {
|
|
CardList library = new CardList(in);
|
|
library.shuffle();
|
|
|
|
//remove all land, keep non-basicland in there, shuffled
|
|
CardList land = library.getType("Land");
|
|
for (int i = 0; i < land.size(); i++) {
|
|
if (land.get(i).isLand()) {
|
|
library.remove(land.get(i));
|
|
}
|
|
}
|
|
|
|
//non-basic lands are removed, because the computer doesn't seem to
|
|
//effectively use them very well
|
|
land = threadLand(land);
|
|
|
|
try {
|
|
//mana weave, total of 7 land
|
|
// The Following have all been reduced by 1, to account for the computer starting first.
|
|
library.add(6, land.get(0));
|
|
library.add(7, land.get(1));
|
|
library.add(8, land.get(2));
|
|
library.add(9, land.get(3));
|
|
library.add(10, land.get(4));
|
|
|
|
library.add(12, land.get(5));
|
|
library.add(15, land.get(6));
|
|
} catch (IndexOutOfBoundsException e) {
|
|
System.err.println("Error: cannot smooth mana curve, not enough land");
|
|
return in;
|
|
}
|
|
|
|
//add the rest of land to the end of the deck
|
|
for (int i = 0; i < land.size(); i++) {
|
|
if (!library.contains(land.get(i))) {
|
|
library.add(land.get(i));
|
|
}
|
|
}
|
|
|
|
|
|
//check
|
|
for (int i = 0; i < library.size(); i++) {
|
|
System.out.println(library.get(i));
|
|
}
|
|
|
|
|
|
return library.toArray();
|
|
} //smoothComputerManaCurve()
|
|
|
|
//non-basic lands are removed, because the computer doesn't seem to
|
|
//effectively used them very well
|
|
|
|
/**
|
|
* <p>threadLand.</p>
|
|
*
|
|
* @param in a {@link forge.CardList} object.
|
|
* @return a {@link forge.CardList} object.
|
|
*/
|
|
public final CardList threadLand(final CardList in) {
|
|
//String[] basicLand = {"Forest", "Swamp", "Mountain", "Island", "Plains"}; //unused
|
|
|
|
//Thread stuff with as large a spread of colors as possible:
|
|
String[] allLand = {
|
|
"Bayou", "Volcanic Island", "Savannah", "Badlands", "Tundra", "Taiga", "Underground Sea",
|
|
"Plateau", "Tropical Island", "Scrubland", "Overgrown Tomb", "Steam Vents", "Temple Garden",
|
|
"Blood Crypt", "Hallowed Fountain", "Stomping Ground", "Watery Grave", "Sacred Foundry",
|
|
"Breeding Pool", "Godless Shrine", "Pendelhaven", "Flagstones of Trokair", "Forest", "Swamp",
|
|
"Mountain", "Island", "Plains", "Tree of Tales", "Vault of Whispers", "Great Furnace",
|
|
"Seat of the Synod", "Ancient Den", "Treetop Village", "Ghitu Encampment", "Faerie Conclave",
|
|
"Forbidding Watchtower", "Savage Lands", "Arcane Sanctum", "Jungle Shrine",
|
|
"Crumbling Necropolis", "Seaside Citadel", "Elfhame Palace", "Coastal Tower", "Salt Marsh",
|
|
"Kher Keep", "Library of Alexandria", "Dryad Arbor"};
|
|
|
|
|
|
ArrayList<CardList> land = new ArrayList<CardList>();
|
|
|
|
//get different CardList of all Forest, Swamps, etc...
|
|
CardList check;
|
|
for (int i = 0; i < allLand.length; i++) {
|
|
check = in.getName(allLand[i]);
|
|
|
|
if (!check.isEmpty()) {
|
|
land.add(check);
|
|
}
|
|
}
|
|
/*
|
|
//get non-basic land CardList
|
|
check = in.filter(new CardListFilter()
|
|
{
|
|
public boolean addCard(Card c)
|
|
{
|
|
return c.isLand() && !c.isBasicLand();
|
|
}
|
|
});
|
|
if(! check.isEmpty())
|
|
land.add(check);
|
|
*/
|
|
|
|
//thread all separate CardList's of land together to get something like
|
|
//Mountain, Plains, Island, Mountain, Plains, Island
|
|
CardList out = new CardList();
|
|
|
|
int i = 0;
|
|
while (!land.isEmpty()) {
|
|
i = (i + 1) % land.size();
|
|
|
|
check = land.get(i);
|
|
if (check.isEmpty()) {
|
|
//System.out.println("removed");
|
|
land.remove(i);
|
|
i--;
|
|
continue;
|
|
}
|
|
|
|
out.add(check.get(0));
|
|
check.remove(0);
|
|
} //while
|
|
|
|
return out;
|
|
} //threadLand()
|
|
|
|
|
|
/**
|
|
* <p>getDifferentLand.</p>
|
|
*
|
|
* @param list a {@link forge.CardList} object.
|
|
* @param land a {@link java.lang.String} object.
|
|
* @return a int.
|
|
*/
|
|
@SuppressWarnings("unused")
|
|
// getDifferentLand
|
|
private int getDifferentLand(final CardList list, final String land) {
|
|
int out = 0;
|
|
|
|
return out;
|
|
}
|
|
|
|
//decides who goes first when starting another game, used by newGame()
|
|
|
|
/**
|
|
* <p>seeWhoPlaysFirst_CoinToss.</p>
|
|
*/
|
|
public void seeWhoPlaysFirst_CoinToss() {
|
|
Object[] possibleValues = {ForgeProps.getLocalized(GAMEACTION_TEXT.HEADS), ForgeProps.getLocalized(GAMEACTION_TEXT.TAILS)};
|
|
Object q = JOptionPane.showOptionDialog(null, ForgeProps.getLocalized(GAMEACTION_TEXT.HEADS_OR_TAILS), ForgeProps.getLocalized(GAMEACTION_TEXT.COIN_TOSS),
|
|
JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
|
|
null, possibleValues, possibleValues[0]);
|
|
|
|
int Flip = MyRandom.random.nextInt(2);
|
|
String Human_Flip = " ";
|
|
String Computer_Flip = " ";
|
|
// JOptionPane.showMessageDialog(null, q, "", JOptionPane.INFORMATION_MESSAGE);
|
|
if (q.equals(0)) {
|
|
Human_Flip = ForgeProps.getLocalized(GAMEACTION_TEXT.HEADS);
|
|
Computer_Flip = ForgeProps.getLocalized(GAMEACTION_TEXT.TAILS);
|
|
} else {
|
|
Human_Flip = ForgeProps.getLocalized(GAMEACTION_TEXT.TAILS);
|
|
Computer_Flip = ForgeProps.getLocalized(GAMEACTION_TEXT.HEADS);
|
|
}
|
|
|
|
if ((Flip == 0 && q.equals(0)) || (Flip == 1 && q.equals(1)))
|
|
JOptionPane.showMessageDialog(null, Human_Flip + "\r\n" + ForgeProps.getLocalized(GAMEACTION_TEXT.HUMAN_WIN), "", JOptionPane.INFORMATION_MESSAGE);
|
|
else {
|
|
computerStartsGame();
|
|
JOptionPane.showMessageDialog(null, Computer_Flip + "\r\n" + ForgeProps.getLocalized(GAMEACTION_TEXT.COMPUTER_WIN), "", JOptionPane.INFORMATION_MESSAGE);
|
|
}
|
|
}//seeWhoPlaysFirst_CoinToss()
|
|
|
|
private Card HumanCut = null;
|
|
private Card ComputerCut = null;
|
|
|
|
/**
|
|
* <p>seeWhoPlaysFirst.</p>
|
|
*/
|
|
public final void seeWhoPlaysFirst() {
|
|
|
|
CardList HLibrary = AllZone.getHumanPlayer().getCardsIn(Zone.Library);
|
|
HLibrary = HLibrary.filter(CardListFilter.nonlands);
|
|
CardList CLibrary = AllZone.getComputerPlayer().getCardsIn(Zone.Library);
|
|
CLibrary = CLibrary.filter(CardListFilter.nonlands);
|
|
|
|
boolean Starter_Determined = false;
|
|
int Cut_Count = 0;
|
|
int Cut_CountMax = 20;
|
|
for (int i = 0; i < Cut_CountMax; i++) {
|
|
if (Starter_Determined == true) {
|
|
break;
|
|
}
|
|
|
|
if (HLibrary.size() > 0) {
|
|
setHumanCut(HLibrary.get(MyRandom.random.nextInt(HLibrary.size())));
|
|
} else {
|
|
computerStartsGame();
|
|
JOptionPane.showMessageDialog(null, ForgeProps.getLocalized(GAMEACTION_TEXT.HUMAN_MANA_COST) + "\r\n" + ForgeProps.getLocalized(GAMEACTION_TEXT.COMPUTER_STARTS), "", JOptionPane.INFORMATION_MESSAGE);
|
|
return;
|
|
}
|
|
|
|
if (CLibrary.size() > 0) {
|
|
setComputerCut(CLibrary.get(MyRandom.random.nextInt(CLibrary.size())));
|
|
} else {
|
|
JOptionPane.showMessageDialog(null, ForgeProps.getLocalized(GAMEACTION_TEXT.COMPUTER_MANA_COST) + "\r\n" + ForgeProps.getLocalized(GAMEACTION_TEXT.HUMAN_STARTS), "", JOptionPane.INFORMATION_MESSAGE);
|
|
return;
|
|
}
|
|
|
|
Cut_Count = Cut_Count + 1;
|
|
AllZone.getGameAction().moveTo(AllZone.getHumanPlayer().getZone(Constant.Zone.Library), AllZone.getGameAction().getHumanCut());
|
|
AllZone.getGameAction().moveTo(AllZone.getComputerPlayer().getZone(Constant.Zone.Library), AllZone.getGameAction().getComputerCut());
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(ForgeProps.getLocalized(GAMEACTION_TEXT.HUMAN_CUT) + getHumanCut().getName() + " (" + getHumanCut().getManaCost() + ")" + "\r\n");
|
|
sb.append(ForgeProps.getLocalized(GAMEACTION_TEXT.COMPUTER_CUT) + getComputerCut().getName() + " (" + getComputerCut().getManaCost() + ")" + "\r\n");
|
|
sb.append("\r\n" + "Number of times the deck has been cut: " + Cut_Count + "\r\n");
|
|
if (CardUtil.getConvertedManaCost(getComputerCut().getManaCost()) > CardUtil.getConvertedManaCost(getHumanCut().getManaCost())) {
|
|
computerStartsGame();
|
|
JOptionPane.showMessageDialog(null, sb + ForgeProps.getLocalized(GAMEACTION_TEXT.COMPUTER_STARTS), "", JOptionPane.INFORMATION_MESSAGE);
|
|
return;
|
|
} else if (CardUtil.getConvertedManaCost(getComputerCut().getManaCost()) < CardUtil.getConvertedManaCost(getHumanCut().getManaCost())) {
|
|
JOptionPane.showMessageDialog(null, sb + ForgeProps.getLocalized(GAMEACTION_TEXT.HUMAN_STARTS), "", JOptionPane.INFORMATION_MESSAGE);
|
|
return;
|
|
} else {
|
|
sb.append(ForgeProps.getLocalized(GAMEACTION_TEXT.EQUAL_CONVERTED_MANA) + "\r\n");
|
|
if (i == Cut_CountMax - 1) {
|
|
sb.append(ForgeProps.getLocalized(GAMEACTION_TEXT.RESOLVE_STARTER));
|
|
if (MyRandom.random.nextInt(2) == 1) {
|
|
JOptionPane.showMessageDialog(null, sb + ForgeProps.getLocalized(GAMEACTION_TEXT.HUMAN_WIN), "", JOptionPane.INFORMATION_MESSAGE);
|
|
} else {
|
|
computerStartsGame();
|
|
JOptionPane.showMessageDialog(null, sb + ForgeProps.getLocalized(GAMEACTION_TEXT.COMPUTER_WIN), "", JOptionPane.INFORMATION_MESSAGE);
|
|
}
|
|
return;
|
|
} else {
|
|
sb.append(ForgeProps.getLocalized(GAMEACTION_TEXT.CUTTING_AGAIN));
|
|
}
|
|
JOptionPane.showMessageDialog(null, sb, "", JOptionPane.INFORMATION_MESSAGE);
|
|
}
|
|
} // for-loop for multiple card cutting
|
|
|
|
|
|
} //seeWhoPlaysFirst()
|
|
|
|
/**
|
|
* <p>computerStartsGame.</p>
|
|
*/
|
|
public final void computerStartsGame() {
|
|
Player computer = AllZone.getComputerPlayer();
|
|
AllZone.getPhase().setPlayerTurn(computer);
|
|
AllZone.getGameInfo().setPlayerWhoGotFirstTurn(computer.getName());
|
|
}
|
|
|
|
//if Card had the type "Aura" this method would always return true, since local enchantments are always attached to something
|
|
//if Card is "Equipment", returns true if attached to something
|
|
|
|
/**
|
|
* <p>isAttachee.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a boolean.
|
|
*/
|
|
public final boolean isAttacheeByMindsDesire(final Card c) {
|
|
CardList list = AllZoneUtil.getCardsIn(Zone.Battlefield);
|
|
|
|
for (int i = 0; i < list.size(); i++) {
|
|
Card [] cc = list.getCard(i).getAttachedCardsByMindsDesire();
|
|
if (Arrays.binarySearch(cc, c) >= 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} //isAttached(Card c)
|
|
|
|
/**
|
|
* <p>playCard.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
* @return a boolean.
|
|
*/
|
|
public final boolean playCard(final Card c) {
|
|
// this can only be called by the Human
|
|
HashMap<String, SpellAbility> map = new HashMap<String, SpellAbility>();
|
|
SpellAbility[] abilities = canPlaySpellAbility(c.getSpellAbility());
|
|
ArrayList<String> choices = new ArrayList<String>();
|
|
Player human = AllZone.getHumanPlayer();
|
|
|
|
if (c.isLand() && human.canPlayLand()) {
|
|
PlayerZone zone = AllZone.getZoneOf(c);
|
|
|
|
if (zone.is(Zone.Hand) || (!zone.is(Zone.Battlefield)) && c.hasKeyword("May be played")) {
|
|
choices.add("Play land");
|
|
}
|
|
}
|
|
|
|
for (SpellAbility sa : abilities) {
|
|
// for uncastables like lotus bloom, check if manaCost is blank
|
|
sa.setActivatingPlayer(human);
|
|
if (sa.canPlay() && (!sa.isSpell() || !sa.getManaCost().equals(""))) {
|
|
choices.add(sa.toString());
|
|
map.put(sa.toString(), sa);
|
|
}
|
|
}
|
|
|
|
String choice;
|
|
if (choices.size() == 0) {
|
|
return false;
|
|
} else if (choices.size() == 1) {
|
|
choice = choices.get(0);
|
|
} else {
|
|
choice = (String) GuiUtils.getChoiceOptional("Choose", choices.toArray());
|
|
}
|
|
|
|
if (choice == null) {
|
|
return false;
|
|
}
|
|
|
|
if (choice.equals("Play land")) {
|
|
AllZone.getHumanPlayer().playLand(c);
|
|
return true;
|
|
}
|
|
|
|
SpellAbility ability = map.get(choice);
|
|
if (ability != null) {
|
|
playSpellAbility(ability);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* <p>playCardNoCost.</p>
|
|
*
|
|
* @param c a {@link forge.Card} object.
|
|
*/
|
|
public final void playCardNoCost(final Card c) {
|
|
//SpellAbility[] choices = (SpellAbility[]) c.getSpells().toArray();
|
|
ArrayList<SpellAbility> choices = c.getBasicSpells();
|
|
SpellAbility sa;
|
|
|
|
//TODO add Buyback, Kicker, ... , spells here
|
|
/*
|
|
ArrayList<SpellAbility> additional = c.getAdditionalCostSpells();
|
|
for (SpellAbility s : additional)
|
|
{
|
|
|
|
}
|
|
*/
|
|
/*
|
|
System.out.println(choices.length);
|
|
for(int i = 0; i < choices.length; i++)
|
|
System.out.println(choices[i]);
|
|
*/
|
|
if (choices.size() == 0) {
|
|
return;
|
|
} else if (choices.size() == 1) {
|
|
sa = choices.get(0);
|
|
} else {
|
|
sa = (SpellAbility) GuiUtils.getChoiceOptional("Choose", choices.toArray());
|
|
}
|
|
|
|
if (sa == null) {
|
|
return;
|
|
}
|
|
|
|
// Ripple causes a crash because it doesn't set the activatingPlayer in this entrance
|
|
if (sa.getActivatingPlayer() == null) {
|
|
sa.setActivatingPlayer(AllZone.getHumanPlayer());
|
|
}
|
|
playSpellAbilityForFree(sa);
|
|
}
|
|
|
|
|
|
/**
|
|
* <p>playSpellAbilityForFree.</p>
|
|
*
|
|
* @param sa a {@link forge.card.spellability.SpellAbility} object.
|
|
*/
|
|
public final void playSpellAbilityForFree(final SpellAbility sa) {
|
|
if (sa.getPayCosts() != null) {
|
|
Target_Selection ts = new Target_Selection(sa.getTarget(), sa);
|
|
Cost_Payment payment = new Cost_Payment(sa.getPayCosts(), sa);
|
|
|
|
SpellAbility_Requirements req = new SpellAbility_Requirements(sa, ts, payment);
|
|
req.setFree(true);
|
|
req.fillRequirements();
|
|
} else if (sa.getBeforePayMana() == null) {
|
|
if (sa.isSpell()) {
|
|
Card c = sa.getSourceCard();
|
|
if (!c.isCopiedSpell()) {
|
|
AllZone.getGameAction().moveToStack(c);
|
|
}
|
|
}
|
|
boolean x = false;
|
|
if (sa.getSourceCard().getManaCost().contains("X")) {
|
|
x = true;
|
|
}
|
|
|
|
if (sa.isKickerAbility()) {
|
|
Command paid1 = new Command() {
|
|
private static final long serialVersionUID = -6531785460264284794L;
|
|
|
|
public void execute() {
|
|
AllZone.getStack().add(sa);
|
|
}
|
|
};
|
|
AllZone.getInputControl().setInput(new Input_PayManaCost_Ability(sa.getAdditionalManaCost(), paid1));
|
|
} else {
|
|
AllZone.getStack().add(sa, x);
|
|
}
|
|
} else {
|
|
sa.setManaCost("0"); // Beached As
|
|
if (sa.isKickerAbility()) {
|
|
sa.getBeforePayMana().setFree(false);
|
|
sa.setManaCost(sa.getAdditionalManaCost());
|
|
} else {
|
|
sa.getBeforePayMana().setFree(true);
|
|
}
|
|
AllZone.getInputControl().setInput(sa.getBeforePayMana());
|
|
}
|
|
}
|
|
|
|
int CostCutting_GetMultiMickerManaCostPaid = 0;
|
|
String CostCutting_GetMultiMickerManaCostPaid_Colored = "";
|
|
|
|
/**
|
|
* <p>getSpellCostChange.</p>
|
|
*
|
|
* @param sa a {@link forge.card.spellability.SpellAbility} object.
|
|
* @param originalCost a {@link forge.card.mana.ManaCost} object.
|
|
* @return a {@link forge.card.mana.ManaCost} object.
|
|
*/
|
|
public ManaCost getSpellCostChange(SpellAbility sa, ManaCost originalCost) {
|
|
// Beached
|
|
Card originalCard = sa.getSourceCard();
|
|
Player controller = originalCard.getController();
|
|
SpellAbility spell = sa;
|
|
String mana = originalCost.toString();
|
|
ManaCost manaCost = new ManaCost(mana);
|
|
if (sa.isXCost() && !originalCard.isCopiedSpell()) originalCard.setXManaCostPaid(0);
|
|
|
|
if (Phase.getGameBegins() != 1)
|
|
return manaCost;
|
|
|
|
if (spell.isSpell() == true) {
|
|
if (originalCard.getName().equals("Avatar of Woe")) {
|
|
Player player = AllZone.getPhase().getPlayerTurn();
|
|
Player opponent = player.getOpponent();
|
|
CardList PlayerCreatureList = player.getCardsIn(Zone.Graveyard);
|
|
PlayerCreatureList = PlayerCreatureList.getType("Creature");
|
|
CardList OpponentCreatureList = opponent.getCardsIn(Zone.Graveyard);
|
|
OpponentCreatureList = OpponentCreatureList.getType("Creature");
|
|
if ((PlayerCreatureList.size() + OpponentCreatureList.size()) >= 10) {
|
|
manaCost = new ManaCost("B B");
|
|
} // Avatar of Woe
|
|
} else if (originalCard.getName().equals("Avatar of Will")) {
|
|
Player opponent = AllZone.getPhase().getPlayerTurn().getOpponent();
|
|
CardList opponentHandList = opponent.getCardsIn(Zone.Hand);
|
|
if (opponentHandList.size() == 0) {
|
|
manaCost = new ManaCost("U U");
|
|
} // Avatar of Will
|
|
} else if (originalCard.getName().equals("Avatar of Fury")) {
|
|
Player opponent = AllZone.getPhase().getPlayerTurn().getOpponent();
|
|
CardList opponentLand = AllZoneUtil.getPlayerLandsInPlay(opponent);
|
|
if (opponentLand.size() >= 7) {
|
|
manaCost = new ManaCost("R R");
|
|
} // Avatar of Fury
|
|
} else if (originalCard.getName().equals("Avatar of Might")) {
|
|
Player player = AllZone.getPhase().getPlayerTurn();
|
|
Player opponent = player.getOpponent();
|
|
CardList playerCreature = AllZoneUtil.getCreaturesInPlay(player);
|
|
CardList opponentCreature = AllZoneUtil.getCreaturesInPlay(opponent);
|
|
if (opponentCreature.size() - playerCreature.size() >= 4) {
|
|
manaCost = new ManaCost("G G");
|
|
} // Avatar of Might
|
|
}
|
|
} // isSpell
|
|
|
|
// Get Cost Reduction
|
|
CardList Cards_In_Play = AllZoneUtil.getCardsIn(Zone.Battlefield);
|
|
Cards_In_Play = Cards_In_Play.filter(new CardListFilter() {
|
|
public boolean addCard(Card c) {
|
|
if (c.getKeyword().toString().contains("CostChange")) return true;
|
|
return false;
|
|
}
|
|
});
|
|
Cards_In_Play.add(originalCard);
|
|
CardList Player_Play = controller.getCardsIn(Zone.Battlefield);
|
|
CardList Player_Hand = controller.getCardsIn(Zone.Hand);
|
|
int XBonus = 0;
|
|
int Max = 25;
|
|
if (sa.isMultiKicker()) CostCutting_GetMultiMickerManaCostPaid_Colored = "";
|
|
|
|
if (mana.toString().length() == 0) mana = "0";
|
|
for (int i = 0; i < Cards_In_Play.size(); i++) {
|
|
Card card = Cards_In_Play.get(i);
|
|
ArrayList<String> a = card.getKeyword();
|
|
int CostKeywords = 0;
|
|
int CostKeyword_Number[] = new int[a.size()];
|
|
for (int x = 0; x < a.size(); x++)
|
|
if (a.get(x).toString().startsWith("CostChange")) {
|
|
CostKeyword_Number[CostKeywords] = x;
|
|
CostKeywords = CostKeywords + 1;
|
|
}
|
|
for (int CKeywords = 0; CKeywords < CostKeywords; CKeywords++) {
|
|
String parse = card.getKeyword().get(CostKeyword_Number[CKeywords]).toString();
|
|
String k[] = parse.split(":");
|
|
if (card.equals(originalCard)) {
|
|
if (!k[4].equals("Self")) k[2] = "Owned";
|
|
}
|
|
if (k[6].equals("ChosenType")) k[6] = card.getChosenType();
|
|
if (k[2].equals("More")) {
|
|
if (k[7].equals("OnlyOneBonus")) { // Only Works for Color and Type
|
|
for (int string_no = 5; string_no < 7; string_no++) {
|
|
String spilt = k[string_no];
|
|
String color_spilt[] = spilt.split("/");
|
|
|
|
for (int cs_num = 0; cs_num < color_spilt.length; cs_num++) {
|
|
k[string_no] = color_spilt[cs_num];
|
|
if (string_no == 5 && CardUtil.getColors(originalCard).contains(k[5])) break;
|
|
if (string_no == 6 && (originalCard.isType(k[6]))) break;
|
|
}
|
|
}
|
|
}
|
|
if (k[7].contains("All Conditions")) { // Only Works for Color and Type
|
|
for (int string_no = 5; string_no < 7; string_no++) {
|
|
String spilt = k[string_no];
|
|
String color_spilt[] = spilt.split("/");
|
|
for (int cs_num = 0; cs_num < color_spilt.length; cs_num++) {
|
|
k[string_no] = color_spilt[cs_num];
|
|
if (string_no == 5) {
|
|
if (CardUtil.getColors(originalCard).contains(k[5]) || k[5].equals("All")) {
|
|
} else {
|
|
k[5] = "Nullified";
|
|
break;
|
|
}
|
|
}
|
|
if (string_no == 6) {
|
|
if (originalCard.isType(k[6]) || k[6].equals("All")) {
|
|
} else {
|
|
k[6] = "Nullified";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!k[5].equals("Nullified")) k[5] = "All";
|
|
if (!k[6].equals("Nullified")) k[6] = "All";
|
|
}
|
|
if ((k[1].equals("Player") && card.getController().equals(controller)
|
|
|| (k[1].equals("Opponent") && card.getController().equals(controller.getOpponent())) || k[1].equals("All"))
|
|
&& ((k[4].equals("Spell") && sa.isSpell() == true) || (k[4].equals("Ability") && sa.isAbility() == true)
|
|
|| (k[4].startsWith("Ability_Cycling") && sa.isCycling()) || (k[4].equals("Self") && originalCard.equals(card))
|
|
|| (k[4].equals("Enchanted") && originalCard.getEnchantedBy().contains(card)) || k[4].equals("All"))
|
|
&& ((CardUtil.getColors(originalCard).contains(k[5])) || k[5].equals("All"))
|
|
&& ((originalCard.isType(k[6]))
|
|
|| (!(originalCard.isType(k[6])) && k[7].contains("NonType")) || k[6].equals("All"))) {
|
|
if (k[7].contains("CardIsTapped")) {
|
|
if (card.isTapped() == false) k[3] = "0";
|
|
}
|
|
if (k[7].contains("TargetInPlay")) {
|
|
if (!Player_Play.contains(originalCard)) k[3] = "0";
|
|
}
|
|
if (k[7].contains("TargetInHand")) {
|
|
if (!Player_Hand.contains(originalCard)) k[3] = "0";
|
|
}
|
|
if (k[7].contains("NonType")) {
|
|
if (originalCard.isType(k[6])) k[3] = "0";
|
|
}
|
|
if (k[7].contains("OpponentTurn")) {
|
|
if (AllZone.getPhase().isPlayerTurn(controller)) k[3] = "0";
|
|
}
|
|
if (k[7].contains("Affinity")) {
|
|
String spilt = k[7];
|
|
String color_spilt[] = spilt.split("/");
|
|
k[7] = color_spilt[1];
|
|
CardList PlayerList = controller.getCardsIn(Zone.Battlefield);
|
|
PlayerList = PlayerList.getType(k[7]);
|
|
k[3] = String.valueOf(PlayerList.size());
|
|
}
|
|
String[] Numbers = new String[Max];
|
|
if ("X".equals(k[3])) {
|
|
for (int no = 0; no < Max; no++) Numbers[no] = String.valueOf(no);
|
|
String Number_ManaCost = " ";
|
|
if (mana.toString().length() == 1) {
|
|
Number_ManaCost = mana.toString().substring(0, 1);
|
|
} else if (mana.toString().length() == 0) {
|
|
Number_ManaCost = "0"; // Should Never Occur
|
|
} else {
|
|
Number_ManaCost = mana.toString().substring(0, 2);
|
|
}
|
|
Number_ManaCost = Number_ManaCost.trim();
|
|
for (int check = 0; check < Max; check++) {
|
|
if (Number_ManaCost.equals(Numbers[check])) {
|
|
int xValue = CardFactoryUtil.xCount(card, card.getSVar("X"));
|
|
//if((spell.isXCost()) || (spell.isMultiKicker()) && (check - Integer.valueOf(k[3])) < 0) XBonus = XBonus - check + Integer.valueOf(k[3]);
|
|
mana = mana.replaceFirst(String.valueOf(check), String.valueOf(check + xValue));
|
|
}
|
|
if (mana.equals("")) mana = "0";
|
|
manaCost = new ManaCost(mana);
|
|
}
|
|
} else if (!"WUGRB".contains(k[3])) {
|
|
for (int no = 0; no < Max; no++) Numbers[no] = String.valueOf(no);
|
|
String Number_ManaCost = " ";
|
|
if (mana.toString().length() == 1) Number_ManaCost = mana.toString().substring(0, 1);
|
|
else if (mana.toString().length() == 0) Number_ManaCost = "0"; // Should Never Occur
|
|
else Number_ManaCost = mana.toString().substring(0, 2);
|
|
Number_ManaCost = Number_ManaCost.trim();
|
|
|
|
for (int check = 0; check < Max; check++) {
|
|
if (Number_ManaCost.equals(Numbers[check])) {
|
|
mana = mana.replaceFirst(String.valueOf(check), String.valueOf(check + Integer.valueOf(k[3])));
|
|
}
|
|
if (mana.equals("")) mana = "0";
|
|
manaCost = new ManaCost(mana);
|
|
}
|
|
if (!manaCost.toString().contains("0") && !manaCost.toString().contains("1") && !manaCost.toString().contains("2")
|
|
&& !manaCost.toString().contains("3") && !manaCost.toString().contains("4") && !manaCost.toString().contains("5")
|
|
&& !manaCost.toString().contains("6") && !manaCost.toString().contains("7") && !manaCost.toString().contains("8")
|
|
&& !manaCost.toString().contains("9")) {
|
|
mana = k[3] + " " + mana;
|
|
manaCost = new ManaCost(mana);
|
|
}
|
|
} else {
|
|
mana = mana + " " + k[3];
|
|
manaCost = new ManaCost(mana);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mana.equals("0") && spell.isAbility()) {
|
|
} else {
|
|
for (int i = 0; i < Cards_In_Play.size(); i++) {
|
|
Card card = Cards_In_Play.get(i);
|
|
ArrayList<String> a = card.getKeyword();
|
|
int CostKeywords = 0;
|
|
int CostKeyword_Number[] = new int[a.size()];
|
|
for (int x = 0; x < a.size(); x++)
|
|
if (a.get(x).toString().startsWith("CostChange")) {
|
|
CostKeyword_Number[CostKeywords] = x;
|
|
CostKeywords = CostKeywords + 1;
|
|
}
|
|
for (int CKeywords = 0; CKeywords < CostKeywords; CKeywords++) {
|
|
String parse = card.getKeyword().get(CostKeyword_Number[CKeywords]).toString();
|
|
String k[] = parse.split(":");
|
|
if (card.equals(originalCard)) {
|
|
if (!k[4].equals("Self")) k[2] = "Owned";
|
|
}
|
|
if (k[6].equals("ChosenType")) k[6] = card.getChosenType();
|
|
if (k[2].equals("Less")) {
|
|
if (k[7].equals("OnlyOneBonus")) { // Only Works for Color and Type
|
|
for (int string_no = 5; string_no < 7; string_no++) {
|
|
String spilt = k[string_no];
|
|
String color_spilt[] = spilt.split("/");
|
|
|
|
for (int cs_num = 0; cs_num < color_spilt.length; cs_num++) {
|
|
k[string_no] = color_spilt[cs_num];
|
|
if (string_no == 5 && CardUtil.getColors(originalCard).contains(k[5]))
|
|
break;
|
|
if (string_no == 6 && (originalCard.isType(k[6]))) break;
|
|
}
|
|
}
|
|
}
|
|
if (k[7].contains("All Conditions")) { // Only Works for Color and Type
|
|
for (int string_no = 5; string_no < 7; string_no++) {
|
|
String spilt = k[string_no];
|
|
String color_spilt[] = spilt.split("/");
|
|
for (int cs_num = 0; cs_num < color_spilt.length; cs_num++) {
|
|
k[string_no] = color_spilt[cs_num];
|
|
if (string_no == 5) {
|
|
if (CardUtil.getColors(originalCard).contains(k[5]) || k[5].equals("All")) {
|
|
} else {
|
|
k[5] = "Nullified";
|
|
break;
|
|
}
|
|
}
|
|
if (string_no == 6) {
|
|
if (originalCard.isType(k[6]) || k[6].equals("All")) {
|
|
} else {
|
|
k[6] = "Nullified";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!k[5].equals("Nullified")) k[5] = "All";
|
|
if (!k[6].equals("Nullified")) k[6] = "All";
|
|
}
|
|
if ((k[1].equals("Player") && card.getController().equals(controller)
|
|
|| (k[1].equals("Opponent") && card.getController().equals(controller.getOpponent())) || k[1].equals("All"))
|
|
&& ((k[4].equals("Spell") && sa.isSpell() == true) || (k[4].equals("Ability") && sa.isAbility() == true)
|
|
|| (k[4].startsWith("Ability_Cycling") && sa.isCycling()) || (k[4].equals("Self") && originalCard.equals(card))
|
|
|| (k[4].equals("Enchanted") && originalCard.getEnchantedBy().contains(card)) || k[4].equals("All"))
|
|
&& ((CardUtil.getColors(originalCard).contains(k[5])) || k[5].equals("All"))
|
|
&& ((originalCard.isType(k[6]))
|
|
|| (!(originalCard.isType(k[6])) && k[7].contains("NonType")) || k[6].equals("All"))) {
|
|
if (k[7].contains("CardIsTapped")) {
|
|
if (card.isTapped() == false) k[3] = "0";
|
|
}
|
|
if (k[7].contains("TargetInPlay")) {
|
|
if (!Player_Play.contains(originalCard)) k[3] = "0";
|
|
}
|
|
if (k[7].contains("TargetInHand")) {
|
|
if (!Player_Hand.contains(originalCard)) k[3] = "0";
|
|
}
|
|
if (k[7].contains("NonType")) {
|
|
if (originalCard.isType(k[6])) k[3] = "0";
|
|
}
|
|
if (k[7].contains("OpponentTurn")) {
|
|
if (AllZone.getPhase().isPlayerTurn(controller)) k[3] = "0";
|
|
}
|
|
if (k[7].contains("Affinity")) {
|
|
String spilt = k[7];
|
|
String color_spilt[] = spilt.split("/");
|
|
k[7] = color_spilt[1];
|
|
CardList PlayerList = controller.getCardsIn(Zone.Battlefield);
|
|
PlayerList = PlayerList.getType(k[7]);
|
|
k[3] = String.valueOf(PlayerList.size());
|
|
}
|
|
|
|
String[] Numbers = new String[Max];
|
|
if (!"WUGRB".contains(k[3])) {
|
|
|
|
int value = 0;
|
|
if ("X".equals(k[3]))
|
|
value = CardFactoryUtil.xCount(card, card.getSVar("X"));
|
|
else
|
|
value = Integer.valueOf(k[3]);
|
|
|
|
for (int no = 0; no < Max; no++) Numbers[no] = String.valueOf(no);
|
|
String Number_ManaCost = " ";
|
|
if (mana.toString().length() == 1)
|
|
Number_ManaCost = mana.toString().substring(0, 1);
|
|
else if (mana.toString().length() == 0)
|
|
Number_ManaCost = "0"; // Should Never Occur
|
|
else Number_ManaCost = mana.toString().substring(0, 2);
|
|
Number_ManaCost = Number_ManaCost.trim();
|
|
|
|
for (int check = 0; check < Max; check++) {
|
|
if (Number_ManaCost.equals(Numbers[check])) {
|
|
if ((spell.isXCost()) || (spell.isMultiKicker()) && (check - value) < 0)
|
|
XBonus = XBonus - check + value;
|
|
if (check - value < 0) value = check;
|
|
mana = mana.replaceFirst(String.valueOf(check), String.valueOf(check - value));
|
|
}
|
|
if (mana.equals("")) mana = "0";
|
|
manaCost = new ManaCost(mana);
|
|
}
|
|
} else {
|
|
// JOptionPane.showMessageDialog(null, Mana + " " + Mana.replaceFirst(k[3],""), "", JOptionPane.INFORMATION_MESSAGE);
|
|
if (mana.equals(mana.replaceFirst(k[3], ""))) {
|
|
// if(sa.isXCost()) sa.getSourceCard().addXManaCostPaid(1); Not Included as X Costs are not in Colored Mana
|
|
if (sa.isMultiKicker())
|
|
CostCutting_GetMultiMickerManaCostPaid_Colored = CostCutting_GetMultiMickerManaCostPaid_Colored + k[3];
|
|
// JOptionPane.showMessageDialog(null, CostCutting_GetMultiMickerManaCostPaid_Colored, "", JOptionPane.INFORMATION_MESSAGE);
|
|
} else {
|
|
mana = mana.replaceFirst(k[3], "");
|
|
mana = mana.trim();
|
|
if (mana.equals("")) mana = "0";
|
|
manaCost = new ManaCost(mana);
|
|
}
|
|
}
|
|
}
|
|
mana = mana.trim();
|
|
if (mana.length() == 0 || mana.equals("0")) {
|
|
if (sa.isSpell() || sa.isCycling()) mana = "0";
|
|
else {
|
|
mana = "1";
|
|
}
|
|
}
|
|
}
|
|
manaCost = new ManaCost(mana);
|
|
}
|
|
}
|
|
}
|
|
if (sa.isXCost()) {
|
|
for (int XPaid = 0; XPaid < XBonus; XPaid++) originalCard.addXManaCostPaid(1);
|
|
}
|
|
if (sa.isMultiKicker()) {
|
|
CostCutting_GetMultiMickerManaCostPaid = 0;
|
|
for (int XPaid = 0; XPaid < XBonus; XPaid++)
|
|
CostCutting_GetMultiMickerManaCostPaid = CostCutting_GetMultiMickerManaCostPaid + 1;
|
|
}
|
|
|
|
if (originalCard.getName().equals("Khalni Hydra") && spell.isSpell() == true) {
|
|
Player player = AllZone.getPhase().getPlayerTurn();
|
|
CardList playerCreature = AllZoneUtil.getCreaturesInPlay(player);
|
|
playerCreature = playerCreature.filter(CardListFilter.green);
|
|
String manaC = manaCost + " ";
|
|
if (playerCreature.size() > 0) {
|
|
for (int i = 0; i < playerCreature.size(); i++) {
|
|
manaC = manaC.replaceFirst("G ", "");
|
|
}
|
|
manaC = manaC.trim();
|
|
if (manaC.equals("")) {
|
|
manaC = "0";
|
|
}
|
|
manaCost = new ManaCost(manaC);
|
|
}
|
|
} // Khalni Hydra
|
|
return manaCost;
|
|
} //GetSpellCostChange
|
|
|
|
/**
|
|
* <p>playSpellAbility.</p>
|
|
*
|
|
* @param sa a {@link forge.card.spellability.SpellAbility} object.
|
|
*/
|
|
public final void playSpellAbility(final SpellAbility sa) {
|
|
sa.setActivatingPlayer(AllZone.getHumanPlayer());
|
|
|
|
AbilityFactory_Charm.setupCharmSAs(sa);
|
|
|
|
// Need to check PayCosts, and Ability + All SubAbilities for Target
|
|
boolean newAbility = sa.getPayCosts() != null;
|
|
SpellAbility ability = sa;
|
|
while (ability != null && !newAbility) {
|
|
Target tgt = ability.getTarget();
|
|
|
|
newAbility |= tgt != null;
|
|
ability = ability.getSubAbility();
|
|
}
|
|
|
|
if (newAbility) {
|
|
Target_Selection ts = new Target_Selection(sa.getTarget(), sa);
|
|
Cost_Payment payment = null;
|
|
if (sa.getPayCosts() == null) {
|
|
payment = new Cost_Payment(new Cost("0", sa.getSourceCard().getName(), sa.isAbility()), sa);
|
|
} else {
|
|
payment = new Cost_Payment(sa.getPayCosts(), sa);
|
|
}
|
|
|
|
if (!sa.isTrigger()) {
|
|
payment.changeCost();
|
|
}
|
|
|
|
SpellAbility_Requirements req = new SpellAbility_Requirements(sa, ts, payment);
|
|
req.fillRequirements();
|
|
} else {
|
|
ManaCost manaCost = new ManaCost(sa.getManaCost());
|
|
if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) {
|
|
manaCost = new ManaCost("0");
|
|
} else {
|
|
|
|
manaCost = getSpellCostChange(sa, new ManaCost(sa.getManaCost()));
|
|
}
|
|
if (manaCost.isPaid() && sa.getBeforePayMana() == null) {
|
|
if (sa.getAfterPayMana() == null) {
|
|
Card source = sa.getSourceCard();
|
|
if (sa.isSpell() && !source.isCopiedSpell()) {
|
|
AllZone.getGameAction().moveToStack(source);
|
|
}
|
|
|
|
AllZone.getStack().add(sa);
|
|
if (sa.isTapAbility() && !sa.wasCancelled()) {
|
|
sa.getSourceCard().tap();
|
|
}
|
|
if (sa.isUntapAbility()) {
|
|
sa.getSourceCard().untap();
|
|
}
|
|
return;
|
|
} else {
|
|
AllZone.getInputControl().setInput(sa.getAfterPayMana());
|
|
}
|
|
} else if (sa.getBeforePayMana() == null) {
|
|
AllZone.getInputControl().setInput(new Input_PayManaCost(sa));
|
|
} else {
|
|
AllZone.getInputControl().setInput(sa.getBeforePayMana());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>playSpellAbility_NoStack.</p>
|
|
*
|
|
* @param sa a {@link forge.card.spellability.SpellAbility} object.
|
|
* @param skipTargeting a boolean.
|
|
*/
|
|
public void playSpellAbility_NoStack(final SpellAbility sa, final boolean skipTargeting) {
|
|
sa.setActivatingPlayer(AllZone.getHumanPlayer());
|
|
|
|
if (sa.getPayCosts() != null) {
|
|
Target_Selection ts = new Target_Selection(sa.getTarget(), sa);
|
|
Cost_Payment payment = new Cost_Payment(sa.getPayCosts(), sa);
|
|
|
|
if (!sa.isTrigger()) {
|
|
payment.changeCost();
|
|
}
|
|
|
|
SpellAbility_Requirements req = new SpellAbility_Requirements(sa, ts, payment);
|
|
req.setSkipStack(true);
|
|
req.fillRequirements(skipTargeting);
|
|
} else {
|
|
ManaCost manaCost = new ManaCost(sa.getManaCost());
|
|
if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) {
|
|
manaCost = new ManaCost("0");
|
|
} else {
|
|
|
|
manaCost = getSpellCostChange(sa, new ManaCost(sa.getManaCost()));
|
|
}
|
|
if (manaCost.isPaid() && sa.getBeforePayMana() == null) {
|
|
if (sa.getAfterPayMana() == null) {
|
|
AbilityFactory.resolve(sa, false);
|
|
if (sa.isTapAbility() && !sa.wasCancelled()) {
|
|
sa.getSourceCard().tap();
|
|
}
|
|
if (sa.isUntapAbility()) {
|
|
sa.getSourceCard().untap();
|
|
}
|
|
return;
|
|
} else {
|
|
AllZone.getInputControl().setInput(sa.getAfterPayMana());
|
|
}
|
|
} else if (sa.getBeforePayMana() == null) {
|
|
AllZone.getInputControl().setInput(new Input_PayManaCost(sa, true));
|
|
} else {
|
|
AllZone.getInputControl().setInput(sa.getBeforePayMana());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>canPlaySpellAbility.</p>
|
|
*
|
|
* @param sa an array of {@link forge.card.spellability.SpellAbility} objects.
|
|
* @return an array of {@link forge.card.spellability.SpellAbility} objects.
|
|
*/
|
|
public final SpellAbility[] canPlaySpellAbility(final SpellAbility[] sa) {
|
|
ArrayList<SpellAbility> list = new ArrayList<SpellAbility>();
|
|
|
|
for (int i = 0; i < sa.length; i++) {
|
|
sa[i].setActivatingPlayer(AllZone.getHumanPlayer());
|
|
if (sa[i].canPlay()) {
|
|
list.add(sa[i]);
|
|
}
|
|
}
|
|
|
|
SpellAbility[] array = new SpellAbility[list.size()];
|
|
list.toArray(array);
|
|
return array;
|
|
} //canPlaySpellAbility()
|
|
|
|
/**
|
|
* <p>setComputerCut.</p>
|
|
*
|
|
* @param computerCut a {@link forge.Card} object.
|
|
*/
|
|
public final void setComputerCut(final Card computerCut) {
|
|
ComputerCut = computerCut;
|
|
}
|
|
|
|
/**
|
|
* <p>getComputerCut.</p>
|
|
*
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card getComputerCut() {
|
|
return ComputerCut;
|
|
}
|
|
|
|
/**
|
|
* <p>setStartCut.</p>
|
|
*
|
|
* @param startCutIn a boolean.
|
|
*/
|
|
public final void setStartCut(final boolean startCutIn) {
|
|
Start_Cut = startCutIn;
|
|
}
|
|
|
|
/**
|
|
* <p>isStartCut.</p>
|
|
*
|
|
* @return a boolean.
|
|
*/
|
|
public final boolean isStartCut() {
|
|
return Start_Cut;
|
|
}
|
|
|
|
/**
|
|
* <p>setHumanCut.</p>
|
|
*
|
|
* @param humanCut a {@link forge.Card} object.
|
|
*/
|
|
public final void setHumanCut(final Card humanCut) {
|
|
HumanCut = humanCut;
|
|
}
|
|
|
|
/**
|
|
* <p>getHumanCut.</p>
|
|
*
|
|
* @return a {@link forge.Card} object.
|
|
*/
|
|
public final Card getHumanCut() {
|
|
return HumanCut;
|
|
}
|
|
}
|