mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
merge latest trunk
This commit is contained in:
@@ -6876,10 +6876,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
for (final Object rem : source.getRemembered()) {
|
||||
if (rem instanceof Card) {
|
||||
final Card card = (Card) rem;
|
||||
System.out.println(this + " vs " + card);
|
||||
System.out.println(this.getOwner().equals(card.getOwner()));
|
||||
System.out.println(this.getOwner());
|
||||
System.out.println(card.getOwner());
|
||||
if (!this.getOwner().equals(card.getOwner())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ public class BoosterData {
|
||||
* @see forge.util.StorageReaderFile#read(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected BoosterData read(String line) {
|
||||
protected BoosterData read(String line, int i) {
|
||||
final FileSection section = FileSection.parse(line, ":", "|");
|
||||
int nC = section.getInt("Commons", 0);
|
||||
int nU = section.getInt("Uncommons", 0);
|
||||
|
||||
@@ -229,11 +229,11 @@ public final class CardBlock implements Comparable<CardBlock> {
|
||||
* @see forge.util.StorageReaderFile#read(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected CardBlock read(String line) {
|
||||
protected CardBlock read(String line, int i) {
|
||||
final String[] sParts = line.trim().split("\\|");
|
||||
|
||||
String name = null;
|
||||
int index = -1;
|
||||
int index = 1+i;
|
||||
final List<CardEdition> sets = new ArrayList<CardEdition>(9); // add support for up to 9 different sets in a block!
|
||||
final ArrayList<MetaSet> metas = new ArrayList<MetaSet>();
|
||||
CardEdition landSet = null;
|
||||
@@ -245,8 +245,6 @@ public final class CardBlock implements Comparable<CardBlock> {
|
||||
final String key = kv[0].toLowerCase();
|
||||
if ("name".equals(key)) {
|
||||
name = kv[1];
|
||||
} else if ("index".equals(key)) {
|
||||
index = Integer.parseInt(kv[1]);
|
||||
} else if ("set0".equals(key) || "set1".equals(key) || "set2".equals(key) || "set3".equals(key)
|
||||
|| "set4".equals(key) || "set5".equals(key) || "set6".equals(key) || "set7".equals(key)
|
||||
|| "set8".equals(key)) {
|
||||
|
||||
@@ -208,9 +208,9 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CardEdition read(String line) {
|
||||
protected CardEdition read(String line, int i) {
|
||||
FileSection section = FileSection.parse(line, ":", "|");
|
||||
int index = section.getInt("index", -1);
|
||||
int index = 1+i;
|
||||
String code2 = section.get("code2");
|
||||
String code = section.get("code3");
|
||||
String type = section.get("type");
|
||||
|
||||
@@ -57,7 +57,7 @@ public class FatPackData {
|
||||
* @see forge.util.StorageReaderFile#read(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected FatPackData read(String line) {
|
||||
protected FatPackData read(String line, int i) {
|
||||
final FileSection section = FileSection.parse(line, ":", "|");
|
||||
int nBoosters = section.getInt("Boosters", 0);
|
||||
int nLand = section.getInt("BasicLands", 0);
|
||||
|
||||
@@ -93,7 +93,7 @@ public final class FormatCollection extends StorageView<GameFormat> {
|
||||
* @see forge.util.StorageReaderFile#read(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected GameFormat read(String line) {
|
||||
protected GameFormat read(String line, int i) {
|
||||
final List<String> sets = new ArrayList<String>(); // default: all sets allowed
|
||||
final List<String> bannedCards = new ArrayList<String>(); // default:
|
||||
// nothing
|
||||
@@ -101,7 +101,7 @@ public final class FormatCollection extends StorageView<GameFormat> {
|
||||
|
||||
FileSection section = FileSection.parse(line, ":", "|");
|
||||
String name = section.get("name");
|
||||
int index = section.getInt("index", 0);
|
||||
int index = 1 + i;
|
||||
String strSets = section.get("sets");
|
||||
if ( null != strSets ) {
|
||||
sets.addAll(Arrays.asList(strSets.split(", ")));
|
||||
|
||||
@@ -143,7 +143,6 @@ public class AbilityUtils {
|
||||
final Object crd = root.getTriggeringObject(defined.substring(9));
|
||||
if (crd instanceof Card) {
|
||||
c = Singletons.getModel().getGame().getCardState((Card) crd);
|
||||
c = (Card) crd;
|
||||
} else if (crd instanceof List<?>) {
|
||||
for (final Card cardItem : (List<Card>) crd) {
|
||||
cards.add(cardItem);
|
||||
@@ -1110,6 +1109,8 @@ public class AbilityUtils {
|
||||
if (paid) {
|
||||
unpaidCommand = paidCommand;
|
||||
}
|
||||
ability.setActivatingPlayer(payer);
|
||||
ability.setTarget(sa.getTarget());
|
||||
GameActionUtil.payCostDuringAbilityResolve(payer, ability, cost, paidCommand, unpaidCommand, sa, game);
|
||||
waitForInput = true; // wait for the human input
|
||||
break; // multiple human players are not supported
|
||||
|
||||
@@ -84,6 +84,12 @@ public abstract class SpellAbilityAi {
|
||||
if (sa.getRestrictions().getPlaneswalker() && Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.MAIN2)) {
|
||||
return true;
|
||||
}
|
||||
if (sa.isTrigger()) {
|
||||
return true;
|
||||
}
|
||||
if (sa.isSpell() && !sa.isBuyBackAbility()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PhaseHandler phase = Singletons.getModel().getGame().getPhaseHandler();
|
||||
return phase.is(PhaseType.END_OF_TURN) && phase.getNextTurn().equals(ai);
|
||||
|
||||
@@ -25,6 +25,7 @@ import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.staticability.StaticAbility;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.ai.ComputerUtilCost;
|
||||
import forge.game.ai.ComputerUtilMana;
|
||||
import forge.game.phase.CombatUtil;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
@@ -46,7 +47,13 @@ public class AttachAi extends SpellAbilityAi {
|
||||
final Card source = sa.getSourceCard();
|
||||
|
||||
if (abCost != null) {
|
||||
// No Aura spells have Additional Costs
|
||||
// AI currently disabled for these costs
|
||||
if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source)) {
|
||||
return false;
|
||||
}
|
||||
if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, null)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// prevent run-away activations - first time will always return true
|
||||
@@ -991,10 +998,12 @@ public class AttachAi extends SpellAbilityAi {
|
||||
if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) {
|
||||
return false;
|
||||
}
|
||||
final boolean evasive = (keyword.endsWith("Unblockable") || keyword.equals("Fear")
|
||||
final boolean evasive = (keyword.equals("Unblockable") || keyword.equals("Fear")
|
||||
|| keyword.equals("Intimidate") || keyword.equals("Shadow")
|
||||
|| keyword.equals("Flying") || keyword.equals("Horsemanship")
|
||||
|| keyword.endsWith("walk"));
|
||||
|| keyword.endsWith("walk") || keyword.equals("CARDNAME can't be blocked except by Walls.")
|
||||
|| keyword.equals("All creatures able to block CARDNAME do so.")
|
||||
|| keyword.equals("CARDNAME can't be blocked by more than one creature."));
|
||||
// give evasive keywords to creatures that can attack and deal damage
|
||||
if (evasive) {
|
||||
if (card.getNetCombatDamage() <= 0
|
||||
|
||||
@@ -294,8 +294,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
chance &= (r.nextFloat() < .8);
|
||||
|
||||
final AbilitySub subAb = sa.getSubAbility();
|
||||
chance &= subAb == null || subAb.getAi().chkDrawbackWithSubs(ai, subAb);
|
||||
|
||||
@@ -747,7 +745,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
// Blink permanents with ETB triggers
|
||||
else if (sa.isAbility() && (sa.getPayCosts() != null) && SpellAbilityAi.playReusable(ai, sa)) {
|
||||
else if (SpellAbilityAi.playReusable(ai, sa)) {
|
||||
aiPermanents = CardLists.filter(aiPermanents, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
@@ -1319,8 +1317,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
player.shuffle();
|
||||
}
|
||||
|
||||
if ((!ZoneType.Battlefield.equals(destination) && !"Card".equals(type) && !defined)
|
||||
|| (sa.hasParam("Reveal") && !fetched.isEmpty())) {
|
||||
if (((!ZoneType.Battlefield.equals(destination) && !"Card".equals(type) && !defined)
|
||||
|| (sa.hasParam("Reveal") && !fetched.isEmpty()))
|
||||
&& !sa.hasParam("NoReveal")) {
|
||||
final String picked = player + " picked:";
|
||||
if (fetched.size() > 0) {
|
||||
GuiChoose.one(picked, fetched);
|
||||
|
||||
@@ -4,11 +4,12 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import forge.card.ability.SpellAbilityAi;
|
||||
import forge.card.ability.effects.CharmEffect;
|
||||
import org.apache.commons.lang.math.RandomUtils;
|
||||
import forge.card.ability.SpellAbilityAi;import forge.card.ability.effects.CharmEffect;
|
||||
import forge.card.spellability.AbilitySub;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
public class CharmAi extends SpellAbilityAi {
|
||||
@@ -22,7 +23,7 @@ public class CharmAi extends SpellAbilityAi {
|
||||
boolean timingRight = sa.isTrigger(); //is there a reason to play the charm now?
|
||||
|
||||
List<AbilitySub> chooseFrom = CharmEffect.makePossibleOptions(sa);
|
||||
List<AbilitySub> chosenList = chooseOptionsAi(ai, timingRight, chooseFrom, num, min);
|
||||
List<AbilitySub> chosenList = chooseOptionsAi(ai, timingRight, chooseFrom, num, min, false);
|
||||
|
||||
if (chosenList == null || chosenList.isEmpty()) {
|
||||
return false;
|
||||
@@ -32,9 +33,17 @@ public class CharmAi extends SpellAbilityAi {
|
||||
return r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());
|
||||
}
|
||||
|
||||
public static List<AbilitySub> chooseOptionsAi(final AIPlayer ai, boolean playNow, List<AbilitySub> choices, int num, int min) {
|
||||
public static List<AbilitySub> chooseOptionsAi(final AIPlayer ai, boolean playNow, List<AbilitySub> choices, int num, int min, boolean opponentChoser) {
|
||||
List<AbilitySub> chosenList = new ArrayList<AbilitySub>();
|
||||
|
||||
if (opponentChoser) {
|
||||
// This branch is for "An Opponent chooses" Charm spells from Alliances
|
||||
// Current just choose the first available spell, which seem generally less disastrous for the AI.
|
||||
//return choices.subList(0, 1);
|
||||
return choices.subList(1, choices.size());
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
AbilitySub thisPick = null;
|
||||
for (SpellAbility sub : choices) {
|
||||
@@ -57,4 +66,9 @@ public class CharmAi extends SpellAbilityAi {
|
||||
}
|
||||
return chosenList.size() >= min ? chosenList : null;
|
||||
}
|
||||
|
||||
public static Player determineOpponentChooser(AIPlayer ai, SpellAbility sa, List<Player> opponents) {
|
||||
return opponents.get(RandomUtils.nextInt(opponents.size()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -77,6 +77,13 @@ public class ControlGainAi extends SpellAbilityAi {
|
||||
|
||||
// if Defined, then don't worry about targeting
|
||||
if (tgt == null) {
|
||||
if (sa.hasParam("AllValid")) {
|
||||
List<Card> tgtCards = ai.getOpponent().getCardsIn(ZoneType.Battlefield);
|
||||
tgtCards = AbilityUtils.filterListByType(tgtCards, sa.getParam("AllValid"), sa);
|
||||
if (tgtCards.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
tgt.resetTargets();
|
||||
|
||||
@@ -80,7 +80,7 @@ public class CounterAi extends SpellAbilityAi {
|
||||
if (toPay <= usableManaSources) {
|
||||
// If this is a reusable Resource, feel free to play it most of
|
||||
// the time
|
||||
if (!sa.getPayCosts().isReusuableResource() || sa.isSpell()) {
|
||||
if (!SpellAbilityAi.playReusable(ai,sa)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,7 @@ public class CounterAi extends SpellAbilityAi {
|
||||
if (toPay <= usableManaSources) {
|
||||
// If this is a reusable Resource, feel free to play it most
|
||||
// of the time
|
||||
if (!sa.getPayCosts().isReusuableResource() || (MyRandom.getRandom().nextFloat() < .4)) {
|
||||
if (!SpellAbilityAi.playReusable(ai,sa) || (MyRandom.getRandom().nextFloat() < .4)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ public class CountersPutAllAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.isTrigger() || sa instanceof AbilitySub || SpellAbilityAi.playReusable(ai, sa)) {
|
||||
if (SpellAbilityAi.playReusable(ai, sa)) {
|
||||
return chance;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ public class DamageAllAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
int minGain = 200; // The minimum gain in destroyed creatures
|
||||
if (sa.getPayCosts().isReusuableResource()) {
|
||||
if (sa.getPayCosts() != null && sa.getPayCosts().isReusuableResource()) {
|
||||
minGain = 100;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,12 @@ package forge.card.ability.ai;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import forge.Card;
|
||||
import forge.card.ability.SpellAbilityAi;
|
||||
import forge.card.spellability.AbilitySub;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.game.ai.ComputerUtilMana;
|
||||
import forge.game.player.AIPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -14,6 +17,7 @@ public class DigUntilAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
protected boolean canPlayAI(AIPlayer ai, SpellAbility sa) {
|
||||
Card source = sa.getSourceCard();
|
||||
double chance = .4; // 40 percent chance with instant speed stuff
|
||||
if (SpellAbilityAi.isSorcerySpeed(sa)) {
|
||||
chance = .667; // 66.7% chance for sorcery speed (since it will
|
||||
@@ -36,6 +40,18 @@ public class DigUntilAi extends SpellAbilityAi {
|
||||
libraryOwner = opp;
|
||||
}
|
||||
|
||||
final String num = sa.getParam("Amount");
|
||||
if ((num != null) && num.equals("X") && source.getSVar(num).equals("Count$xPaid")) {
|
||||
// Set PayX here to maximum value.
|
||||
if (!(sa instanceof AbilitySub) || source.getSVar("PayX").equals("")) {
|
||||
int numCards = ComputerUtilMana.determineLeftoverMana(sa, ai);
|
||||
if (numCards <= 0) {
|
||||
return false;
|
||||
}
|
||||
source.setSVar("PayX", Integer.toString(numCards));
|
||||
}
|
||||
}
|
||||
|
||||
// return false if nothing to dig into
|
||||
if (libraryOwner.getCardsIn(ZoneType.Library).isEmpty()) {
|
||||
return false;
|
||||
|
||||
@@ -132,7 +132,7 @@ public class LifeLoseAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
boolean randomReturn = r.nextFloat() <= .6667;
|
||||
if (SpellAbilityAi.playReusable(ai, sa) || priority) {
|
||||
if (priority || SpellAbilityAi.playReusable(ai, sa)) {
|
||||
randomReturn = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
|
||||
final boolean evasive = (keyword.endsWith("Unblockable") || keyword.endsWith("Fear")
|
||||
|| keyword.endsWith("Intimidate") || keyword.endsWith("Shadow")
|
||||
|| keyword.contains("CantBeBlockedBy"));
|
||||
|| keyword.contains("CantBeBlockedBy") || keyword.endsWith("CARDNAME can't be blocked except by Walls."));
|
||||
final boolean combatRelevant = (keyword.endsWith("First Strike") || keyword.contains("Bushido"));
|
||||
// give evasive keywords to creatures that can or do attack
|
||||
if (evasive) {
|
||||
|
||||
@@ -50,17 +50,37 @@ public class CharmEffect extends SpellAbilityEffect {
|
||||
final List<AbilitySub> choices = makePossibleOptions(sa);
|
||||
|
||||
List<AbilitySub> chosen = null;
|
||||
|
||||
Card source = sa.getSourceCard();
|
||||
Player activator = sa.getActivatingPlayer();
|
||||
if (activator.isHuman()) {
|
||||
Player chooser = sa.getActivatingPlayer();
|
||||
|
||||
if (sa.hasParam("Chooser")) {
|
||||
// Three modal cards require you to choose a player to make the modal choice'
|
||||
// Two of these also reference the chosen player during the spell effect
|
||||
String choose = sa.getParam("Chooser");
|
||||
List<Player> opponents = activator.getOpponents();
|
||||
int numOpps = opponents.size();
|
||||
if (numOpps == 1) {
|
||||
chooser = opponents.get(0);
|
||||
} else {
|
||||
if (activator.isComputer()) {
|
||||
chooser = CharmAi.determineOpponentChooser((AIPlayer)activator, sa, opponents);
|
||||
} else {
|
||||
chooser = GuiChoose.one("Choose an opponent", opponents);
|
||||
}
|
||||
}
|
||||
source.setChosenPlayer(chooser);
|
||||
}
|
||||
|
||||
if (chooser.isHuman()) {
|
||||
String modeTitle = String.format("%s activated %s - Choose a mode", activator, source);
|
||||
chosen = new ArrayList<AbilitySub>();
|
||||
for (int i = 0; i < num; i++) {
|
||||
AbilitySub a;
|
||||
if (i < min) {
|
||||
a = GuiChoose.one("Choose a mode", choices);
|
||||
a = GuiChoose.one(modeTitle, choices);
|
||||
} else {
|
||||
a = GuiChoose.oneOrNone("Choose a mode", choices);
|
||||
a = GuiChoose.oneOrNone(modeTitle, choices);
|
||||
}
|
||||
if (null == a) {
|
||||
break;
|
||||
@@ -70,7 +90,7 @@ public class CharmEffect extends SpellAbilityEffect {
|
||||
chosen.add(a);
|
||||
}
|
||||
} else {
|
||||
chosen = CharmAi.chooseOptionsAi((AIPlayer)activator, sa.isTrigger(), choices, num, min);
|
||||
chosen = CharmAi.chooseOptionsAi((AIPlayer)chooser, sa.isTrigger(), choices, num, min, !chooser.equals(activator));
|
||||
}
|
||||
|
||||
chainAbilities(sa, chosen);
|
||||
|
||||
@@ -143,7 +143,7 @@ public class DigEffect extends SpellAbilityEffect {
|
||||
}
|
||||
// Singletons.getModel().getGameAction().revealToCopmuter(top.toArray());
|
||||
// - for when it exists
|
||||
} else if (choser.isHuman()) {
|
||||
} else if (choser.isHuman() && !sa.hasParam("NoLooking")) {
|
||||
// show the user the revealed cards
|
||||
GuiChoose.one("Looking at cards from library", top);
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ public class DiscardEffect extends RevealEffectBase {
|
||||
List<Card> chosen = getDiscardedList(p, dPChHand);
|
||||
|
||||
for (Card c : chosen) {
|
||||
dPChHand.remove(chosen);
|
||||
dPChHand.remove(c);
|
||||
toBeDiscarded.add(c);
|
||||
}
|
||||
} else
|
||||
|
||||
@@ -48,7 +48,7 @@ public class RestartGameEffect extends SpellAbilityEffect {
|
||||
playerLibraries.put(p, newLibrary);
|
||||
}
|
||||
|
||||
GameNew.restartGame(game, sa.getActivatingPlayer(), playerLibraries);
|
||||
GameNew.restartGame(Singletons.getModel().getMatch(), game, sa.getActivatingPlayer(), playerLibraries);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
@@ -3,15 +3,19 @@ package forge.card.cardfactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import forge.Card;
|
||||
import forge.Command;
|
||||
|
||||
import forge.Singletons;
|
||||
import forge.card.cost.Cost;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.spellability.Ability;
|
||||
import forge.card.spellability.AbilityActivated;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputSelectManyCards;
|
||||
import forge.game.ai.ComputerUtil;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.Zone;
|
||||
@@ -54,8 +58,10 @@ class CardFactoryArtifacts {
|
||||
@Override
|
||||
public boolean canPlayAI() {
|
||||
this.getTarget().resetTargets();
|
||||
final List<Card> libList = getActivatingPlayer().getOpponent().getCardsIn(ZoneType.Library);
|
||||
return !libList.isEmpty() && ComputerUtil.targetHumanAI(this);
|
||||
Player human = getActivatingPlayer().getOpponent();
|
||||
final List<Card> libList = human.getCardsIn(ZoneType.Library);
|
||||
this.getTarget().addTarget(human);
|
||||
return !libList.isEmpty() && canTarget(human);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,6 +104,7 @@ class CardFactoryArtifacts {
|
||||
sb.append("Put the top two cards of target player's library into that player's graveyard. ");
|
||||
sb.append("If both cards share a color, repeat this process.");
|
||||
ab1.setDescription(sb.toString());
|
||||
ab1.setStackDescription(sb.toString());
|
||||
card.addSpellAbility(ab1);
|
||||
} // *************** END ************ END **************************
|
||||
|
||||
@@ -191,5 +198,126 @@ class CardFactoryArtifacts {
|
||||
ability.setStackDescription(sbStack.toString());
|
||||
card.addSpellAbility(ability);
|
||||
} // *************** END ************ END **************************
|
||||
|
||||
|
||||
// *************** START *********** START **************************
|
||||
else if (cardName.equals("Temporal Aperture")) {
|
||||
/*
|
||||
* 5, Tap: Shuffle your library, then reveal the top card. Until end
|
||||
* of turn, for as long as that card remains on top of your library,
|
||||
* play with the top card of your library revealed and you may play
|
||||
* that card without paying its mana cost. (If it has X in its mana
|
||||
* cost, X is 0.)
|
||||
*/
|
||||
final Card[] topCard = new Card[1];
|
||||
|
||||
final Ability freeCast = new Ability(card, ManaCost.ZERO) {
|
||||
|
||||
@Override
|
||||
public boolean canPlay() {
|
||||
final PlayerZone lib = card.getController().getZone(ZoneType.Library);
|
||||
return super.canPlay() && ((lib.size() > 0) && lib.get(0).equals(topCard[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve() {
|
||||
final Card freeCard = topCard[0];
|
||||
final Player player = card.getController();
|
||||
if (freeCard != null) {
|
||||
if (freeCard.isLand()) {
|
||||
if (player.canPlayLand(freeCard)) {
|
||||
player.playLand(freeCard);
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(null, "You can't play any more lands this turn.", "",
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
} else {
|
||||
Singletons.getModel().getGame().getActionPlay().playCardWithoutManaCost(freeCard, player);
|
||||
}
|
||||
} else {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Error in ").append(cardName).append(". freeCard is null");
|
||||
JOptionPane.showMessageDialog(null, sb.toString(), "", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayAI() {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
freeCast.setDescription("Play the previously revealed top card of your library for free.");
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(cardName).append(" - play card without paying its mana cost.");
|
||||
freeCast.setStackDescription(sb.toString());
|
||||
|
||||
class AbilityTemporalAperture extends AbilityActivated {
|
||||
public AbilityTemporalAperture(final Card ca, final Cost co, final Target t) {
|
||||
super(ca, co, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbilityActivated getCopy() {
|
||||
AbilityActivated res = new AbilityTemporalAperture(getSourceCard(),
|
||||
getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
|
||||
CardFactoryUtil.copySpellAbility(this, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -7328518969488588777L;
|
||||
|
||||
@Override
|
||||
public void resolve() {
|
||||
final PlayerZone lib = card.getController().getZone(ZoneType.Library);
|
||||
if (lib.size() > 0) {
|
||||
|
||||
// shuffle your library
|
||||
card.getController().shuffle();
|
||||
|
||||
// reveal the top card
|
||||
topCard[0] = lib.get(0);
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Revealed card:\n").append(topCard[0].getName());
|
||||
JOptionPane.showMessageDialog(null, sb.toString(), card.getName(), JOptionPane.PLAIN_MESSAGE);
|
||||
|
||||
card.addSpellAbility(freeCast);
|
||||
card.addExtrinsicKeyword("Play with the top card of your library revealed.");
|
||||
Singletons.getModel().getGame().getEndOfTurn().addUntil(new Command() {
|
||||
private static final long serialVersionUID = -2860753262177388046L;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
card.removeSpellAbility(freeCast);
|
||||
card.removeExtrinsicKeyword("Play with the top card of your library revealed.");
|
||||
}
|
||||
});
|
||||
}
|
||||
} // resolve
|
||||
|
||||
@Override
|
||||
public boolean canPlayAI() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final Cost abCost = new Cost(card, "5 T", true);
|
||||
final AbilityActivated ability = new AbilityTemporalAperture(card, abCost, null);
|
||||
|
||||
final StringBuilder sbStack = new StringBuilder();
|
||||
sbStack.append(card).append(" - Shuffle your library, then reveal the top card.");
|
||||
ability.setStackDescription(sbStack.toString());
|
||||
|
||||
final StringBuilder sbDesc = new StringBuilder();
|
||||
sbDesc.append(abCost).append("Shuffle your library, then reveal the top card. ");
|
||||
sbDesc.append("Until end of turn, for as long as that card remains on top of your ");
|
||||
sbDesc.append("library, play with the top card of your library revealed ");
|
||||
sbDesc.append("and you may play that card without paying its mana cost. ");
|
||||
sbDesc.append("(If it has X in its mana cost, X is 0.)");
|
||||
ability.setDescription(sbDesc.toString());
|
||||
|
||||
card.addSpellAbility(ability);
|
||||
} // *************** END ************ END **************************
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class Cost {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean hasNoManaCost() {
|
||||
return this.getTotalMana().toString().equals(ManaCost.ZERO.toString());
|
||||
return this.getTotalMana().isZero();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,7 +373,6 @@ public class Cost {
|
||||
}
|
||||
|
||||
public final CostPartMana getCostMana() {
|
||||
// TODO: Change where ChangeCost happens
|
||||
for (final CostPart part : this.costParts) {
|
||||
if (part instanceof CostPartMana) {
|
||||
return (CostPartMana) part;
|
||||
|
||||
@@ -78,7 +78,6 @@ public class CostPutCounter extends CostPartWithList {
|
||||
super(amount, type, description);
|
||||
this.counter = cntr;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isReusable() { return true; }
|
||||
|
||||
@@ -56,6 +56,9 @@ public class CostReveal extends CostPartWithList {
|
||||
super(amount, type, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReusable() { return true; }
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
||||
@@ -45,7 +45,7 @@ public class CostUnattach extends CostPartWithList {
|
||||
public boolean isUndoable() { return false; }
|
||||
|
||||
@Override
|
||||
public boolean isReusable() { return false; }
|
||||
public boolean isReusable() { return true; }
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
||||
@@ -183,6 +183,10 @@ public final class ManaCost implements Comparable<ManaCost> {
|
||||
return this.shards.isEmpty() && !this.isNoCost();
|
||||
}
|
||||
|
||||
public boolean isZero() {
|
||||
return genericCost == 0 && isPureGeneric();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
||||
@@ -51,7 +51,6 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
|
||||
// choices for constructor isPermanent argument
|
||||
private String description = "";
|
||||
private Player targetPlayer = null;
|
||||
private String stackDescription = "";
|
||||
private ManaCost manaCost = null;
|
||||
private ManaCost multiKickerManaCost = null;
|
||||
@@ -1111,7 +1110,6 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
if (tgt != null) {
|
||||
tgt.addTarget(card);
|
||||
} else {
|
||||
this.targetPlayer = null; // reset setTargetPlayer()
|
||||
this.targetCard = card;
|
||||
}
|
||||
String desc = "";
|
||||
@@ -1124,74 +1122,6 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
this.setStackDescription(desc);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * <p>
|
||||
// * Getter for the field <code>targetList</code>.
|
||||
// * </p>
|
||||
// *
|
||||
// * @return a {@link forge.CardList} object.
|
||||
// */
|
||||
// public List<Card> getTargetList() {
|
||||
// return this.targetList;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * <p>
|
||||
// * Setter for the field <code>targetList</code>.
|
||||
// * </p>
|
||||
// *
|
||||
// * @param list
|
||||
// * a {@link forge.CardList} object.
|
||||
// */
|
||||
// public void setTargetList(final List<Card> list) {
|
||||
// // The line below started to create a null error at
|
||||
// // forge.CardFactoryUtil.canBeTargetedBy(CardFactoryUtil.java:3329)
|
||||
// // after ForgeSVN r2699. I hope that commenting out the line below will
|
||||
// // not result in other bugs. :)
|
||||
// // targetPlayer = null;//reset setTargetPlayer()
|
||||
//
|
||||
// this.targetList = list;
|
||||
// final StringBuilder sb = new StringBuilder();
|
||||
// sb.append(this.getSourceCard().getName()).append(" - targeting ");
|
||||
// for (int i = 0; i < this.targetList.size(); i++) {
|
||||
//
|
||||
// if (!this.targetList.get(i).isFaceDown()) {
|
||||
// sb.append(this.targetList.get(i));
|
||||
// } else {
|
||||
// sb.append("Morph(").append(this.targetList.get(i).getUniqueNumber()).append(")");
|
||||
// }
|
||||
//
|
||||
// if (i < (this.targetList.size() - 1)) {
|
||||
// sb.append(", ");
|
||||
// }
|
||||
// }
|
||||
// this.setStackDescription(sb.toString());
|
||||
// }
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>targetPlayer</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param p
|
||||
* a {@link forge.game.player.Player} object.
|
||||
*/
|
||||
public void setTargetPlayer(final Player p) {
|
||||
if (p == null) {
|
||||
throw new RuntimeException("SpellAbility : setTargetPlayer() error, argument is " + p + " source card is "
|
||||
+ this.getSourceCard());
|
||||
}
|
||||
|
||||
final Target tgt = this.getTarget();
|
||||
if (tgt != null) {
|
||||
tgt.addTarget(p);
|
||||
} else {
|
||||
this.targetCard = null; // reset setTargetCard()
|
||||
this.targetPlayer = p;
|
||||
}
|
||||
this.setStackDescription(this.getSourceCard().getName() + " - targeting " + p);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Getter for the field <code>targetPlayer</code>.
|
||||
@@ -1200,18 +1130,15 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
* @return a {@link forge.game.player.Player} object.
|
||||
*/
|
||||
public Player getTargetPlayer() {
|
||||
if (this.targetPlayer == null) {
|
||||
final Target tgt = this.getTarget();
|
||||
if (tgt != null) {
|
||||
final ArrayList<Player> list = tgt.getTargetPlayers();
|
||||
final Target tgt = this.getTarget();
|
||||
if (tgt != null) {
|
||||
final ArrayList<Player> list = tgt.getTargetPlayers();
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
return list.get(0);
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
return list.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return this.targetPlayer;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,6 +81,9 @@ public class SpellAbilityCondition extends SpellAbilityVariables {
|
||||
if (value.equals("Kicked")) {
|
||||
this.setKicked(true);
|
||||
}
|
||||
if (value.equals("AllTargetsLegal")) {
|
||||
this.setAllTargetsLegal(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (params.containsKey("ConditionZone")) {
|
||||
@@ -196,6 +199,14 @@ public class SpellAbilityCondition extends SpellAbilityVariables {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.isAllTargetsLegal()) {
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
for (Card c : root.getTarget().getTargetCards()) {
|
||||
if (!CardFactoryUtil.isTargetStillValid(sa, c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isSorcerySpeed() && !activator.canCastSorcery()) {
|
||||
return false;
|
||||
|
||||
@@ -69,6 +69,7 @@ public class SpellAbilityVariables {
|
||||
this.threshold = sav.isThreshold();
|
||||
this.metalcraft = sav.isThreshold();
|
||||
this.hellbent = sav.isHellbent();
|
||||
this.allTargetsLegal = sav.isAllTargetsLegal();
|
||||
this.prowl = new ArrayList<String>(sav.getProwl());
|
||||
this.isPresent = sav.getIsPresent();
|
||||
this.presentCompare = sav.getPresentCompare();
|
||||
@@ -136,6 +137,8 @@ public class SpellAbilityVariables {
|
||||
|
||||
/** The Kicked. */
|
||||
private boolean kicked = false;
|
||||
|
||||
private boolean allTargetsLegal = false;
|
||||
|
||||
/** The prowl. */
|
||||
private ArrayList<String> prowl = new ArrayList<String>();
|
||||
@@ -519,6 +522,21 @@ public class SpellAbilityVariables {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the allTargetsLegal
|
||||
*/
|
||||
public boolean isAllTargetsLegal() {
|
||||
return allTargetsLegal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allTargetsLegal0 the allTargetsLegal to set
|
||||
*/
|
||||
public void setAllTargetsLegal(boolean allTargets) {
|
||||
this.allTargetsLegal = allTargets;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>prowl</code>.
|
||||
|
||||
@@ -340,16 +340,6 @@ public class WrappedAbility extends Ability implements ISpellAbility {
|
||||
sa.setTargetCard(card);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void setTargetList(final List<Card> list) {
|
||||
// sa.setTargetList(list);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void setTargetPlayer(final Player p) {
|
||||
sa.setTargetPlayer(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(final String s) {
|
||||
sa.setType(s);
|
||||
|
||||
@@ -25,6 +25,7 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController;
|
||||
import forge.game.zone.MagicStack;
|
||||
import forge.gui.match.controllers.CMessage;
|
||||
import forge.util.MyObservable;
|
||||
|
||||
/**
|
||||
@@ -65,7 +66,7 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
*/
|
||||
public final void setInput(final Input in) {
|
||||
boolean isInputEmpty = this.input == null || this.input instanceof InputPassPriority;
|
||||
System.out.println(in.getClass().getName());
|
||||
//System.out.println(in.getClass().getName());
|
||||
if (!this.game.getStack().isResolving() && isInputEmpty) {
|
||||
this.input = in;
|
||||
} else {
|
||||
@@ -134,12 +135,9 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
* @param update
|
||||
* a boolean.
|
||||
*/
|
||||
public final void resetInput() { resetInput(true); }
|
||||
public final void resetInput(final boolean update) {
|
||||
public final void resetInput() {
|
||||
this.input = null;
|
||||
if (update) {
|
||||
this.updateObservers();
|
||||
}
|
||||
this.updateObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,4 +242,19 @@ public class InputControl extends MyObservable implements java.io.Serializable {
|
||||
return pc.getDefaultInput();
|
||||
} // getInput()
|
||||
|
||||
public final void setNewInput(GameState game) {
|
||||
PhaseHandler ph = game.getPhaseHandler();
|
||||
|
||||
final Input tmp = getActualInput();
|
||||
//String message = String.format("%s's %s, priority of %s [%sP] input is %s", ph.getPlayerTurn(), ph.getPhase(), ph.getPriorityPlayer(), ph.isPlayerPriorityAllowed() ? "+" : "-", tmp == null ? "null" : tmp.getClass().getSimpleName());
|
||||
//System.out.println(message);
|
||||
if (tmp != null) {
|
||||
//System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ input is " + tmp.getClass().getName() );
|
||||
CMessage.SINGLETON_INSTANCE.getInputControl().setInput(tmp);
|
||||
} else if (!ph.isPlayerPriorityAllowed()) {
|
||||
// System.out.println("cannot have priority, forced to pass");
|
||||
ph.getPriorityPlayer().getController().passPriority();
|
||||
}
|
||||
}
|
||||
|
||||
} // InputControl
|
||||
|
||||
@@ -62,10 +62,19 @@ public class InputMulligan extends Input {
|
||||
ButtonUtil.setButtonText("No", "Yes");
|
||||
ButtonUtil.enableAllFocusOk();
|
||||
|
||||
final String str =
|
||||
(Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().equals(Singletons.getControl().getPlayer())
|
||||
? "You're going first. " : "The computer is going first. ");
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(str + "Do you want to Mulligan?");
|
||||
GameState game = Singletons.getModel().getGame();
|
||||
Player startingPlayer = game.getPhaseHandler().getPlayerTurn();
|
||||
Player localPlayer = Singletons.getControl().getPlayer();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(startingPlayer.getName()).append(" is going first. ");
|
||||
|
||||
if (!startingPlayer.equals(localPlayer)) {
|
||||
sb.append("You are going ").append(game.getOrdinalPosition(localPlayer, startingPlayer)).append(". ");
|
||||
}
|
||||
|
||||
sb.append("Do you want to Mulligan?");
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
||||
@@ -46,7 +46,7 @@ import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
* This class knows how to make a file out of a deck object and vice versa.
|
||||
*
|
||||
*/
|
||||
public class DeckSerializer extends StorageReaderFolder<Deck> implements IItemSerializer<Deck> {
|
||||
|
||||
@@ -248,7 +248,7 @@ public class GameAction {
|
||||
copied.getCharacteristics().resetCardColor();
|
||||
}
|
||||
|
||||
if (zoneFrom.is(ZoneType.Battlefield)) {
|
||||
if (zoneFrom.is(ZoneType.Battlefield) && !c.isToken()) {
|
||||
copied.setSuspendCast(false);
|
||||
copied.setState(CardCharacteristicName.Original);
|
||||
// Soulbond unpairing
|
||||
|
||||
@@ -11,8 +11,6 @@ import java.util.Set;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -25,11 +23,13 @@ import forge.CardUtil;
|
||||
import forge.Singletons;
|
||||
import forge.card.trigger.TriggerHandler;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.control.input.Input;
|
||||
import forge.control.input.InputControl;
|
||||
import forge.control.input.InputMulligan;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.error.BugReporter;
|
||||
import forge.game.event.FlipCoinEvent;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.phase.PhaseType;
|
||||
@@ -38,9 +38,11 @@ import forge.game.player.LobbyPlayer;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.match.controllers.CMessage;
|
||||
import forge.gui.match.views.VAntes;
|
||||
import forge.item.CardPrinted;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.MyRandom;
|
||||
@@ -50,6 +52,45 @@ import forge.util.MyRandom;
|
||||
* All of these methods can and should be static.
|
||||
*/
|
||||
public class GameNew {
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public static final class GameInputUpdatesThread extends Thread {
|
||||
private final MatchController match;
|
||||
private final GameState game;
|
||||
private boolean wasChangedRecently;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param match
|
||||
* @param game
|
||||
*/
|
||||
public GameInputUpdatesThread(MatchController match, GameState game) {
|
||||
this.match = match;
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
public void run(){
|
||||
while(!game.isGameOver()) {
|
||||
boolean needsNewInput = CMessage.SINGLETON_INSTANCE.getInputControl().isValid() == false;
|
||||
if ( needsNewInput ) {
|
||||
match.getInput().setNewInput(game);
|
||||
wasChangedRecently = true;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(wasChangedRecently ? 2 : 40);
|
||||
wasChangedRecently = false;
|
||||
} catch (InterruptedException e) {
|
||||
BugReporter.reportException(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final ForgePreferences preferences = Singletons.getModel().getPreferences();
|
||||
|
||||
private static void preparePlayerLibrary(Player player, final ZoneType zoneType, CardPool secion, boolean canRandomFoil, Random generator) {
|
||||
PlayerZone library = player.getZone(zoneType);
|
||||
@@ -60,7 +101,7 @@ public class GameNew {
|
||||
final Card card = cardPrinted.toForgeCard(player);
|
||||
|
||||
// apply random pictures for cards
|
||||
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_CARD_ART)) {
|
||||
if (preferences.getPrefBoolean(FPref.UI_RANDOM_CARD_ART)) {
|
||||
final int cntVariants = cardPrinted.getRules().getEditionInfo(cardPrinted.getEdition()).getCopiesCount();
|
||||
if (cntVariants > 1) {
|
||||
card.setRandomPicture(generator.nextInt(cntVariants - 1) + 1);
|
||||
@@ -86,8 +127,8 @@ public class GameNew {
|
||||
* TODO: Accept something like match state as parameter. Match should be aware of players,
|
||||
* their decks and other special starting conditions.
|
||||
*/
|
||||
public static void newGame(final Map<Player, PlayerStartConditions> playersConditions, final GameState game, final boolean canRandomFoil) {
|
||||
Singletons.getModel().getMatch().getInput().clearInput();
|
||||
public static void newGame(final MatchController match, final Map<Player, PlayerStartConditions> playersConditions, final GameState game, final boolean canRandomFoil) {
|
||||
match.getInput().clearInput();
|
||||
|
||||
Card.resetUniqueNumber();
|
||||
// need this code here, otherwise observables fail
|
||||
@@ -97,7 +138,7 @@ public class GameNew {
|
||||
trigHandler.clearDelayedTrigger();
|
||||
|
||||
// friendliness
|
||||
boolean useAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE);
|
||||
boolean useAnte = preferences.getPrefBoolean(FPref.UI_ANTE);
|
||||
final Set<CardPrinted> rAICards = new HashSet<CardPrinted>();
|
||||
|
||||
Map<Player, Set<CardPrinted>> removedAnteCards = new HashMap<Player, Set<CardPrinted>>();
|
||||
@@ -112,8 +153,8 @@ public class GameNew {
|
||||
|
||||
initVariantsZones(player, psc);
|
||||
|
||||
GameType gameType = Singletons.getModel().getMatch().getGameType();
|
||||
boolean isFirstGame = Singletons.getModel().getMatch().getPlayedGames().isEmpty();
|
||||
GameType gameType = match.getGameType();
|
||||
boolean isFirstGame = match.getPlayedGames().isEmpty();
|
||||
boolean hasSideboard = psc.getOriginalDeck().has(DeckSection.Sideboard);
|
||||
boolean canSideBoard = !isFirstGame && gameType.isSideboardingAllowed() && hasSideboard;
|
||||
|
||||
@@ -132,7 +173,7 @@ public class GameNew {
|
||||
preparePlayerLibrary(player, ZoneType.Sideboard, myDeck.get(DeckSection.Sideboard), canRandomFoil, generator);
|
||||
|
||||
// Shuffling
|
||||
if (player instanceof AIPlayer && Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_SMOOTH_LAND)) {
|
||||
if (player instanceof AIPlayer && preferences.getPrefBoolean(FPref.UI_SMOOTH_LAND)) {
|
||||
// AI may do this instead of shuffling its deck
|
||||
final Iterable<Card> c1 = GameNew.smoothComputerManaCurve(player.getCardsIn(ZoneType.Library));
|
||||
player.getZone(ZoneType.Library).setCards(c1);
|
||||
@@ -174,7 +215,7 @@ public class GameNew {
|
||||
JOptionPane.showMessageDialog(null, ante.toString(), "", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
GameNew.actuateGame(game, false);
|
||||
GameNew.actuateGame(match, game, false);
|
||||
}
|
||||
|
||||
private static void initVariantsZones(final Player player, final PlayerStartConditions psc) {
|
||||
@@ -243,8 +284,7 @@ public class GameNew {
|
||||
}
|
||||
|
||||
// ultimate of Karn the Liberated
|
||||
public static void restartGame(final GameState game, final Player startingTurn, Map<Player, List<Card>> playerLibraries) {
|
||||
MatchController match = Singletons.getModel().getMatch();
|
||||
public static void restartGame(final MatchController match, final GameState game, final Player startingTurn, Map<Player, List<Card>> playerLibraries) {
|
||||
|
||||
Map<LobbyPlayer, PlayerStartConditions> players = match.getPlayers();
|
||||
Map<Player, PlayerStartConditions> playersConditions = new HashMap<Player, PlayerStartConditions>();
|
||||
@@ -291,7 +331,7 @@ public class GameNew {
|
||||
PhaseHandler phaseHandler = game.getPhaseHandler();
|
||||
phaseHandler.setPlayerTurn(startingTurn);
|
||||
|
||||
GameNew.actuateGame(game, true);
|
||||
GameNew.actuateGame(match, game, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,10 +342,10 @@ public class GameNew {
|
||||
* newGame, then when all is ready, call this function.
|
||||
* @param isRestartedGame Whether the actuated game is the first start or a restart
|
||||
*/
|
||||
private static void actuateGame(final GameState game, boolean isRestartedGame) {
|
||||
private static void actuateGame(final MatchController match, final GameState game, boolean isRestartedGame) {
|
||||
if (!isRestartedGame) {
|
||||
// Deciding which cards go to ante
|
||||
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE)) {
|
||||
if (preferences.getPrefBoolean(FPref.UI_ANTE)) {
|
||||
final String nl = System.getProperty("line.separator");
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
for (final Player p : game.getPlayers()) {
|
||||
@@ -324,15 +364,24 @@ public class GameNew {
|
||||
JOptionPane.showMessageDialog(null, msg, "Ante", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
GameOutcome lastGameOutcome = Singletons.getModel().getMatch().getLastGameOutcome();
|
||||
GameOutcome lastGameOutcome = match.getLastGameOutcome();
|
||||
// Only cut/coin toss if it's the first game of the match
|
||||
if (lastGameOutcome == null) {
|
||||
GameNew.seeWhoPlaysFirstDice();
|
||||
Player goesFirst;
|
||||
Player humanPlayer = Singletons.getControl().getPlayer();
|
||||
boolean isFirstGame = lastGameOutcome == null;
|
||||
if (isFirstGame) {
|
||||
goesFirst = GameNew.seeWhoPlaysFirstDice(game);
|
||||
} else {
|
||||
Player human = Singletons.getControl().getPlayer();
|
||||
Player goesFirst = lastGameOutcome.isWinner(human.getLobbyPlayer()) ? human.getOpponent() : human;
|
||||
setPlayersFirstTurn(goesFirst, false);
|
||||
|
||||
goesFirst = lastGameOutcome.isWinner(humanPlayer.getLobbyPlayer()) ? humanPlayer.getOpponent() : humanPlayer;
|
||||
}
|
||||
String message = goesFirst + ( isFirstGame ? " has won the coin toss." : " lost the last game.");
|
||||
boolean willPlay = goesFirst.getController().getWillPlayOnFirstTurn(message);
|
||||
if ( goesFirst != humanPlayer ) {
|
||||
JOptionPane.showMessageDialog(null, message + "\nComputer Going First", "You are drawing", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
goesFirst = willPlay ? goesFirst : goesFirst.getOpponent();
|
||||
game.getPhaseHandler().setPlayerTurn(goesFirst);
|
||||
}
|
||||
|
||||
// Draw <handsize> cards
|
||||
@@ -340,9 +389,20 @@ public class GameNew {
|
||||
p.drawCards(p.getMaxHandSize());
|
||||
}
|
||||
|
||||
|
||||
|
||||
game.getPhaseHandler().setPhaseState(PhaseType.MULLIGAN);
|
||||
InputControl control = Singletons.getModel().getMatch().getInput();
|
||||
control.setInput(new InputMulligan());
|
||||
|
||||
InputControl control = match.getInput();
|
||||
Input tmp = new InputMulligan();
|
||||
control.setInput(tmp);
|
||||
|
||||
|
||||
Thread thGame = new GameInputUpdatesThread(match, game);
|
||||
|
||||
match.getInput().getInput().showMessage();
|
||||
thGame.setName("Game input updater");
|
||||
thGame.start();
|
||||
} // newGame()
|
||||
|
||||
private static String buildFourColumnList(String firstLine, Iterable<CardPrinted> cAnteRemoved) {
|
||||
@@ -418,49 +478,14 @@ public class GameNew {
|
||||
* <p>
|
||||
* seeWhoPlaysFirstCoinToss.
|
||||
* </p>
|
||||
* @return
|
||||
*/
|
||||
private static void seeWhoPlaysFirstDice() {
|
||||
int playerDie = 0;
|
||||
int computerDie = 0;
|
||||
|
||||
while (playerDie == computerDie) {
|
||||
playerDie = MyRandom.getRandom().nextInt(20);
|
||||
computerDie = MyRandom.getRandom().nextInt(20);
|
||||
}
|
||||
|
||||
private static Player seeWhoPlaysFirstDice(final GameState game) {
|
||||
// Play the Flip Coin sound
|
||||
Singletons.getModel().getGame().getEvents().post(new FlipCoinEvent());
|
||||
game.getEvents().post(new FlipCoinEvent());
|
||||
|
||||
List<Player> allPlayers = Singletons.getModel().getGame().getPlayers();
|
||||
setPlayersFirstTurn(allPlayers.get(MyRandom.getRandom().nextInt(allPlayers.size())), true);
|
||||
List<Player> allPlayers = game.getPlayers();
|
||||
return allPlayers.get(MyRandom.getRandom().nextInt(allPlayers.size()));
|
||||
}
|
||||
|
||||
private static void setPlayersFirstTurn(Player goesFirst, boolean firstGame) {
|
||||
StringBuilder sb = new StringBuilder(goesFirst.toString());
|
||||
if (firstGame) {
|
||||
sb.append(" has won the coin toss.");
|
||||
}
|
||||
else {
|
||||
sb.append(" lost the last game.");
|
||||
}
|
||||
if (goesFirst.isHuman()) {
|
||||
if (!humanPlayOrDraw(sb.toString())) {
|
||||
goesFirst = goesFirst.getOpponent();
|
||||
}
|
||||
} else {
|
||||
sb.append("\nComputer Going First");
|
||||
JOptionPane.showMessageDialog(null, sb.toString(), "Play or Draw?", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
Singletons.getModel().getGame().getPhaseHandler().setPlayerTurn(goesFirst);
|
||||
} // seeWhoPlaysFirstDice()
|
||||
|
||||
private static boolean humanPlayOrDraw(String message) {
|
||||
final String[] possibleValues = { "Play", "Draw" };
|
||||
|
||||
final Object playDraw = JOptionPane.showOptionDialog(null, message + "\n\nWould you like to play or draw?",
|
||||
"Play or Draw?", JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null,
|
||||
possibleValues, possibleValues[0]);
|
||||
|
||||
return !playDraw.equals(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,6 +478,21 @@ public class GameState {
|
||||
return roIngamePlayers.get(iPlayer);
|
||||
|
||||
}
|
||||
|
||||
public String getOrdinalPosition(Player player, Player startingPlayer) {
|
||||
int startPosition = roIngamePlayers.indexOf(startingPlayer);
|
||||
int position = roIngamePlayers.indexOf(player) + startPosition + 1;
|
||||
String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
|
||||
switch (position % 100) {
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
return position + "th";
|
||||
default:
|
||||
return position + sufixes[position % 10];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only game knows how to get suitable players out of just connected clients.
|
||||
|
||||
@@ -19,7 +19,7 @@ import forge.game.player.Player;
|
||||
import forge.game.player.PlayerStatistics;
|
||||
import forge.game.player.PlayerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiInput;
|
||||
import forge.gui.InputProxy;
|
||||
import forge.gui.framework.EDocID;
|
||||
import forge.gui.framework.SDisplayUtil;
|
||||
import forge.gui.match.CMatchUI;
|
||||
@@ -149,8 +149,7 @@ public class MatchController {
|
||||
Singletons.getControl().changeState(FControl.Screens.MATCH_SCREEN);
|
||||
SDisplayUtil.showTab(EDocID.REPORT_LOG.getDoc());
|
||||
|
||||
// set all observers
|
||||
GuiInput inputControl = CMessage.SINGLETON_INSTANCE.getInputControl();
|
||||
InputProxy inputControl = CMessage.SINGLETON_INSTANCE.getInputControl();
|
||||
input.addObserver(inputControl);
|
||||
currentGame.getStack().addObserver(inputControl);
|
||||
currentGame.getPhaseHandler().addObserver(inputControl);
|
||||
@@ -159,7 +158,7 @@ public class MatchController {
|
||||
// some observers are set in CMatchUI.initMatch
|
||||
|
||||
final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed;
|
||||
GameNew.newGame(startConditions, currentGame, canRandomFoil);
|
||||
GameNew.newGame(this, startConditions, currentGame, canRandomFoil);
|
||||
|
||||
// TODO restore this functionality!!!
|
||||
//VMatchUI.SINGLETON_INSTANCE.getViewDevMode().getDocument().setVisible(Preferences.DEV_MODE);
|
||||
|
||||
@@ -161,7 +161,9 @@ public class AiInputCommon extends Input {
|
||||
sa = computer.getSpellAbilityToPlay();
|
||||
if ( sa == null ) break;
|
||||
//System.out.println("Playing sa: " + sa);
|
||||
ComputerUtil.handlePlayingSpellAbility(player, sa, game);
|
||||
if (!ComputerUtil.handlePlayingSpellAbility(player, sa, game)) {
|
||||
break;
|
||||
}
|
||||
} while ( sa != null );
|
||||
}
|
||||
|
||||
|
||||
@@ -425,14 +425,16 @@ public class ComputerUtil {
|
||||
int count = 0;
|
||||
|
||||
while (count < amount) {
|
||||
final Card prefCard = ComputerUtil.getCardPreference(ai, source, "SacCost", typeList);
|
||||
if (prefCard != null) {
|
||||
sacList.add(prefCard);
|
||||
typeList.remove(prefCard);
|
||||
count++;
|
||||
} else {
|
||||
Card prefCard = ComputerUtil.getCardPreference(ai, source, "SacCost", typeList);
|
||||
if (prefCard == null) {
|
||||
prefCard = ComputerUtilCard.getWorstAI(typeList);
|
||||
}
|
||||
if (prefCard == null) {
|
||||
return null;
|
||||
}
|
||||
sacList.add(prefCard);
|
||||
typeList.remove(prefCard);
|
||||
count++;
|
||||
}
|
||||
return sacList;
|
||||
}
|
||||
@@ -945,19 +947,6 @@ public class ComputerUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static boolean targetHumanAI(final SpellAbility sa) {
|
||||
if (sa == null || sa.getActivatingPlayer() == null) {
|
||||
return false;
|
||||
}
|
||||
Player human = sa.getActivatingPlayer().getOpponent();
|
||||
if (!sa.canTarget(human)) {
|
||||
return false;
|
||||
}
|
||||
sa.setTargetPlayer(human);
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns true if it's better to wait until blockers are declared
|
||||
/**
|
||||
* <p>
|
||||
|
||||
@@ -1648,13 +1648,13 @@ public class ComputerUtilCombat {
|
||||
public static Map<Card, Integer> distributeAIDamage(final Card attacker, final List<Card> block, int dmgCanDeal, GameEntity defender) {
|
||||
Map<Card, Integer> damageMap = new HashMap<Card, Integer>();
|
||||
|
||||
if (attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")
|
||||
|| attacker.hasKeyword("CARDNAME assigns its combat damage as though it weren't blocked.")) {
|
||||
boolean isAttacking = defender != null;
|
||||
|
||||
if (isAttacking && (attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")
|
||||
|| attacker.hasKeyword("CARDNAME assigns its combat damage as though it weren't blocked."))) {
|
||||
damageMap.put(null, dmgCanDeal);
|
||||
return damageMap;
|
||||
}
|
||||
|
||||
boolean isAttacking = defender != null;
|
||||
|
||||
final boolean hasTrample = attacker.hasKeyword("Trample");
|
||||
|
||||
|
||||
@@ -460,6 +460,7 @@ public class ComputerUtilMana {
|
||||
private static List<Card> getAvailableMana(final Player ai, final boolean checkPlayable) {
|
||||
final GameState game = Singletons.getModel().getGame();
|
||||
final List<Card> list = ai.getCardsIn(ZoneType.Battlefield);
|
||||
list.addAll(ai.getCardsIn(ZoneType.Hand));
|
||||
final List<Card> manaSources = CardLists.filter(list, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
|
||||
@@ -2522,6 +2522,10 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
||||
if (!source.getRemembered().contains(this)) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.equals("IsNotRemembered")) {
|
||||
if (source.getRemembered().contains(this)) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.startsWith("EnchantedBy")) {
|
||||
if (!this.getEnchantedBy().contains(source)) {
|
||||
return false;
|
||||
|
||||
@@ -30,24 +30,6 @@ import forge.Card;
|
||||
* @version $Id$
|
||||
*/
|
||||
interface IZone {
|
||||
/**
|
||||
* <p>
|
||||
* setUpdate.
|
||||
* </p>
|
||||
*
|
||||
* @param b
|
||||
* a boolean.
|
||||
*/
|
||||
void setUpdate(boolean b);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getUpdate.
|
||||
* </p>
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
boolean getUpdate();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -101,7 +83,7 @@ interface IZone {
|
||||
* @param o
|
||||
* a {@link java.lang.Object} object.
|
||||
*/
|
||||
void remove(Object o);
|
||||
void remove(Card o);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
||||
@@ -680,7 +680,7 @@ public class MagicStack extends MyObservable {
|
||||
// Create a new object, since the triggers aren't happening right away
|
||||
runParams = new HashMap<String, Object>();
|
||||
runParams.put("SourceSA", sp);
|
||||
if (chosenTargets.size() > 0) {
|
||||
if (!chosenTargets.isEmpty()) {
|
||||
HashSet<Object> distinctObjects = new HashSet<Object>();
|
||||
for (final TargetChoices tc : chosenTargets) {
|
||||
if ((tc != null) && (tc.getTargetCards() != null)) {
|
||||
@@ -704,10 +704,6 @@ public class MagicStack extends MyObservable {
|
||||
else if (sp.getTargetCard() != null) {
|
||||
runParams.put("Target", sp.getTargetCard());
|
||||
|
||||
game.getTriggerHandler().runTrigger(TriggerType.BecomesTarget, runParams, false);
|
||||
} else if (sp.getTargetPlayer() != null) {
|
||||
runParams.put("Target", sp.getTargetPlayer());
|
||||
|
||||
game.getTriggerHandler().runTrigger(TriggerType.BecomesTarget, runParams, false);
|
||||
}
|
||||
}
|
||||
@@ -1075,9 +1071,6 @@ public class MagicStack extends MyObservable {
|
||||
else if (sa.getTargetCard() != null) {
|
||||
fizzle = !CardFactoryUtil.isTargetStillValid(sa, sa.getTargetCard());
|
||||
}
|
||||
else if (sa.getTargetPlayer() != null) {
|
||||
fizzle = !sa.getTargetPlayer().canBeTargetedBy(sa);
|
||||
}
|
||||
else {
|
||||
// Set fizzle to the same as the parent if there's no target info
|
||||
fizzle = parentFizzled;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.game.zone;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
@@ -181,7 +180,7 @@ public class PlayerZoneBattlefield extends PlayerZone {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void remove(final Object o) {
|
||||
public final void remove(final Card o) {
|
||||
|
||||
super.remove(o);
|
||||
|
||||
@@ -244,30 +243,6 @@ public class PlayerZoneBattlefield extends PlayerZone {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>trigger</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param b
|
||||
* a boolean.
|
||||
*/
|
||||
public final void setTrigger(final boolean b) {
|
||||
this.trigger = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>leavesTrigger</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param b
|
||||
* a boolean.
|
||||
*/
|
||||
public final void setLeavesTrigger(final boolean b) {
|
||||
this.leavesTrigger = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setTriggers.
|
||||
@@ -300,7 +275,7 @@ public class PlayerZoneBattlefield extends PlayerZone {
|
||||
// getCards(false) to get Phased Out cards
|
||||
|
||||
if (!filter) {
|
||||
return new ArrayList<Card>(cardList);
|
||||
return super.getCards(false);
|
||||
}
|
||||
return Lists.newArrayList(Iterables.filter(cardList, isNotPhased));
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@ public class Zone extends MyObservable implements IZone, Observer, java.io.Seria
|
||||
public Zone(final ZoneType zone) {
|
||||
this.zoneName = zone;
|
||||
this.roCardList = Collections.unmodifiableList(cardList);
|
||||
|
||||
//System.out.println(zoneName + " (ct) " + Integer.toHexString(System.identityHashCode(roCardList)));
|
||||
}
|
||||
|
||||
// ************ BEGIN - these methods fire updateObservers() *************
|
||||
@@ -191,7 +193,7 @@ public class Zone extends MyObservable implements IZone, Observer, java.io.Seria
|
||||
* an Object
|
||||
*/
|
||||
@Override
|
||||
public void remove(final Object c) {
|
||||
public void remove(final Card c) {
|
||||
this.cardList.remove(c);
|
||||
this.update();
|
||||
}
|
||||
@@ -287,6 +289,7 @@ public class Zone extends MyObservable implements IZone, Observer, java.io.Seria
|
||||
*/
|
||||
@Override
|
||||
public final List<Card> getCards() {
|
||||
//System.out.println(zoneName + ": " + Integer.toHexString(System.identityHashCode(roCardList)));
|
||||
return this.getCards(true);
|
||||
}
|
||||
|
||||
@@ -322,29 +325,6 @@ public class Zone extends MyObservable implements IZone, Observer, java.io.Seria
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the update.
|
||||
*
|
||||
* @param b
|
||||
* a boolean.
|
||||
*/
|
||||
@Override
|
||||
public final void setUpdate(final boolean b) {
|
||||
this.update = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Getter for the field <code>update</code>.
|
||||
* </p>
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
@Override
|
||||
public final boolean getUpdate() {
|
||||
return this.update;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* toString.
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package forge.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Rectangle;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.FileInputStream;
|
||||
@@ -61,8 +60,6 @@ import forge.game.zone.ZoneType;
|
||||
import forge.item.CardDb;
|
||||
import forge.item.CardPrinted;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.view.arcane.PlayArea;
|
||||
import forge.view.arcane.util.Animation;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -255,91 +252,6 @@ public final class GuiDisplayUtil {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setupPlayZone.
|
||||
* </p>
|
||||
*
|
||||
* @param p
|
||||
* a {@link forge.view.arcane.PlayArea} object.
|
||||
* @param c
|
||||
* an array of {@link forge.Card} objects.
|
||||
*/
|
||||
public static void setupPlayZone(final PlayArea p, final List<Card> c) {
|
||||
List<Card> tmp, diff;
|
||||
tmp = new ArrayList<Card>();
|
||||
for (final forge.view.arcane.CardPanel cpa : p.getCardPanels()) {
|
||||
tmp.add(cpa.getGameCard());
|
||||
}
|
||||
diff = new ArrayList<Card>(tmp);
|
||||
diff.removeAll(c);
|
||||
if (diff.size() == p.getCardPanels().size()) {
|
||||
p.clear();
|
||||
} else {
|
||||
for (final Card card : diff) {
|
||||
p.removeCardPanel(p.getCardPanel(card.getUniqueNumber()));
|
||||
}
|
||||
}
|
||||
diff = new ArrayList<Card>(c);
|
||||
diff.removeAll(tmp);
|
||||
|
||||
List<forge.view.arcane.CardPanel> panelList = new ArrayList<forge.view.arcane.CardPanel>();
|
||||
for (final Card card : diff) {
|
||||
panelList.add(p.addCard(card));
|
||||
}
|
||||
if (!diff.isEmpty()) {
|
||||
p.doLayout();
|
||||
}
|
||||
for (final forge.view.arcane.CardPanel toPanel : panelList) {
|
||||
p.scrollRectToVisible(new Rectangle(toPanel.getCardX(), toPanel.getCardY(), toPanel
|
||||
.getCardWidth(), toPanel.getCardHeight()));
|
||||
Animation.moveCard(toPanel);
|
||||
}
|
||||
|
||||
for (final Card card : c) {
|
||||
final forge.view.arcane.CardPanel toPanel = p.getCardPanel(card.getUniqueNumber());
|
||||
if (card.isTapped()) {
|
||||
toPanel.setTapped(true);
|
||||
toPanel.setTappedAngle(forge.view.arcane.CardPanel.TAPPED_ANGLE);
|
||||
} else {
|
||||
toPanel.setTapped(false);
|
||||
toPanel.setTappedAngle(0);
|
||||
}
|
||||
toPanel.getAttachedPanels().clear();
|
||||
if (card.isEnchanted()) {
|
||||
final ArrayList<Card> enchants = card.getEnchantedBy();
|
||||
for (final Card e : enchants) {
|
||||
final forge.view.arcane.CardPanel cardE = p.getCardPanel(e.getUniqueNumber());
|
||||
if (cardE != null) {
|
||||
toPanel.getAttachedPanels().add(cardE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (card.isEquipped()) {
|
||||
final ArrayList<Card> enchants = card.getEquippedBy();
|
||||
for (final Card e : enchants) {
|
||||
final forge.view.arcane.CardPanel cardE = p.getCardPanel(e.getUniqueNumber());
|
||||
if (cardE != null) {
|
||||
toPanel.getAttachedPanels().add(cardE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (card.isEnchantingCard()) {
|
||||
toPanel.setAttachedToPanel(p.getCardPanel(card.getEnchantingCard().getUniqueNumber()));
|
||||
} else if (card.isEquipping()) {
|
||||
toPanel.setAttachedToPanel(p.getCardPanel(card.getEquipping().get(0).getUniqueNumber()));
|
||||
} else {
|
||||
toPanel.setAttachedToPanel(null);
|
||||
}
|
||||
|
||||
toPanel.setCard(toPanel.getGameCard());
|
||||
}
|
||||
p.invalidate();
|
||||
p.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* updateGUI.
|
||||
|
||||
@@ -21,9 +21,7 @@ import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import forge.Card;
|
||||
import forge.Singletons;
|
||||
import forge.control.input.Input;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.util.MyObservable;
|
||||
@@ -36,28 +34,16 @@ import forge.util.MyObservable;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class GuiInput extends MyObservable implements Observer {
|
||||
public class InputProxy extends MyObservable implements Observer {
|
||||
|
||||
/** The input. */
|
||||
private Input input;
|
||||
private volatile boolean valid = false;
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void update(final Observable observable, final Object obj) {
|
||||
PhaseHandler ph = Singletons.getModel().getGame().getPhaseHandler();
|
||||
|
||||
final Input tmp = Singletons.getModel().getMatch().getInput().getActualInput();
|
||||
// System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ actual input is " + ( tmp == null ? "null" : tmp.getClass().getName()) + "; MHP = " + ph.mayPlayerHavePriority() );
|
||||
if (tmp != null) {
|
||||
// System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ input is " + tmp.getClass().getName() );
|
||||
this.setInput(tmp);
|
||||
} else if (!ph.isPlayerPriorityAllowed()) {
|
||||
//System.out.println("cannot have priority, forced to pass");
|
||||
ph.passPriority();
|
||||
}
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Setter for the field <code>input</code>.
|
||||
@@ -66,9 +52,10 @@ public class GuiInput extends MyObservable implements Observer {
|
||||
* @param in
|
||||
* a {@link forge.control.input.Input} object.
|
||||
*/
|
||||
private void setInput(final Input in) {
|
||||
public void setInput(final Input in) {
|
||||
valid = true;
|
||||
this.input = in;
|
||||
this.input.showMessage();
|
||||
this.input.showMessage(); // this call may invalidate the input by the time it returns
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,10 +108,13 @@ public class GuiInput extends MyObservable implements Observer {
|
||||
return this.getInput().toString();
|
||||
}
|
||||
|
||||
/** @return {@link forge.gui.GuiInput.Input} */
|
||||
/** @return {@link forge.gui.InputProxy.Input} */
|
||||
public Input getInput() {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import javax.swing.JButton;
|
||||
|
||||
import forge.Command;
|
||||
import forge.game.MatchController;
|
||||
import forge.gui.GuiInput;
|
||||
import forge.gui.InputProxy;
|
||||
import forge.gui.framework.ICDoc;
|
||||
import forge.gui.framework.SDisplayUtil;
|
||||
import forge.gui.match.views.VMessage;
|
||||
@@ -42,7 +42,7 @@ public enum CMessage implements ICDoc {
|
||||
/** */
|
||||
SINGLETON_INSTANCE;
|
||||
|
||||
private GuiInput inputControl = new GuiInput();
|
||||
private InputProxy inputControl = new InputProxy();
|
||||
private Component lastFocusedButton = null;
|
||||
|
||||
private final ActionListener actCancel = new ActionListener() {
|
||||
@@ -87,7 +87,7 @@ public enum CMessage implements ICDoc {
|
||||
*
|
||||
* @return GuiInput
|
||||
*/
|
||||
public GuiInput getInputControl() {
|
||||
public InputProxy getInputControl() {
|
||||
return this.inputControl;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,7 @@ import forge.Card;
|
||||
|
||||
import forge.Command;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiDisplayUtil;
|
||||
import forge.gui.framework.ICDoc;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.gui.match.controllers.CMessage;
|
||||
@@ -55,8 +53,7 @@ public class CCommand implements ICDoc {
|
||||
private final Observer observerPlay = new Observer() {
|
||||
@Override
|
||||
public void update(final Observable a, final Object b) {
|
||||
final PlayerZone pZone = (PlayerZone) a;
|
||||
GuiDisplayUtil.setupPlayZone(CCommand.this.view.getTabletop(), pZone.getCards(false));
|
||||
CCommand.this.view.getTabletop().setupPlayZone();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -118,7 +115,7 @@ public class CCommand implements ICDoc {
|
||||
|
||||
if (c != null && c.isInZone(ZoneType.Command)) {
|
||||
//TODO: Cast commander/activate avatar/roll planar dice here.
|
||||
CMessage.SINGLETON_INSTANCE.getInputControl().getInput().selectCard(c);
|
||||
CMessage.SINGLETON_INSTANCE.getInputControl().selectCard(c, player.getZone(ZoneType.Command));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.ForgeAction;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.GuiDisplayUtil;
|
||||
import forge.gui.framework.ICDoc;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.gui.match.controllers.CMessage;
|
||||
@@ -147,8 +146,7 @@ public class CField implements ICDoc {
|
||||
private final Observer observerPlay = new Observer() {
|
||||
@Override
|
||||
public void update(final Observable a, final Object b) {
|
||||
final PlayerZone pZone = (PlayerZone) a;
|
||||
GuiDisplayUtil.setupPlayZone(CField.this.view.getTabletop(), pZone.getCards(false));
|
||||
CField.this.view.getTabletop().setupPlayZone();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import javax.swing.border.MatteBorder;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.framework.DragCell;
|
||||
import forge.gui.framework.DragTab;
|
||||
import forge.gui.framework.EDocID;
|
||||
@@ -66,7 +67,7 @@ public class VCommand implements IVDoc<CCommand> {
|
||||
|
||||
// TODO player is hard-coded into tabletop...should be dynamic
|
||||
// (haven't looked into it too deeply). Doublestrike 12-04-12
|
||||
tabletop = new PlayArea(scroller, id0 == EDocID.COMMAND_0);
|
||||
tabletop = new PlayArea(scroller, id0 == EDocID.COMMAND_0, player.getZone(ZoneType.Command).getCards(false));
|
||||
|
||||
control = new CCommand(player, this);
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ public class VField implements IVDoc<CField> {
|
||||
|
||||
// TODO player is hard-coded into tabletop...should be dynamic
|
||||
// (haven't looked into it too deeply). Doublestrike 12-04-12
|
||||
tabletop = new PlayArea(scroller, id0 == EDocID.FIELD_1);
|
||||
tabletop = new PlayArea(scroller, id0 == EDocID.FIELD_1, player.getZone(ZoneType.Battlefield).getCards(false));
|
||||
|
||||
control = new CField(player, this, playerViewer);
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.esotericsoftware.minlog.Log;
|
||||
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.view.arcane.util.UI;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -167,11 +166,11 @@ public class CardFaceSymbols {
|
||||
* @param w an int
|
||||
* @param h and int
|
||||
*/
|
||||
public static void draw(final Graphics g, String s, int x, final int y, final int w, final int h) {
|
||||
public static void drawOther(final Graphics g, String s, int x, final int y, final int w, final int h) {
|
||||
if (s.length() == 0) {
|
||||
return;
|
||||
}
|
||||
s = UI.getDisplayManaCost(s);
|
||||
|
||||
StringTokenizer tok = new StringTokenizer(s, " ");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String symbol = tok.nextToken();
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.quest.data.GameFormatQuest;
|
||||
import forge.util.FileSection;
|
||||
import forge.util.storage.StorageReaderFile;
|
||||
|
||||
/**
|
||||
@@ -121,7 +122,7 @@ public class QuestWorld implements Comparable<QuestWorld>{
|
||||
* @see forge.util.StorageReaderFile#read(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected QuestWorld read(String line) {
|
||||
protected QuestWorld read(String line, int i) {
|
||||
String useName = null;
|
||||
String useDir = null;
|
||||
GameFormatQuest useFormat = null;
|
||||
@@ -129,9 +130,13 @@ public class QuestWorld implements Comparable<QuestWorld>{
|
||||
final List<String> sets = new ArrayList<String>();
|
||||
final List<String> bannedCards = new ArrayList<String>(); // if both empty, no format
|
||||
|
||||
// This is what you need to use here =>
|
||||
// FileSection.parse(line, ":", "|");
|
||||
|
||||
final String[] sParts = line.trim().split("\\|");
|
||||
|
||||
for (final String sPart : sParts) {
|
||||
|
||||
final String[] kv = sPart.split(":", 2);
|
||||
final String key = kv[0].toLowerCase();
|
||||
if ("name".equals(key)) {
|
||||
|
||||
@@ -70,12 +70,13 @@ public abstract class StorageReaderFile<T> implements IItemReader<T> {
|
||||
public Map<String, T> readAll() {
|
||||
final Map<String, T> result = new TreeMap<String, T>();
|
||||
|
||||
int idx = 0;
|
||||
for (final String s : FileUtil.readFile(this.file)) {
|
||||
if (!this.lineContainsObject(s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final T item = this.read(s);
|
||||
final T item = this.read(s, idx);
|
||||
if (null == item) {
|
||||
final String msg = "An object stored in " + this.file.getPath()
|
||||
+ " failed to load.\nPlease submit this as a bug with the mentioned file attached.";
|
||||
@@ -83,6 +84,7 @@ public abstract class StorageReaderFile<T> implements IItemReader<T> {
|
||||
continue;
|
||||
}
|
||||
|
||||
idx++;
|
||||
result.put(this.keySelector.apply(item), item);
|
||||
}
|
||||
|
||||
@@ -95,8 +97,8 @@ public abstract class StorageReaderFile<T> implements IItemReader<T> {
|
||||
* @param line
|
||||
* the line
|
||||
* @return the t
|
||||
*/
|
||||
protected abstract T read(String line);
|
||||
*/
|
||||
protected abstract T read(String line, int idx);
|
||||
|
||||
/**
|
||||
* Line contains object.
|
||||
|
||||
@@ -415,7 +415,7 @@ public class CardPanel extends JPanel implements CardContainer {
|
||||
if (this.getCard() != null && this.getGameCard().getFoil() > 0) {
|
||||
final String fl = String.format("foil%02d", this.getCard().getFoil());
|
||||
final int z = Math.round(this.cardWidth * CardPanel.BLACK_BORDER_SIZE);
|
||||
CardFaceSymbols.draw(g, fl, this.cardXOffset + z, this.cardYOffset + z, this.cardWidth - (2 * z),
|
||||
CardFaceSymbols.drawOther(g, fl, this.cardXOffset + z, this.cardYOffset + z, this.cardWidth - (2 * z),
|
||||
this.cardHeight - (2 * z));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,12 @@
|
||||
package forge.view.arcane;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -33,7 +35,6 @@ import forge.Card;
|
||||
import forge.Constant;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.arcane.util.CardPanelMouseListener;
|
||||
import forge.view.arcane.util.UI;
|
||||
|
||||
/**
|
||||
* Manages mouse events and common functionality for CardPanel containing
|
||||
@@ -296,7 +297,7 @@ public abstract class CardPanelContainer extends JPanel {
|
||||
* a {@link forge.view.arcane.CardPanel} object.
|
||||
*/
|
||||
public final void removeCardPanel(final CardPanel fromPanel) {
|
||||
UI.invokeAndWait(new Runnable() {
|
||||
CardPanelContainer.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (CardPanelContainer.this.getMouseDragPanel() != null) {
|
||||
@@ -321,7 +322,7 @@ public abstract class CardPanelContainer extends JPanel {
|
||||
* </p>
|
||||
*/
|
||||
public final void clear() {
|
||||
UI.invokeAndWait(new Runnable() {
|
||||
CardPanelContainer.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CardPanelContainer.this.getCardPanels().clear();
|
||||
@@ -623,4 +624,25 @@ public abstract class CardPanelContainer extends JPanel {
|
||||
public void setMouseDragPanel(final CardPanel mouseDragPanel0) {
|
||||
this.mouseDragPanel = mouseDragPanel0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* invokeAndWait.
|
||||
* </p>
|
||||
*
|
||||
* @param runnable
|
||||
* a {@link java.lang.Runnable} object.
|
||||
*/
|
||||
public static void invokeAndWait(final Runnable runnable) {
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
runnable.run();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
EventQueue.invokeAndWait(runnable);
|
||||
} catch (InterruptedException ex) {
|
||||
} catch (InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.List;
|
||||
|
||||
import javax.swing.JScrollPane;
|
||||
import forge.Card;
|
||||
import forge.view.arcane.util.Animation;
|
||||
import forge.view.arcane.util.CardPanelMouseListener;
|
||||
|
||||
/**
|
||||
@@ -65,6 +66,8 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
private int extraCardSpacingX, cardSpacingX, cardSpacingY;
|
||||
private int stackSpacingX, stackSpacingY;
|
||||
|
||||
private List<Card> model;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for PlayArea.
|
||||
@@ -76,10 +79,11 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
* a boolean.
|
||||
* @param modelRef
|
||||
*/
|
||||
public PlayArea(final JScrollPane scrollPane, final boolean mirror) {
|
||||
public PlayArea(final JScrollPane scrollPane, final boolean mirror, List<Card> modelRef) {
|
||||
super(scrollPane);
|
||||
this.setBackground(Color.white);
|
||||
this.mirror = mirror;
|
||||
this.model = modelRef;
|
||||
}
|
||||
|
||||
private final CardStackRow collectAllLands() {
|
||||
@@ -210,6 +214,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
|
||||
while (deltaCardWidth > 0) {
|
||||
List<CardStackRow> template = tryArrangePilesOfWidth(lands, tokens, creatures, others);
|
||||
//System.out.println(template == null ? "won't fit" : "Fits @ " + cardWidth + " !!! " + template.toString());
|
||||
|
||||
deltaCardWidth = (getCardWidth() - lastGoodCardWidth) / 2;
|
||||
if (template != null) {
|
||||
@@ -254,6 +259,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
int x = 0;
|
||||
int y = PlayArea.GUTTER_Y;
|
||||
|
||||
//System.out.println("-------- " + (mirror ? "^" : "_") + " (Positioning ) Card width = " + cardWidth + ". Playarea = " + playAreaWidth + " x " + playAreaHeight );
|
||||
for (final CardStackRow row : template) {
|
||||
int rowBottom = 0;
|
||||
x = PlayArea.GUTTER_X;
|
||||
@@ -273,10 +279,11 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
this.setComponentZOrder(panel, panelIndex);
|
||||
final int panelX = x + (stackPosition * this.stackSpacingX);
|
||||
final int panelY = y + (stackPosition * this.stackSpacingY);
|
||||
//System.out.println("... placinng " + panel.getCard() + " @ (" + panelX + ", " + panelY + ")" );
|
||||
panel.setCardBounds(panelX, panelY, this.getCardWidth(), this.cardHeight);
|
||||
}
|
||||
rowBottom = Math.max(rowBottom, y + stack.getHeight());
|
||||
x += stack.getWidth() + cardSpacingX;
|
||||
x += stack.getWidth();
|
||||
}
|
||||
y = rowBottom;
|
||||
}
|
||||
@@ -287,6 +294,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
|
||||
int afterFirstRow;
|
||||
|
||||
//System.out.println( "======== " + ( mirror ? "^" : "_" ) + " (try arrange) Card width = " + cardWidth + ". PlayArea = " + playAreaWidth + " x " + playAreaHeight + " ========");
|
||||
boolean landsFit, tokensFit, creaturesFit;
|
||||
if (this.mirror) {
|
||||
// Wrap all creatures and lands.
|
||||
@@ -350,13 +358,13 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
// card width.
|
||||
final boolean isMinimalSize = this.getCardWidth() == this.getCardWidthMin();
|
||||
|
||||
// System.err.format("[%d] @ %d - Repaint playarea - %s %n", new Date().getTime(), cntRepaints++, mirror ? "MIRROR" : "DIRECT");
|
||||
|
||||
CardStackRow currentRow = new CardStackRow();
|
||||
for (final CardStack stack : sourceRow) {
|
||||
final int rowWidth = currentRow.getWidth();
|
||||
final int stackWidth = stack.getWidth();
|
||||
//System.out.printf("Adding %s (+%dpx), current row is %dpx and has %s \n", stack, stackWidth, rowWidth, currentRow );
|
||||
// If the row is not empty and this stack doesn't fit, add the row.
|
||||
if (rowWidth + stack.getWidth() > this.playAreaWidth && !currentRow.isEmpty() ) {
|
||||
if (rowWidth + stackWidth > this.playAreaWidth && !currentRow.isEmpty() ) {
|
||||
|
||||
// Stop processing if the row is too wide or tall.
|
||||
if (rowWidth > this.playAreaWidth || this.getRowsHeight(template) + sourceRow.getHeight() > this.playAreaHeight) {
|
||||
@@ -384,6 +392,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
template.add(insertIndex, currentRow);
|
||||
} else return false;
|
||||
}
|
||||
//System.out.println("... row complete! " + currentRow.getWidth() + "px");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -405,6 +414,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
private int planOthersRow(final List<CardStack> sourceRow, final int firstPile, final List<CardStackRow> template, final CardStackRow rowToFill) {
|
||||
int rowWidth = rowToFill.getWidth();
|
||||
|
||||
// System.out.println("This row has:" + rowToFill + "; want to add:" + sourceRow );
|
||||
for (int i = firstPile; i < sourceRow.size(); i++ ) {
|
||||
CardStack stack = sourceRow.get(i);
|
||||
|
||||
@@ -478,6 +488,89 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
super.mouseLeftClicked(panel, evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setupPlayZone.
|
||||
* </p>
|
||||
*
|
||||
* @param newList
|
||||
* an array of {@link forge.Card} objects.
|
||||
*/
|
||||
public void setupPlayZone() {
|
||||
List<Card> oldCards, toDelete;
|
||||
oldCards = new ArrayList<Card>();
|
||||
for (final CardPanel cpa : getCardPanels()) {
|
||||
oldCards.add(cpa.getGameCard());
|
||||
}
|
||||
toDelete = new ArrayList<Card>(oldCards);
|
||||
toDelete.removeAll(model);
|
||||
if (toDelete.size() == getCardPanels().size()) {
|
||||
clear();
|
||||
} else {
|
||||
for (final Card card : toDelete) {
|
||||
removeCardPanel(getCardPanel(card.getUniqueNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
List<Card> toAdd = new ArrayList<Card>(model);
|
||||
toAdd.removeAll(oldCards);
|
||||
|
||||
List<CardPanel> newPanels = new ArrayList<CardPanel>();
|
||||
for (final Card card : toAdd) {
|
||||
newPanels.add(addCard(card));
|
||||
}
|
||||
if (!toAdd.isEmpty()) {
|
||||
doLayout();
|
||||
}
|
||||
for (final CardPanel toPanel : newPanels) {
|
||||
scrollRectToVisible(new Rectangle(toPanel.getCardX(), toPanel.getCardY(), toPanel.getCardWidth(), toPanel.getCardHeight()));
|
||||
Animation.moveCard(toPanel);
|
||||
}
|
||||
|
||||
for (final Card card : model) {
|
||||
final CardPanel toPanel = getCardPanel(card.getUniqueNumber());
|
||||
if (card.isTapped()) {
|
||||
toPanel.setTapped(true);
|
||||
toPanel.setTappedAngle(forge.view.arcane.CardPanel.TAPPED_ANGLE);
|
||||
} else {
|
||||
toPanel.setTapped(false);
|
||||
toPanel.setTappedAngle(0);
|
||||
}
|
||||
toPanel.getAttachedPanels().clear();
|
||||
if (card.isEnchanted()) {
|
||||
final ArrayList<Card> enchants = card.getEnchantedBy();
|
||||
for (final Card e : enchants) {
|
||||
final forge.view.arcane.CardPanel cardE = getCardPanel(e.getUniqueNumber());
|
||||
if (cardE != null) {
|
||||
toPanel.getAttachedPanels().add(cardE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (card.isEquipped()) {
|
||||
final ArrayList<Card> enchants = card.getEquippedBy();
|
||||
for (final Card e : enchants) {
|
||||
final forge.view.arcane.CardPanel cardE = getCardPanel(e.getUniqueNumber());
|
||||
if (cardE != null) {
|
||||
toPanel.getAttachedPanels().add(cardE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (card.isEnchantingCard()) {
|
||||
toPanel.setAttachedToPanel(getCardPanel(card.getEnchantingCard().getUniqueNumber()));
|
||||
} else if (card.isEquipping()) {
|
||||
toPanel.setAttachedToPanel(getCardPanel(card.getEquipping().get(0).getUniqueNumber()));
|
||||
} else {
|
||||
toPanel.setAttachedToPanel(null);
|
||||
}
|
||||
|
||||
toPanel.setCard(toPanel.getGameCard());
|
||||
}
|
||||
invalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private static enum RowType {
|
||||
Land,
|
||||
Creature,
|
||||
|
||||
@@ -140,6 +140,18 @@ public abstract class Animation {
|
||||
protected void end() {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* invokeLater.
|
||||
* </p>
|
||||
*
|
||||
* @param runnable
|
||||
* a {@link java.lang.Runnable} object.
|
||||
*/
|
||||
public static void invokeLater(final Runnable runnable) {
|
||||
EventQueue.invokeLater(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses averaging of the time between the past few frames to provide smooth
|
||||
* animation.
|
||||
@@ -248,7 +260,7 @@ public abstract class Animation {
|
||||
public static void moveCardToPlay(final int startX, final int startY, final int startWidth, final int endX,
|
||||
final int endY, final int endWidth, final CardPanel animationPanel, final CardPanel placeholder,
|
||||
final JLayeredPane layeredPane, final int speed) {
|
||||
UI.invokeLater(new Runnable() {
|
||||
Animation.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final int startHeight = Math.round(startWidth * CardPanel.ASPECT_RATIO);
|
||||
@@ -343,7 +355,7 @@ public abstract class Animation {
|
||||
public static void moveCard(final int startX, final int startY, final int startWidth, final int endX,
|
||||
final int endY, final int endWidth, final CardPanel animationPanel, final CardPanel placeholder,
|
||||
final JLayeredPane layeredPane, final int speed) {
|
||||
UI.invokeLater(new Runnable() {
|
||||
Animation.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final int startHeight = Math.round(startWidth * CardPanel.ASPECT_RATIO);
|
||||
@@ -397,19 +409,14 @@ public abstract class Animation {
|
||||
* a {@link forge.view.arcane.CardPanel} object.
|
||||
*/
|
||||
public static void moveCard(final CardPanel placeholder) {
|
||||
UI.invokeLater(new Runnable() {
|
||||
Animation.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (placeholder != null) {
|
||||
placeholder.setDisplayEnabled(true);
|
||||
// placeholder.setImage(imagePanel);
|
||||
placeholder.setCard(placeholder.getGameCard());
|
||||
}
|
||||
}
|
||||
});
|
||||
if (placeholder != null) {
|
||||
placeholder.setDisplayEnabled(true);
|
||||
// placeholder.setImage(imagePanel);
|
||||
placeholder.setCard(placeholder.getGameCard());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
/*
|
||||
* Forge: Play Magic: the Gathering.
|
||||
* Copyright (C) 2011 Nate
|
||||
*
|
||||
* 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.view.arcane.util;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Toolkit;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.ViewportLayout;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.View;
|
||||
import javax.swing.text.ViewFactory;
|
||||
import javax.swing.text.html.HTML;
|
||||
import javax.swing.text.html.HTMLEditorKit;
|
||||
import javax.swing.text.html.ImageView;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
|
||||
/**
|
||||
* UI utility functions.
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class UI {
|
||||
/** Constant <code>imageCache</code>. */
|
||||
private static ConcurrentMap<URI, Image> imageCache = new MapMaker().softValues().makeMap();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getToggleButton.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link javax.swing.JToggleButton} object.
|
||||
*/
|
||||
public static JToggleButton getToggleButton() {
|
||||
JToggleButton button = new JToggleButton();
|
||||
button.setMargin(new Insets(2, 4, 2, 4));
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getButton.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@link javax.swing.JButton} object.
|
||||
*/
|
||||
public static JButton getButton() {
|
||||
JButton button = new JButton();
|
||||
button.setMargin(new Insets(2, 4, 2, 4));
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setTitle.
|
||||
* </p>
|
||||
*
|
||||
* @param panel
|
||||
* a {@link javax.swing.JPanel} object.
|
||||
* @param title
|
||||
* a {@link java.lang.String} object.
|
||||
*/
|
||||
public static void setTitle(final JPanel panel, final String title) {
|
||||
Border border = panel.getBorder();
|
||||
if (border instanceof TitledBorder) {
|
||||
((TitledBorder) panel.getBorder()).setTitle(title);
|
||||
panel.repaint();
|
||||
} else {
|
||||
panel.setBorder(BorderFactory.createTitledBorder(title));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getFileURL.
|
||||
* </p>
|
||||
*
|
||||
* @param path
|
||||
* a {@link java.lang.String} object.
|
||||
* @return a {@link java.net.URL} object.
|
||||
*/
|
||||
public static URL getFileURL(final String path) {
|
||||
File file = new File(path);
|
||||
if (file.exists()) {
|
||||
try {
|
||||
return file.toURI().toURL();
|
||||
} catch (MalformedURLException ignored) {
|
||||
}
|
||||
}
|
||||
return UI.class.getResource(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getImageIcon.
|
||||
* </p>
|
||||
*
|
||||
* @param path
|
||||
* a {@link java.lang.String} object.
|
||||
* @return a {@link javax.swing.ImageIcon} object.
|
||||
*/
|
||||
public static ImageIcon getImageIcon(final String path) {
|
||||
InputStream stream = null;
|
||||
try {
|
||||
try {
|
||||
stream = UI.class.getResourceAsStream(path);
|
||||
if (stream == null && new File(path).exists()) {
|
||||
stream = new FileInputStream(path);
|
||||
}
|
||||
if (stream == null) {
|
||||
throw new RuntimeException("Image not found: " + path);
|
||||
}
|
||||
byte[] data = new byte[stream.available()];
|
||||
stream.read(data);
|
||||
return new ImageIcon(data);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("Error reading image: " + path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setHTMLEditorKit.
|
||||
* </p>
|
||||
*
|
||||
* @param editorPane
|
||||
* a {@link javax.swing.JEditorPane} object.
|
||||
*/
|
||||
public static void setHTMLEditorKit(final JEditorPane editorPane) {
|
||||
editorPane.getDocument().putProperty("imageCache", imageCache); // Read
|
||||
// internally
|
||||
// by
|
||||
// ImageView,
|
||||
// but
|
||||
// never
|
||||
// written.
|
||||
// Extend all this shit to cache images.
|
||||
editorPane.setEditorKit(new HTMLEditorKit() {
|
||||
private static final long serialVersionUID = -562969765076450440L;
|
||||
|
||||
@Override
|
||||
public ViewFactory getViewFactory() {
|
||||
return new HTMLFactory() {
|
||||
@Override
|
||||
public View create(final Element elem) {
|
||||
Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
|
||||
if (o instanceof HTML.Tag) {
|
||||
HTML.Tag kind = (HTML.Tag) o;
|
||||
if (kind == HTML.Tag.IMG) {
|
||||
return new ImageView(elem) {
|
||||
@Override
|
||||
public URL getImageURL() {
|
||||
URL url = super.getImageURL();
|
||||
// Put an image into the cache to be
|
||||
// read by other ImageView methods.
|
||||
if (url != null && imageCache.get(url) == null) {
|
||||
try {
|
||||
imageCache.put(url.toURI(), Toolkit.getDefaultToolkit()
|
||||
.createImage(url));
|
||||
} catch (URISyntaxException e) {
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return super.create(elem);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setVerticalScrollingView.
|
||||
* </p>
|
||||
*
|
||||
* @param scrollPane
|
||||
* a {@link javax.swing.JScrollPane} object.
|
||||
* @param view
|
||||
* a {@link java.awt.Component} object.
|
||||
*/
|
||||
public static void setVerticalScrollingView(final JScrollPane scrollPane, final Component view) {
|
||||
final JViewport viewport = new JViewport();
|
||||
viewport.setLayout(new ViewportLayout() {
|
||||
private static final long serialVersionUID = -4436977380450713628L;
|
||||
|
||||
@Override
|
||||
public void layoutContainer(final Container parent) {
|
||||
viewport.setViewPosition(new Point(0, 0));
|
||||
Dimension viewportSize = viewport.getSize();
|
||||
int width = viewportSize.width;
|
||||
int height = Math.max(view.getPreferredSize().height, viewportSize.height);
|
||||
viewport.setViewSize(new Dimension(width, height));
|
||||
}
|
||||
});
|
||||
viewport.setView(view);
|
||||
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scrollPane.setViewport(viewport);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* getDisplayManaCost.
|
||||
* </p>
|
||||
*
|
||||
* @param manaCost
|
||||
* a {@link java.lang.String} object.
|
||||
* @return a {@link java.lang.String} object.
|
||||
*/
|
||||
public static String getDisplayManaCost(String manaCost) {
|
||||
manaCost = manaCost.replace("/", "");
|
||||
manaCost = manaCost.replace("X 0", "X");
|
||||
// A pipe in the cost means
|
||||
// "process left of the pipe as the card color, but display right of the pipe as the cost".
|
||||
int pipePosition = manaCost.indexOf("{|}");
|
||||
if (pipePosition != -1) {
|
||||
manaCost = manaCost.substring(pipePosition + 3);
|
||||
}
|
||||
return manaCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* invokeLater.
|
||||
* </p>
|
||||
*
|
||||
* @param runnable
|
||||
* a {@link java.lang.Runnable} object.
|
||||
*/
|
||||
public static void invokeLater(final Runnable runnable) {
|
||||
EventQueue.invokeLater(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* invokeAndWait.
|
||||
* </p>
|
||||
*
|
||||
* @param runnable
|
||||
* a {@link java.lang.Runnable} object.
|
||||
*/
|
||||
public static void invokeAndWait(final Runnable runnable) {
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
runnable.run();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
EventQueue.invokeAndWait(runnable);
|
||||
} catch (InterruptedException ex) {
|
||||
} catch (InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setDefaultFont.
|
||||
* </p>
|
||||
*
|
||||
* @param font
|
||||
* a {@link java.awt.Font} object.
|
||||
*/
|
||||
public static void setDefaultFont(final Font font) {
|
||||
for (Object key : Collections.list(UIManager.getDefaults().keys())) {
|
||||
Object value = UIManager.get(key);
|
||||
if (value instanceof javax.swing.plaf.FontUIResource) {
|
||||
UIManager.put(key, font);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user